长时间运行的Windows服务中的依赖注入 - 组合根是正确的思路吗?

10
我正在编写一个 Windows 服务,如果一切顺利,它将运行数个月。在服务的生命周期内,它将维护几个 WCF 服务(用于与其他本地应用程序通信的命名管道),运行嵌入式数据存储(可能是 RavenDB,对于此问题来说不太相关),并使用一些第三方软件维护 SIP 服务(VoIP 功能)。我面临的挑战之一是需要根据事件做出反应,并创建一些新的业务对象来处理这些事件代表的内容。
现在,我已经阅读了 Mark Seemann 的书籍(至少是与此讨论相关的部分),我理解了为什么服务定位器是不好的,以及为什么在组合根(在我的情况下是服务启动点)中处理这个问题是好的 - 在一般情况下。
然而,我不明白这如何适用于每种情况。我看到在你可以在应用程序启动时组合整个根的情况下,或者在诸如 MVC 这样的框架中 IoC 引擎按请求使用的情况下,这将是完美的。但是,对于长时间运行的服务,我想最好的情况下它会效率低下,在某些情况下甚至是不可能的,因为你无法预先创建所有对象。我无法想象能够编写一个复杂的服务来获得它可能需要的所有对象,并且永远不需要在生命周期内创建新对象。
现在,这还不足以吸引我去采用服务定位器这样的隐藏依赖的代价。但是,在这里应该怎么做呢?如果我有一个 CallHandlerService 需要根据每个传入呼叫创建(因为它使用昂贵的非托管资源,例如),我该如何处理?
组合根 + 一点点服务定位器?
最后一部分不是认真的,但我仍然很想知道如何正确解决这个问题。

组合根是您“组合”图形,定义关系和相互依赖性的地方。它不是您创建对象的地方。 - qujck
没问题,这个没关系 - 但是我如何创建对象,而不引入事实上的服务定位器呢? - Rune Jacobsen
您将引用容器来实例化根对象。因此,您的服务将依赖于容器,所有其他依赖项都将被注入(通常的做法)。对象生命周期由容器管理。 - qujck
一个对象作为单例的能力不应该随着时间(小时、天或月份)的推移而衰减。在这种情况下,容器应该是最有能力的类。 - qujck
2个回答

16

可以将问题分为两个部分:

  • 如何管理作用域
    • 避免提前创建所有可能的依赖项
    • 仅创建所需的依赖项
  • 如何管理生命周期
    • 保留对已创建依赖项的引用
    • 如果可能,重复使用依赖项
    • 尽早清理它们

如何管理作用域

你可以定义界面或实现 几个专门的 抽象工厂,每个工厂都只限于管理自己特定类型的依赖项。例如:一个用于处理数据库相关的依赖项,另一个用于SIP相关的依赖项。然后您可以注入工厂本身,而不是依赖项,并从中检索依赖项。

这听起来像服务定位器吗?是的,但它不是服务定位器。您可以在Mark Seemann博客中了解更多信息:抽象工厂还是服务定位器?

如果抽象工厂可以接受,请查看Ninject.Extensions.Factory以根据您的 IKernel 配置自动创建它们。

如何管理生命周期

如果您将运行您的服务24-7,则这是更为复杂和重要的部分。在这里,我可以给您一些实际的建议:

  • 对于此类服务,外部依赖项方面的故障(即数据库、服务)是常规问题,而不是例外
  • 不要在代码中保留任何对依赖项的引用,以提高性能或复用
  • 不要使用复杂的生命周期(例如 Ninject 的命名范围)
  • 尽快释放依赖项。配置 Ninject 来代替您管理它们。
  • 考虑依赖项的超时时间,以重新创建新实例
  • 对于长时间运行的任务,创建一个独立的Kernel实例,并确保在使用后进行处理

  • 非常好的回答,但我仍然发现自己很难不使用"ServiceLocate"这些工厂。我该如何注入它们?我将它们保持为静态单例吗?谢谢! - cvbarros
    1
    Service LocatorAbstract Factory 的区别在于,后者只能创建特定的依赖项,而前者几乎可以创建任何东西。您可以在马克的文章中找到更多信息,但最重要的是:抽象工厂是具有非泛型 Create 方法的通用类型;服务定位器是具有泛型 Create 方法的非泛型类型。 - Akim

    0
    在我看来,依赖注入(通常用于提供服务)有点像黑魔法,需要深入了解何时以及如何正确使用它。
    从我的经验来看,调试一个存在缺陷或异常的注入依赖项的应用程序是一项繁琐的过程,特别是如果特定对象是隐藏在相同接口后面的多个对象之一。这就是为什么重要的是对使用该接口的所有对象进行单元测试,因为您永远不知道哪个对象会在相同输入下失败。
    您的依赖注入最好用于服务启动时为每种类型的调用创建处理程序,然后在每个调用到达时适当地分派。但是,我认为尝试创建一个对象来处理每个调用是增加更多开销和复杂性的事情。
    跟随您的直觉,保持简洁高效。

    2
    你没有回答问题,因此我认为这虽然是一个有效的意见,但应该作为评论。我也不同意你对OP的“直觉”的评估,但我猜说话者应该是权威! - Ruben Bartelink

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