1. 程式人生 > 實用技巧 >Spring原型bean-prototype不能銷燬? 轉載

Spring原型bean-prototype不能銷燬? 轉載

一個原型bean的例子:

結果是 註解的@PreDestroy的方法close()沒有執行,而如果是單例bean 的singleton則會執行

那若想銷燬Spring的原型bean應該怎麼辦呢?

看這篇分析:java – 需要手動銷燬Spring原型bean嗎?

我注意到我的原型範圍的Springbean的@PreDestroy鉤子沒有被執行.

我已經讀過here,這實際上是設計的. Spring容器將銷燬單例bean,但不會銷燬原型bean.我不清楚為什麼.如果Spring容器將建立我的原型bean並執行其@PostConstruct鉤子,為什麼在容器關閉時它也不會破壞我的bean?一旦我的Spring容器關閉,繼續使用它的任何bean都有意義嗎?我看不到你想要在完成bean之前關閉容器的場景.甚至可以在容器關閉後繼續使用原型Spring bean嗎?

上面描述了我的主要問題的令人費解的背景:如果Spring容器沒有破壞原型bean,那是否意味著可能發生記憶體洩漏?或者原型bean會在某些時候被垃圾收集?

春季檔案指出:

The client code must clean up prototype-scoped objects and release
expensive resources that the prototype bean(s) are holding. To get the
Spring container to release resources held by prototype-scoped beans,
try using a custom bean post-processor, which holds a reference to

beans that need to be cleaned up.

那是什麼意思?該文字告訴我,我作為程式設計師負責明確(手動)銷燬我的原型bean.它是否正確?如果是這樣,我該怎麼做?

最佳答案 為了他人的利益,我將在下面介紹我從調查中收集到的內容:

只要原型bean本身不持有對另一個資源(如資料庫連線或會話物件)的引用,只要刪除了對該物件的所有引用或物件超出範圍,就會立即收集垃圾.因此,通常沒有必要顯式銷燬原型bean.

但是,在如上所述可能發生記憶體洩漏的情況下,可以通過建立單一bean後處理器來銷燬原型bean,其後處理方法顯式呼叫原型bean的銷燬掛鉤.因為後處理器本身是單例範圍的,所以Spring會呼叫它的破壞鉤子:

> 建立一個bean post處理器來處理所有原型bean的銷燬.這是必要的,因為Spring不會破壞原型bean,因此程式碼中的任何@PreDestroy掛鉤永遠不會被容器呼叫.
> 實現以下介面:

1.BeanFactoryAware
  該介面提供了一個接收Beanfactory物件的回撥方法.此BeanFactory物件在後處理器類中用於通過其BeanFactory.isPrototype(String beanName)方法標識所有原型bean.

2. DisposableBean
  此介面提供Spring容器呼叫的Destroy()回撥方法.我們將在此方法中呼叫所有原型bean的Destroy()方法.

3. BeanPostProcessor
  實現此介面提供對程序內回撥的訪問,我們在其中準備內部List<> Spring容器例項化的所有原型物件.我們稍後將遍歷此List<>銷燬我們的每個原型bean.

4.最後在每個原型bean中實現DisposableBean介面,提供此契約所需的Destroy()方法.

為了說明這個邏輯,我提供了以下從article中獲取的一些程式碼:

/**
* Bean PostProcessor that handles destruction of prototype beans
*/
@Component
public class DestroyPrototypeBeansPostProcessor implements BeanPostProcessor, BeanFactoryAware, DisposableBean {

    private BeanFactory beanFactory;

    private final List<Object> prototypeBeans = new LinkedList<>();

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (beanFactory.isPrototype(beanName)) {
            synchronized (prototypeBeans) {
                prototypeBeans.add(bean);
            }
        }
        return bean;
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    @Override
    public void destroy() throws Exception {
        synchronized (prototypeBeans) {
            for (Object bean : prototypeBeans) {
                if (bean instanceof DisposableBean) {
                    DisposableBean disposable = (DisposableBean)bean;
                    try {
                        disposable.destroy();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
            prototypeBeans.clear();
        }
    }
}