先说下为何翻译这篇文章,既定的方向是架构,而后为了学习架构就去学习一些架构模式、设计思想。数据库
忽然有一天发现依赖注入这种技能。为了使得架构可测试、易维护、可扩展,须要架构设计为松耦合类型,简单的说也就是解耦。为了解耦前面的人提出各类理论,主要思想是控制反转,而如今主流的主要是两个:依赖注入、服务定位(有篇英文文章特地讨论这种模式,最终的结论是否认的,乍看了一眼,没看懂)数组
有了某个思想即可以在程序中体现,用多了,人们就去对它进行封装,普通的人封装的大概就本身用,高人封装了便成了组件。如今基本上都在弄 .net ,因此说的技术也基本上是这一块的。.net 的 IOC 框架有 Autofac、Castle Windsor、Unity、Spring.NET、StructureMap、Ninject。session
有这么多框架为何选 Autofac,我在这个地方只是学习这种 IOC 思想的框架,并无真实的用在生产中。Autofac 各方面的的性能都比较中庸,因此用它做为 IOC 入门应该是比较合适的,这样也就致使这篇文章适合初学者阅读。架构
接下来就要具体说下翻译的原文,文章对于 Autofac 在 IOC 思想的实现和 Autofac 如何使用作了十分透彻的说明,可是本人水平有限,一些地方没有翻译对,甚至翻译错了,这些我特地指明,省的坑了各位,若是发现不对直接参考原文,但也请告知我,以便改正。app
原文地址:http://www.codeproject.com/Articles/25380/Dependency-Injection-with-Autofac框架
----------------------------------------------------------------------------------------------------------------------------------------------函数
Dependency Injection with Autofac性能
使用 Autofac 进行依赖注入学习
目录测试
Autofac 是发布在 Google Code 上的依赖注入或控制反转的开源容器。
Autofac 与许多相似技术不一样的是它坚持尽量的使用纯质的 C# 语法。【也就说不去依赖其它的组件,从而使得 Autofac 有着更好的兼容性】
等等
这个程序是一个控制台程序,它检查一个备忘录列表,每个备忘录有一个过时日期,程序向用户提醒哪些过时的备忘录。
如下几点做为使用依赖注入的直接缘由:
1 以参数接收全部依赖的对象
2 独立的持久化-IQueryable 对象多是数据库表、一个结构文件,再或者内存集合。(集合公布)
3 提醒用户的形式是独立的。(以接口控制)
这些举措使得这个类容易测试,可配置的而且是可维护的。
IQueryable 接口在 dotnet 3.5 中引入,它适合做为备忘录的数据源。由于它能够同时用于内存对象和关系型数据库的查询。
应用程序最基础的结构以下:
本文主要关注的是 MemoCHecker 如何获取与它关联的 notifier 和 memo 服务,以及每一个被依赖的对象如何获取他们的实体。【有个反转的概念】
更重要的是,它很难去切换不一样的实现服务;好比可能用 EmailNotifier 替换 printing notifier,可是原有的会有依赖,或许不一样来源于这些 PrintingNotifier【不理解】,但也有多是与依赖的其它组件有交互。(这也多是这些组合现成的问题,而它自己就值得写文说明)
Autofac 和其它的依赖组件经过在配置时“扁平化”深度网状对象图。【待译】
当使用 Autofac,访问 MemoChecker 是分离的来源于如下建立方式:
Container.Resolve() 执行请求一个 MemoChecker 的实例,它负责实例的实例化和准备使用。那么,容器是如何工做的、如何建立 MemoChecker 实例。
依赖注入容器是一个把服务映射到组件的集合。在这种情形下,服务是用来识别某一特定的功能,它能够是一个文本标签,但其一般是某个接口。
注册器在系统内部捕获组件动态的行为。其最受关注点是如何建立组件的实例。
Autofac 可以接受建立组件的注册方式有:表达式、提供实例和基于 System.Type 反射。【待译】
下面就是为 MemoChecker 组件设置一个注册器:
每一条 Register() 语句仅只处理那些处于对象图顶端的且其直接关联到依赖对象上。
C=> new MemoChecker(…) 将被用于容器建立 MemoChecker 组件。
每一个 MemoChecker 依赖于额外的两个服务:IQueryable<Memo> 和 IMemoDueNotifier 。这些服务经过容器调用 Resolve() 方法在 lambda 表达式内检索到,容器是经过参数 c 传递过来的。
上面的注册器并无对 IQueryabl<Meno> 和 IMemoDueNotifier 的实现进行任何说明。这两个服务的配置依赖关系同 MemoChecker 的配置相似。
上面的表达式将被提供于 Register() 当其返回 MemoChecker 类型,因而,Autofac 会将其做为这个注册器的默认服务,除非有另外的更为准确的 As() 方法,下面这个 As() 方法包含更为明确的目的:
不管哪一种方式,某个 MemoChecker 实例的请求都将是调用咱们的表达式后的某一结果。
Autofac 不会在组件注册时执行表达式,相反,它会等到 Resolve<MemoChecker>() 调用时执行表达式。这一点很关键,由于它除去了组件注册的顺序的依赖。【依赖关系不受注册顺序影响】
IQueryable<Memo> 服务由存在的 memos 实例提供,PrintingMemoNotifier 类最终指向 TextWriter 的实例 Console.Out 。
Memos 和 Console.Out 都以已经建立的实例提供给容器。(对于 ExternallyOwned() 的解释,请参考 Deterministic Disposal)
Autofac 也能够用其它容器建立组件的方式-反射来建立组件。(更多这个场景的优化伴随着 MSIL-generation)
这种方式的含义是说你能够告诉 Autofac 有关于提供服务的类型,而且容器将会使用最合适的构造函数,以及根据其它可用的服务来选择参数。
MemoChecker 注册能够被下面的形式替换:
通常说来,最多见的作法是使用自动链接去注册某一批次的组件。【待译】
这种方式使得大量的组件可使用但没有繁重的注册每个组件的消耗,而且你须要清楚的思考这种情形。Autofac 提供以下快捷的方式批次注册组件:
自动链接在以程序 XML 配置文件注册组件时也特别实用。
在请求 MemoChecker 服务以前程序建立注册组件以下所示:
在上面的配置代码中没有嵌套显示了“扁平”的依赖结构而这些由容器提供。
这彷佛很难看到上面这种注册方式比手动的例子更为之间的对象结构,但请再次回忆起,这个示例比日常的系统拥有更少的组件。
最为重要的区别是如今每一个组件的配置都独立于全部其余的组件。伴随着更多的组件添加到系统中,他们能够被理解为纯净的按照这些服务所暴露的河这些服务所须要的。这是一种有效的控制架构复杂化的手段。
IDisposable 兼具祝福和诅咒。组件有一致的方式去同其应当被清理交互这是好的。不幸的是,哪一个组件在何时应当被清理并不老是很容易肯定。
这个问题因为容许相同的服务有不一样的实现而变得糟糕。在这个示例中,IMemoDueNotifier 有许多不一样的实现可能被部署。其中的一些将有工厂建立,一些将会是单例的形式,一些将会被清理,还有一些将不会被清理。
组件做为一个通告者是没有办法决定它们应当尝试把它丢给 IDisposable 和调用 Dispose() 或者是不这样作。各类记录的结果是致使易错的河繁琐的。
Autofac 使用经过容器跟踪建立的全部能够清理对象方式解决这个问题。记录的示例以下:
容器在一个 using 程序块中,由于它拥有全部它建立的组件的全部权,而且清理它们当容器被清理的时候。
这一点很重要由于它真正实现了从配置关注分离的精神【待译】,MemoChecker 服务能够在任何须要它的时候使用,甚至是以另外被依赖的组件角色被直接建立,不用担忧它们是否应当被清理。
伴随着这个带来的心里的平静,你甚至不用来回读示例程序来发现任何须要实现 IDisposable (实际是没有)的类,由于你能够依赖容器去作正确的事情。
Disabling Disposal
记住 ExternallyOwned() 子句在上面完整的示例中添加到 Console.Out 的注册上。这是合意的由于 Console.Out 是可清理的,但这个时候容器不该当去清理它。
容器将会正常的存在于应用程序执行期间,而且在相同应用程序长生命周期内清理它是一个很好的方式去释放组件所拥有的资源。大多数不平凡的程序也应释放资源在一些其它的时候,如:Http 请求完成、工做线程退出或者一个用户会话结束。
Autofac 使用嵌套的生命周期域帮助你管理这些生命周期,代码以下:
生命周期管理是经过注册组件实例映射到生命周期域实现的。
Autofac 容许你指定一个组件多少实例能够驻留以及它们将如何在其它组件间共享。
控制组件独立的定义做用域是一个很是重要的改进对于传统方法使用静态 Instance 属性来定义单例。这个区别在于对象是什么和如何使用对象。【待译】
使用 Autofac 最经常使用生命周期设置以下:
单例
每一依赖一个实例
每一辈子命做用域一个实例
单例生命周期,它将是大多数组件只有一个实例在容器中的选择,而且实例会随着建立它的容器清理时被清理。
一个组件可使用 SingleInstance() 修饰配置为这种生命周期,以下所示:
每次这样的组件从容器请求时,都会返回相同的实例:
当组件注册时没有特地指定生命周期,将会默认 instance-per-dependency 生命周期。每次从容器获取这样的组件时,都会返回新建的实例:
某个使用这种生命周期的组件将会跟随着组件被建立的生命周期而被清理。若是一个 per-dependency 组件被请求是去构造一个 single-instance 组件,对于这种例子,那么 per-denpendency 组件将会随着 single-instance 组件对于容器的生命周期一直存在。
这种方式知足每一线程、每一请求或者每一事务组件的生命周期的灵活需求。简单建立一个生命做用域能够生存在必须的生命周期持续的周期。【待译】来自相同的做用域请求将会获得相同的实例,同时来自不一样做用域的请求将会获得不一样的实例。
组件间的依赖仅只在其知足其它的组件在其相同的做用域或者在其外部(父)做用域才能创建。这样确保组件间的依赖在其没有创建前被处理掉。【待译】若是 application、session 和Request 有着嵌套的需求,那么可能会按照以下的方式建立:
在这个示例中请知道,appContainer 将会建立许多子 sessionLifetime,而且每一个 session 同appContainer 同样会有许多子 controller。【待译】
在这个场景,容许依赖的方向是 Request -> session -> application。用于处理用户请求的组件能够引用任何其余的组件。可是依赖关系在相反的方向上是不被容许的,因此,对于这个状况,应用程序级别的 single-instance 组件将不会链接到指定单例用户 session 的组件。【待译】
在这样的层次结构中,Autofac 老是服务于 shortest-lived 生命周期的组件请求。这将会日常的请求生命周期。【待译】Single-instance 组件将会驻留在应用程序级别,来将组件的生命周期关联到 session 级别,详情请参考 wiki。【待译】
Autofac 的做用域模式是灵活和有效的。做用域和嵌套生命周期间的关系使得注册庞大的依赖成员成为可能。
依赖注入是一种极其强大的结构控制机制,可是想要获取这些优点,系统的组件经过容器成为其它组件能用的占比十分重要。
到目前为止 Autofac 所描述的特征都是被设计为获取存在的,当“老的简朴的” .Net 组件添加到容器中,不须要修改或适配代码。
使用表达式来向容器注册组件在使用 Autofac 的应用程序中。一些示例场景说明这些由 Autofac 实现的:
已经存在的工厂方法能够用表达式的形式使用:
已经存在须要在第一次访问时加载的单例可使用表达式注册,而且它的加载是延迟的:
传递给组件的参数可使任何的来源:
某个类型的实现甚至能够根据参数来决定:
集成,在这里的意思是使得已存在的类库服务和程序组件经过容器使他们可使用。
Autofac 支持一些典型场景的集成好比在 ASP.Net 应用程序中使用的那样;然而,Autofac 模型的灵活性产生了大量的繁琐的集成工做,于是最好的方式是把这些留给程序设计者在他们程序最合适的地方实现。
基于表达式的注册和指定的清理以及延迟加载组件的方案,能够产生使人惊奇的效果当它们集成在一块儿时:
这是一个 WCF client 集成自 Autofac 网站的示例。ITrackListing 和 IChannelFactory<ITrackkListing> 这两个关键的服务,WCF 管道对于这些通用的 bit 流很容易基于表达式进行注册。【待译】
一些要点以下:
Channel 工厂只有在其须要的时候建立,可是一旦建立,它将保留以在每一次 ITrackListing 请求时重用。
ITrackListing 不继承自 IDisposable,但在 WCF 中,客户端服务代理以这种方式建立须要联系到 IDisposable 而且清理它。使用 ITRackListing 接口,使得仍然不知道其实现细节。
终端信息能够来自任何地方-任意服务、数据库或者某个配置文件。
除了使用基本的 Register() 方法没有其余概念引入。
这小节向你展现 Autofac 是如何工做的,使得你集中于实现你的应用程序,而不是扩展或惊奇 DI 容器的复杂性。
我但愿这篇文章用来讲明来学习如何使用 Autofac 的各类要点,接下来的步骤多是:
下载源代码
在 Wiki 上阅读更多文章
在论坛里介绍你本身