Castle Windsor中文文档 - 三次调用模式(Three Calls Pattern)

三次调用模式(Three Calls Pattern)

控制反转(称为IoC)框架与所有其他类型的框架不同,因为在代码中看不到许多对框架的调用。事实上在大多数应用程序中(不管它们的大小和复杂程度如何),只能在三个地方直接调用容器。这是最常见的模式,Windsor完全支持。

容器的三次调用模式

这种模式被称为三次调用, 有时也被称为RRR - 注册(Register),解决(Resolve),释放(Release) - 参考Mark Seemann关于容器的著作
顾名思义,容器只在应用程序的三个地方被调用,或者更确切地说,在你的入口项目中。

什么是入口项目? 入口项目要么是客户端.exe应用程序的Program.Main方法,要么是Web应用程序的Application_StartApplication_End,或其他类型的应用程序相应的地方。

是的,这也意味着在企业应用程序中: IoC的新手很难相信你可以用容器来构建一个“企业级”、“大的”,“现实世界”的应用程序,而且几乎没有明确地使用它。是的,绝对可以。它已经被多次完成,并且运作得非常好。如第一段所述 - 这就是控制反转。

这也意味着处理容器的一个非常重要的方面 - 在应用程序中有一个容器实例。您只需要一个单一的根容器实例。在一些罕见的高级场景中,你可以创建“子”容器,但是它们作为子容器被绑定到一个单一的无处不在的根容器中。

现在我们来看看这三次调用是什么。

调用One - 引导程序(bootstrapper)

Bootstrapper是您创建和配置容器的地方。它通常只是一个看起来像这样的单一方法:

public IWindsorContainer BootstrapContainer()
{
    return new WindsorContainer()
        .Install(
            Configuration.FromAppConfig(),
            FromAssembly.This()
            //perhaps pass other installers here if needed
        );
}

在引导程序中,您执行以下操作:

  • 创建我们将要使用的容器的实例。
  • 如果需要的话可以自定义容器,大多数情况下你不需要(通常意味着永远不会),因为容器的默认行为和配置应该足以满足95%的应用程序。通过自定义,就是替换容器的HandlerFactoryReleasePolicyDependencyResolver、子系统等容器内部用来执行其工作的东西。您可能也需要给容器增加一些扩展,例如facilities,需要在任何组件之前进行注册它。
  • 注册所有组件,容器会管理他们,就是前面所说的Install方法的调用。在这里传递封装了特定组件的所有信息的installer。大部分工作发生在这里,稍后你会看到。

建议只调用一次Install方法: 建议一次调用Install就安装所有installers,尽管当前的容器也支持多次调用Install, 或者在此方法之外配置组件,Windsor对这种情况进行了优化,如果您这样做,它的性能会更好。在未来的版本中,将进一步优化(一次调用Install)。

调用two - 解析(Resolve)

在第一步我们完全配置了容器,现在我们可以实际使用它(来创建组件),重要的是我们只使用它一次(记住控制反转的部分)。每个应用程序都有一个根组件,在MonoRail或ASP.NET MVC应用程序中就是控制器,在WPF或WinForms应用程序中就是主窗口,在WCF服务就是服务,等等。可以有多个根组件,就像在一个控制台应用程序中,一个用于解析命令行参数,另一个用于执行一些实际的工作,然而在你的组件图(graph)中,根组件总是很少的。

这些根组件是唯一需要从容器中显式Resolve的,然后容器构造完整组件图,包含它的依赖和依赖的依赖等,容器做了各种工作,这样你就可以编写如此简单的代码:

var container = BootstrapContainer();
var shell = container.Resolve<IShell>();
shell.Display();

按类型解析vs按名称解析: Resolve方法有几个重载,可以分成两组 - 按名称和不按名称。如果没有提供名称,Windsor将使用类型来定位服务(如上例所示)。如果提供了名字,名字将被使用,且类型将被用作为你提供方便(这样你就不必从object类型强制转换或者作为容器的提示,当你解析打开的泛型组件时,windsor应该如何关闭打开的泛型类型)。除非你有一个很好的理由来按名称解析,否则请使用类型解析

当上面的代码执行完第二行时,您将有一个完全配置的IShell服务实例,然后您可以将控制权交给下一行。如果你是新手,容器应该是真正令人印象深刻的部分。容器在一行代码中创建了整个复杂的(包含潜在的数百个对象,每个都以不同的方式配置)对象的图形。这是深刻的,相信我。

对不能/或不想在根对象解析的时间/地点获取的组件怎么办?
对于需要在稍后的某个时间点(而不是在解析根组件时)从容器中取出某些组件的情况,请使用类型化的工厂

那么我想在根解析时间/地点实例化组件,但是我不想对它们做任何事情,比如后台任务?
如果组件不是根的依赖关系,但需要在应用程序启动时启动(如后台任务),请使用可启动设施

调用 three - 释放(Dispose)

这是许多人(特别是那些坚持容器是做“依赖注入”的人)忘记的部分。容器管理组件的整个生命周期,并且在我们关闭应用程序之前,我们需要关闭容器,然后将所有管理的组件关闭(例如Dispose)。这就是为什么在关闭应用程序之前调用container.Dispose()非常重要。

Additional Resources

posted @ 2019-06-18 10:47  下一个起点  阅读(82)  评论(0)    收藏  举报