我意识到DI是一种非常灵活的设计模式,尽管我很难接受它作为创建解耦代码的“银弹”。
原因如下:当依赖对象的生命周期长于其注入的依赖项时会发生什么?
示例应用程序:我有一个BusinessLogic
类,它在我的应用程序的生命周期中实例化。此类需要DataContext
对象来执行数据库操作。我之前创建了一个带有两个实现的抽象DataContextFactory
:StaticDataContextFactory
和WebDataContextFactory
。前者在应用程序的生命周期内维护单个DataContext,而后者将为每个HTTP请求创建新的DataContexts。
示例中的问题:正如您所看到的,使用StaticDataContextFactory
时一切正常。但是,当使用WebDataContextFactory
时,BusinessLogic
将失败,因为它会注入一个DataContext
,一旦第一个请求完成,它将过期/处置。
我的问题是:所有依赖对象的生命周期是否必须小于或等于其依赖关系的生命周期?如果是这样,那么当实例化依赖类的代码未知每个依赖的生存期时会发生什么?
答案 0 :(得分:1)
Spring框架的Web集成使用代理和方面解决了这个问题。较长范围的对象注入较短范围的对象的代理。每个代理都知道如何通过HTTP会话或HTTP请求(分别针对会话和请求范围的bean)获取其较短范围委托的“当前”版本。
答案 1 :(得分:1)
正如其他海报所指出的那样,有基于代理的解决方案。我会把它放在“最后的手段”类别中。
你可以重构以消除这种不一致性,我认为从长远来看,最终结果会更好。我不太了解你的情况,但你可以考虑一些事情:
摆脱工厂,让容器注入DataContext
,然后使用容器的生命周期控制来调整DataContext
在不同环境中的生命周期
不要使BusinessLogic
组件成为单实例。如果为每次使用创建一个新的,如果以这种方式配置DC,或者在其他配置中使用单个DC,它自然会选择网络范围DataContext
如果BusinessLogic
具有状态或实例化成本高昂,请将昂贵/有状态的部分移动到具有单实例生命周期的子组件
我已经看到了可以在Spring使用的基于代理的解决方案 - 这是个人品味,但我对这个解决方案长期存在的可理解程度持谨慎态度。您必须非常自律,以确保通过代理从“当前Web请求”返回的任何内容都不会被引用或保留的时间超过拥有它的请求...
在IoC中成功地工作非常依赖于在工作单元之间保持清晰的分离,这在网络环境中是愉快和自然的 - 如果可以的话,它将付出代价。
希望这有帮助,尼克
答案 2 :(得分:0)
我一直在思考一个类似的问题。 (查看DI上的帖子:Dependency Injection Container,第二个答案)我意识到使用接口注入的正确实现实际上可以解决问题。
我认为它可能运行良好的原因是因为尽管从对象中提取接口是常见的,但只要接口层次结构设计得当,即使对象超出范围,与接口相关的数据也是如此实际上会坚持下去。因此,在您的实际对象被消耗它的代码释放之前,您最终不会有超出范围的依赖项。
在我展示的示例中,我推出了自己的“DI”,虽然它不是真正的DI模式,但我相信它能很好地完成工作。
答案 3 :(得分:0)
为什么不能向XXXDataContextFactory询问“当前”DataContext?您的静态工厂将始终返回相同的工厂,而您的Web工厂将根据当前的HttpRequest返回一个。