8

我已经逐渐掌握了 Spring 一段时间,并且认为我对这些概念有一个合理的想法,但是我在另一个线程中遇到了信息,这让我的事情发生了翻天覆地的变化......

“...尽管在所有对象上调用初始化生命周期回调方法而不考虑范围,但在原型的情况下,不会调用配置的销毁生命周期回调。客户端代码必须清理原型范围的对象并释放原型 bean 的昂贵资源(s) 正在持有。要让 Spring 容器释放原型范围 bean 持有的资源,请尝试使用自定义 bean 后处理器,它包含对需要清理的 bean 的引用。

这让我想到我有真正的用例,我想使用原型 bean,例如,每个请求我需要一个“新”bean 实例。然而,根据我对这个片段的理解(来自 Spring 3 文档),Spring 保留对需要清理的 bean 的引用(引用本身意味着垃圾收集器不会自动清除 bean)。此外,我认为原型 bean 持有的资源必须手动清理。

有人可以让我知道这是否正确吗?如果是这样,是否有用于处理此问题的典型模式?我很欣赏一个可以描述 Spring 以这种方式实现原型 bean 的架构原因的答案。

4

3 回答 3

19

Spring 保留对需要清理的 bean 的引用(引用本身意味着垃圾收集器不会自动清除 bean)。

是的,但容器不包含对原型范围 bean 的引用。这就是为什么不调用销毁回调的原因:Spring 创建 bean 实例,连接它并调用构造回调。它给出了一个实例并忘记了那个 bean。

您可以安全地为每个请求创建原型范围的 bean。Spring 会给你一个实例,当你没有对该 bean 的任何引用时(Spring 没有保留一个!),它将被垃圾收集。但是由于 Spring 在创建 bean 后对它一无所知 - 它不能调用任何销毁回调。事实上,这归结为一个问题:为什么 Java 没有析构函数。

那么如何清理原型范围的 bean?好吧,就像你在 Java 中清理任何其他资源一样——明确地。提供close(),或您喜欢destroy()stop()任何名称(考虑实现Closeable。请注意,通常不需要此类方法。垃圾收集器将释放整个对象图,而持久性资源(如数据库连接)将在整个关闭时DataSource关闭。

于 2012-06-08T21:42:26.890 回答
8

您误读了文档。它明确地说:

要让 Spring 容器释放原型范围的 bean 持有的资源,请尝试使用自定义 bean 后处理器,它包含对需要清理的 bean 的引用。

所以 Spring 没有对它创建的原型 bean 进行任何引用。如果需要,您可以创建一个 bean 后处理器来保存对这些 bean 的引用。

此外,原型 bean 很少有必须清理的资源。例如,连接池(需要在关闭时正确销毁)通常是单例 bean。把它做成原型没有多大意义。由于原型 bean 经常使用很短的时间,创建它的客户端可以在不再使用它时显式地释放它的资源。就像你创建一个新的流或连接,并在 finally 块中关闭它一样。

于 2012-06-08T21:43:55.100 回答
6

Spring 不知道使用原型范围创建的所有实例。它将简单地实例化和配置原型范围的 bean,然后按照文档中的说明将其交给客户端。

Spring 不管理原型 bean 的完整生命周期:容器实例化、配置、装饰和以其他方式组装原型对象,将其交给客户端,然后不再了解该原型实例。

http://static.springsource.org/spring/docs/3.0.0.M3/spring-framework-reference/html/ch04s04.html#beans-factory-scopes-prototype

于 2012-06-08T21:46:24.430 回答