是否需要手动销毁Spring原型bean?

Iqb*_*mid 15 java spring garbage-collection spring-bean predestroy

我注意到@PreDestroy我的原型范围Spring bean 的钩子没有被执行.

我在这里读到这实际上是设计的.Spring容器将销毁单例bean,但不会销毁原型bean.我不清楚为什么.如果Spring容器将创建我的原型bean并执行它的@PostConstruct钩子,为什么在容器关闭时它也不会破坏我的bean?一旦我的Spring容器关闭,继续使用它的任何bean都有意义吗?我看不到你想要在完成bean之前关闭容器的场景.甚至可以在容器关闭后继续使用原型Spring bean吗?

上面描述了我的主要问题的令人费解的背景:如果Spring容器没有破坏原型bean,那是否意味着可能发生内存泄漏?或者原型bean会在某些时候被垃圾收集?

春季文件指出:

客户端代码必须清理原型范围的对象并释放原型bean所持有的昂贵资源.要使Spring容器释放原型范围的bean所拥有的资源,请尝试使用自定义bean后处理器,它包含对需要清理的bean的引用.

那是什么意思?该文本告诉我,我作为程序员负责明确(手动)销毁我的原型bean.它是否正确?如果是这样,我该怎么做?

Iqb*_*mid 17

为了他人的利益,我将在下面介绍我从调查中收集到的内容:

只要原型bean本身不持有对另一个资源(如数据库连接或会话对象)的引用,只要删除了对该对象的所有引用或对象超出范围,就会立即收集垃圾.因此,通常没有必要显式销毁原型bean.

但是,在如上所述可能发生内存泄漏的情况下,可以通过创建单一bean后处理器来销毁原型bean,其后处理方法显式调用原型bean的销毁挂钩.因为后处理器本身是单例范围的,所以Spring 调用它的破坏钩子:

  1. 创建一个bean post处理器来处理所有原型bean的销毁.这是必要的,因为Spring不会破坏原型bean,因此代码中的任何@PreDestroy挂钩永远不会被容器调用.

  2. 实现以下接口:

    1. BeanFactoryAware
    此接口提供一个接收Beanfactory对象的回调方法.此BeanFactory对象在后处理器类中用于通过其BeanFactory.isPrototype(String beanName)方法标识所有原型bean.

    2. DisposableBean
    此接口提供Spring容器调用的Destroy()回调方法.我们将在此方法中调用所有原型bean的Destroy()方法.

    3. BeanPostProcessor
    实现此接口提供对进程内回调的访问,我们在其中准备Spring容器实例化的所有原型对象的内部List <>.我们稍后将循环遍历此List <>以销毁我们的每个原型bean.


3.最后在每个原型bean中实现DisposableBean接口,提供此契约所需的Destroy()方法.

为了说明这个逻辑,我提供了以下从本文中获得的一些代码:

/**
* 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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)