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 tobeans 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(); } } }