Spring原型bean-prototype不能销毁? 转载
一个原型bean的例子:
结果是 注解的@PreDestroy的方法close()没有执行,而如果是单例bean 的singleton则会执行
那若想销毁Spring的原型bean应该怎么办呢?
看这篇分析: java – 需要手动销毁Spring原型bean吗?
我注意到我的原型范围的Spring bean的@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(); } } }