Castle Windsor - 我需要释放单例或非可释放的瞬态对象吗?

11

Castle 维基在多个地方都提到,对于通过容器解析出来的组件,我应该总是调用 container.Release() 方法。这显然适用于复杂的生命周期管理技术(例如 LifeStyle.Pooled)或使用特殊设施...

但是对于那些单例(在容器被销毁之前一直存在)和不需要释放资源的瞬态对象,我真的需要调用 Release() 吗?如果对于瞬态对象或单例进行 Release() 调用,这些调用似乎是多余的 - 例如,在瞬态对象不实现 IDisposable 接口时,内核只会发现它无法追踪该对象并返回...

似乎有一个“组件负担”的概念来跟踪解析瞬态对象时可能构建的其他可释放组件的“间接”引用。我理解,如果您不能100%确定它们是否有此类间接依赖关系,则需要释放瞬态对象。这是“敦促”所有 Castle 用户始终释放组件的主要原因吗?

1个回答

21

在这里,Castle Wiki 有点严格 - 它试图保持安全而不是抱歉。可能需要重新措辞。

无论如何 - 这是它的工作原理。

默认情况下,Windsor 跟踪大多数组件,并保存对它们的引用,这会阻止垃圾回收器将它们收集起来。这不是一个 bug - 它是一个极其有用和强大的功能。 在大多数情况下,您不应该假设组件是否被跟踪。非可释放组件及其依赖项也将被跟踪。这是一般规则:“自身或某些依赖项具有任何退役步骤的组件将由 Windsor 默认发布策略跟踪”。

现在,这里就是寿命发挥作用的部分。

  • Singleton - 根据定义,单例在容器上下文中是“全局”的 - 当您首次请求它们时创建,并在容器的余生(即直到容器被处理)内存活。如果您查看文档,实际上是说释放单例实际上没有做任何事情。只有当容器被处理时,您的寿命组件的退役问题才会得到解决。

  • Per (上下文:Web 请求/WCF 会话/) - 由于对象在具有明确定义结束的上下文中共享,因此上下文的结束将负责释放您的组件。

  • Transient - 这就是真正的问题所在。由于临时组件没有任何结束寿命的任意结束,并且您可以在应用程序的生命周期内生成大量它们的实例,因此除了明确表示并告诉容器“嘿,我不再使用这个对象,随时都可以处理它,感谢您为所有鱼提供的帮助。”以外别无选择。

现在,文档建议始终释放组件的原因是使用组件的代码实际上不应该知道组件的寿命。 虽然并非总是如此,在应用程序中通常有“自然”适合某种寿命方式的组件。但总的来说,如我所说,这是为了安全起见而不是抱歉。

另一件事是你调用 ResolveRelease 的位置。你应该只释放你解析的对象,而不应该释放其它对象。

当你使用容器类似于我这样的方式时,你可能不需要在代码中任何地方调用Release。你会解析你的根组件,但是容器本身的Dispose将负责释放它。你可能还会通过类型化工厂隐式解析其他组件,在这种情况下你也应该释放它们(通过工厂),但通常只有这些。

因此,最终结果是,它并不像一开始听起来那么可怕。


谢谢Krzysztof!那就是我在寻找的答案。关于Release和容器:您建议避免“服务定位器模式”(避免传递容器)当然是非常正确的。我主要问这个问题是因为工厂设施创建的工厂也有相同的“释放问题”。 - blueling
4
Krzysztof解释的规则有一个例外,如果您自己创建对象并将实例注册到容器中(而不是让容器为您创建实例),那么容器将让该实例的生命周期管理由您决定。也就是说,即使您将其注册为单例,当您处理容器时,容器也不会处理该实例的销毁。 - Kenneth Baltrinic
最终决定权在ILifestyleManager手中,而在即将到来的Windsor 3中,生命周期管理器在这里甚至拥有更多的控制权。 - Krzysztof Kozmic

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接