我已经逐渐掌握了Spring一段时间并且认为我对这些概念有一个合理的想法,但是我在另一个线程中遇到了信息,这让我的事情变得颠倒了...... / p>
" ...虽然无论范围如何都在所有对象上调用初始化生命周期回调方法,但在原型的情况下,不会调用已配置的销毁生命周期回调。客户端代码必须清理原型范围的对象并释放原型bean所持有的昂贵资源。要让Spring容器释放原型范围bean所拥有的资源,请尝试使用自定义bean后处理器,它包含对需要清理的bean的引用。"
这让我觉得我有真正的用例,我想使用原型bean,例如,我需要一个" new"每个请求的bean实例。但是根据我对这个片段的理解(来自Spring 3文档),Spring坚持引用需要清理的bean(引用本身意味着bean不会被垃圾收集器自动清除)。此外,我认为必须手动清理原型bean所拥有的资源。
如果这是正确的,有人可以告诉我吗?如果是这样,有一个典型的模式来处理这个?我非常感谢能够描述Spring以这种方式实现原型bean的架构原因的答案。
答案 0 :(得分:16)
Spring坚持对需要清理的bean的引用(引用本身意味着bean不会被垃圾收集器自动清除)。
是的,但容器不包含对原型范围bean的引用。这就是为什么不调用销毁回调的原因:Spring创建bean实例,连接它并调用构造回调。它给出了一个实例并忘记了那个bean。
您可以安全地为每个请求创建原型范围的bean。 Spring会给你一个实例,当你没有任何对bean的引用时(Spring没有保留一个!),它将被垃圾收集。但是因为Spring在创建它之后对你的bean一无所知 - 它不能调用任何破坏回调。事实上,这归结为一个问题:为什么Java没有析构函数。
那你如何清理原型范围的豆子呢?好吧,就像你清理Java中的任何其他资源一样 - 明确地说。提供close()
,destroy()
,stop()
或您喜欢的任何名称(考虑实施Closeable
。请注意,通常不需要此类方法。垃圾收集器将释放整个对象图当整个DataSource
关闭时,将关闭像数据库连接这样的持久性资源。
答案 1 :(得分:6)
你误读了文档。它明确地说:
让Spring容器释放所持有的资源 原型范围的bean,尝试使用自定义bean后处理器,其中 持有对需要清理的bean的引用。
所以Spring没有对它创建的原型bean有任何引用。由你来创建一个bean后处理器,如果需要的话,它将保存对这些bean的引用。
此外,原型bean很少能够保存必须清理的资源。例如,连接池(需要在关闭时正确销毁)通常是单例bean。将它作为原型是没有多大意义的。由于原型bean通常使用的时间很短,因此创建它的客户端可以在不再使用它时明确释放其资源。就像创建新流或连接时一样,并在finally块中关闭它。
答案 2 :(得分:4)
Spring不了解使用原型范围创建的所有实例。它将简单地实例化和配置原型范围的bean,并将其交给客户端,如文档中所述。
Spring不管理原型bean的完整生命周期: 容器实例化,配置,装饰和以其他方式组装 一个原型对象,交给客户端,然后没有进一步 了解该原型实例。