使用 Autofac 进行依赖注入

 先说下为什么翻译这篇文章,既定的方向是架构,然后为了学习架构就去学习一些架构模式、设计思想。

     突然有一天发现依赖注入这种技能。为了使得架构可测试、易维护、可扩展,需要架构设计为松耦合类型,简单的说也就是解耦。为了解耦前面的人提出各种理论,主要思想是控制反转,而现在主流的主要是两个:依赖注入、服务定位(有篇英文文章特意讨论这种模式,最终的结论是否定的,乍看了一眼,没看懂)

    有了某个思想便可以在程序中体现,用多了,人们就去对它进行封装,普通的人封装的大概就自己用,高人封装了便成了组件。现在基本上都在弄 .net ,所以说的技术也基本上是这一块的。.net 的 IOC 框架有 Autofac、Castle Windsor、Unity、Spring.NET、StructureMap、Ninject。

    有这么多框架为什么选 Autofac,我在这个地方只是学习这种 IOC 思想的框架,并没有真实的用在生产中。Autofac 各方面的的性能都比较中庸,所以用它作为 IOC 入门应该是比较合适的,这样也就导致这篇文章适合初学者阅读。

    接下来就要具体说下翻译的原文,文章对于 Autofac 在 IOC 思想的实现和 Autofac 如何使用做了十分透彻的说明,但是本人水平有限,一些地方没有翻译对,甚至翻译错了,这些我特意指明,省的坑了各位,如果发现不对直接参考原文,但也请告知我,以便改正。

    原文地址:http://www.codeproject.com/Articles/25380/Dependency-Injection-with-Autofac

----------------------------------------------------------------------------------------------------------------------------------------------

Dependency Injection with Autofac

使用 Autofac 进行依赖注入

目录

Introduction-介绍

Autofac 是发布在 Google Code 上的依赖注入或控制反转的开源容器。

Autofac 与许多类似技术不同的是它坚持以近乎 C# 的材质

等等

The Example Application-应用程序示例

这个程序是一个控制台程序,它检查一个备忘录列表,每一个备忘录有一个过期日期,程序向用户提醒哪些过期的备忘录。

Checking for Overdue Memos-检查过期备忘录

以下几点作为使用依赖注入的直接原因:

1 以参数接收所有依赖的对象

2 独立的持久化-IQueryable 对象可能是数据库表、一个结构文件,再或者内存集合。(集合公布)

3 提醒用户的形式是独立的。(以接口控制)

这些举措使得这个类容易测试,可配置的并且是可维护的。

Notifying the User-提醒用户

Data Storage-数据仓储

IQueryable 接口在 dotnet 3.5 中引入,它适合作为备忘录的数据源。因为它可以同时用于内存对象和关系型数据库的查询。

Wiring Up Components-连接组件

应用程序最基础的结构如下:

 

本文主要关注的是 MemoCHecker 如何获取与它关联的 notifier 和 memo 服务,以及每个被依赖的对象如何获取他们的实体。【有个反转的概念】

Dependency Injection by Hand-手动依赖

更重要的是,它很难去切换不同的实现服务;比如可能用 EmailNotifier 替换 printing notifier,但是原有的会有依赖,或许不同来源于这些 PrintingNotifier【不理解】,但也有可能是与依赖的其它组件有交互。(这也可能是这些组合现成的问题,而它本身就值得写文说明)

Autofac 和其它的依赖组件通过在配置时“扁平化”深度网状对象图。【待译】

Dependency Injection with a Container-容器依赖

当使用 Autofac,访问 MemoChecker 是分离的来源于以下创建方式:

Container.Resolve() 执行请求一个 MemoChecker 的实例,它负责实例的实例化和准备使用。那么,容器是如何工作的、如何创建 MemoChecker 实例。

Component Registrations-注册组件

依赖注入容器是一个把服务映射到组件的集合。在这种情形下,服务是用来识别某一特定的功能,它可以是一个文本标签,但其通常是某个接口。

注册器在系统内部捕获组件动态的行为。其最受关注点是如何创建组件的实例。

Autofac 能够接受创建组件的注册方式有:表达式、提供实例和基于 System.Type 反射。【待译】

Registering a Component Create with Expression-使用表达式注册组件

下面就是为 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>() 调用时执行表达式。这一点很关键,因为它除去了组件注册的顺序的依赖。【依赖关系不受注册顺序影响】

Registering a Component Instance-使用实例注册组件

IQueryable<Memo> 服务由存在的 memos 实例提供,PrintingMemoNotifier 类最终指向 TextWriter 的实例 Console.Out 。

Memos 和 Console.Out 都以已经创建的实例提供给容器。(对于 ExternallyOwned() 的解释,请参考 Deterministic Disposal)

Registering a Component with its Implementation Type-使用实现类型注册组件

Autofac 也可以用其它容器创建组件的方式-反射来创建组件。(更多这个场景的优化伴随着 MSIL-generation)

这种方式的含义是说你可以告诉 Autofac 有关于提供服务的类型,并且容器将会使用最合适的构造函数,以及根据其它可用的服务来选择参数。

MemoChecker 注册可以被下面的形式替换:

一般说来,最常见的做法是使用自动连接去注册某一批次的组件。【待译】

这种方式使得大量的组件可以使用但没有繁重的注册每一个组件的消耗,并且你需要清楚的思考这种情形。Autofac 提供如下快捷的方式批次注册组件:

自动连接在以程序 XML 配置文件注册组件时也特别实用。

Completing the Example-完整示例

在请求 MemoChecker 服务之前程序创建注册组件如下所示:

在上面的配置代码中没有嵌套显示了“扁平”的依赖结构而这些由容器提供。

这似乎很难看到上面这种注册方式比手动的例子更为之间的对象结构,但请再次回忆起,这个示例比平常的系统拥有更少的组件。

最为重要的区别是现在每个组件的配置都独立于所有其他的组件。伴随着更多的组件添加到系统中,他们可以被理解为纯净的按照这些服务所暴露的河这些服务所需要的。这是一种有效的控制架构复杂化的手段。

Deterministic Disposal-指定清理

IDisposable 兼具祝福和诅咒。组件有一致的方式去同其应当被清理交互这是好的。不幸的是,哪个组件在什么时候应当被清理并不总是很容易确定。

这个问题由于允许相同的服务有不同的实现而变得糟糕。在这个示例中,IMemoDueNotifier 有许多不同的实现可能被部署。其中的一些将有工厂创建,一些将会是单例的形式,一些将会被清理,还有一些将不会被清理。

组件作为一个通告者是没有办法决定它们应当尝试把它丢给 IDisposable 和调用 Dispose() 或者是不这样做。各种记录的结果是导致易错的河繁琐的。

Autofac 使用通过容器跟踪创建的所有可以清理对象方式解决这个问题。记录的示例如下:

容器在一个 using 程序块中,因为它拥有所有它创建的组件的所有权,并且清理它们当容器被清理的时候。

这一点很重要因为它真正实现了从配置关注分离的精神【待译】,MemoChecker 服务可以在任何需要它的时候使用,甚至是以另外被依赖的组件角色被直接创建,不用担心它们是否应当被清理。

伴随着这个带来的内心的平静,你甚至不用来回读示例程序来发现任何需要实现 IDisposable (实际是没有)的类,因为你可以依赖容器去做正确的事情。

Disabling Disposal

记住 ExternallyOwned() 子句在上面完整的示例中添加到 Console.Out 的注册上。这是合意的因为 Console.Out 是可清理的,但这个时候容器不应当去清理它。

Fine-Grained Control of Component Lifetimes-精细控制组件生命周期

容器将会正常的存在于应用程序执行期间,并且在相同应用程序长生命周期内清理它是一个很好的方式去释放组件所拥有的资源。大多数不平凡的程序也应释放资源在一些其它的时候,如:Http 请求完成、工作线程退出或者一个用户会话结束。

Autofac 使用嵌套的生命周期域帮助你管理这些生命周期,代码如下:

生命周期管理是通过注册组件实例映射到生命周期域实现的。

Component Lifetime-组件生命周期

Autofac 允许你指定一个组件多少实例可以驻留以及它们将如何在其它组件间共享。

控制组件独立的定义作用域是一个非常重要的改进对于传统方法使用静态 Instance 属性来定义单例。这个区别在于对象是什么和如何使用对象。【待译】

使用 Autofac 最常用生命周期设置如下:

单例

每一依赖一个实例

每一生命作用域一个实例

Single Instance-单例

单例生命周期,它将是大多数组件只有一个实例在容器中的选择,并且实例会随着创建它的容器清理时被清理。

一个组件可以使用 SingleInstance() 修饰配置为这种生命周期,如下所示:

每次这样的组件从容器请求时,都会返回相同的实例:

Instance Per Dependency-每一依赖一个实例

当组件注册时没有特意指定生命周期,将会默认 instance-per-dependency 生命周期。每次从容器获取这样的组件时,都会返回新建的实例:

某个使用这种生命周期的组件将会跟随着组件被创建的生命周期而被清理。如果一个 per-dependency 组件被请求是去构造一个 single-instance 组件,对于这种例子,那么 per-denpendency 组件将会随着 single-instance 组件对于容器的生命周期一直存在。

Instance per Lifetime Scope-每一生命周期作用域一个实例

这种方式满足每一线程、每一请求或者每一事务组件的生命周期的灵活需求。简单创建一个生命作用域可以生存在必须的生命周期持续的周期。【待译】来自相同的作用域请求将会得到相同的实例,同时来自不同作用域的请求将会得到不同的实例。

Using Scope to Control Visibility-使用作用域去控制组件依赖的可见性

组件间的依赖仅只在其满足其它的组件在其相同的作用域或者在其外部(父)作用域才能建立。这样确保组件间的依赖在其没有建立前被处理掉。【待译】如果 application、session 和Request 有着嵌套的需求,那么可能会按照如下的方式创建:

在这个示例中请知道,appContainer 将会创建许多子 sessionLifetime,并且每个 session 同appContainer 一样会有许多子 controller。【待译】

在这个场景,允许依赖的方向是 Request -> session -> application。用于处理用户请求的组件可以引用任何其他的组件。但是依赖关系在相反的方向上是不被允许的,所以,对于这个情况,应用程序级别的 single-instance 组件将不会连接到指定单例用户 session 的组件。【待译】

在这样的层次结构中,Autofac 总是服务于 shortest-lived 生命周期的组件请求。这将会平常的请求生命周期。【待译】Single-instance 组件将会驻留在应用程序级别,来将组件的生命周期关联到 session 级别,详情请参考 wiki。【待译】

Autofac 的作用域模式是灵活和有效的。作用域和嵌套生命周期间的关系使得注册庞大的依赖成员成为可能。

Autofac in Application-在程序中使用 Autofac

依赖注入是一种极其强大的结构控制机制,但是想要获取这些优势,系统的组件通过容器成为其它组件能用的占比十分重要。

到目前为止 Autofac 所描述的特征都是被设计为获取存在的,当“老的简朴的” .Net 组件添加到容器中,不需要修改或适配代码。

Expressive Registrations-显示注册

使用表达式来向容器注册组件在使用 Autofac 的应用程序中。一些示例场景说明这些由 Autofac 实现的:

已经存在的工厂方法可以用表达式的形式使用:

已经存在需要在第一次访问时加载的单例可以使用表达式注册,并且它的加载是延迟的:

传递给组件的参数可以使任何的来源:

某个类型的实现甚至可以根据参数来决定:

Simplified Integration-简单集成

集成,在这里的意思是使得已存在的类库服务和程序组件通过容器使他们可以使用。

Autofac 支持一些典型场景的集成比如在 ASP.Net 应用程序中使用的那样;然而,Autofac 模型的灵活性产生了大量的繁琐的集成工作,因而最好的方式是把这些留给程序设计者在他们程序最合适的地方实现。

基于表达式的注册和指定的清理以及延迟加载组件的方案,可以产生令人惊奇的效果当它们集成在一起时:

这是一个 WCF client 集成自 Autofac 网站的示例。ITrackListing 和 IChannelFactory<ITrackkListing> 这两个关键的服务,WCF 管道对于这些通用的 bit 流很容易基于表达式进行注册。【待译】

一些要点如下:

Channel 工厂只有在其需要的时候创建,但是一旦创建,它将保留以在每一次 ITrackListing 请求时重用。

ITrackListing 不继承自 IDisposable,但在 WCF 中,客户端服务代理以这种方式创建需要联系到 IDisposable 并且清理它。使用 ITRackListing 接口,使得仍然不知道其实现细节。

终端信息可以来自任何地方-任意服务、数据库或者某个配置文件。

除了使用基本的 Register() 方法没有其他概念引入。

这小节向你展示 Autofac 是如何工作的,使得你集中于实现你的应用程序,而不是扩展或惊奇 DI 容器的复杂性。

Where to Next?

我希望这篇文章用来说明来学习如何使用 Autofac 的各种要点,接下来的步骤可能是:

下载源代码

在 Wiki 上文章

在论坛里介绍你自己

相关文章: 

  • 为ASP.NET MVC程序集成Autofac

  • 基于DDD的现代ASP.NET开发框架--ABP系列之6、ABP依赖注入


原文地址:http://www.cnblogs.com/Ricky81317/p/5604690.html


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/329140.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

组合的示例代码 java_java实现Composite组合模式的实例代码

//20210121写在前面&#xff1a;刚期末考试完&#xff0c;考了面向对象&#xff0c;里边儿有23个设计模式&#xff0c;我寻思着考完挨个儿实现一下&#xff0c;本文实现组合模式组合模式核心思想类似文件夹的概念&#xff0c;构件树形结构&#xff0c;树形有叶子结点和文件夹结…

Java中的ThreadPoolExecutor类

转载自 Java中的ThreadPoolExecutor类在前面的文章中&#xff0c;我们使用线程的时候就去创建一个线程&#xff0c;这样实现起来非常简便&#xff0c;但是就会有一个问题&#xff1a; 如果并发的线程数量很多&#xff0c;并且每个线程都是执行一个时间很短的任务就结束了&…

webpack 前端构建

一、建立简单的项目目录 1、创建 manager 根目录(作为项目根目录)2、执行 npm init&#xff0c;在根目录manager下自动生成 package.json文件3、npm install webpack --save-dev&#xff0c;在项目中安装 webpack npm包4、在根目录下 创建 webpack.config.js&#xff0c;所有的…

简析 .NET Core 构成体系

简析 .NET Core 构成体系Roslyn 编译器RyuJIT 编译器CoreCLR & CoreRTCoreFX(.NET Core Libraries).NET Core 代码开发、部署、运行过程总结 前文介绍了.NET Core 在整个.NET 平台所处的地位&#xff0c;以及与.NET Framework的关系(原文链接)&#xff0c;本文将详细介绍.N…

判断一个男人穷还是富,只看这几点!

转载至&#xff1a; 来源&#xff1a;甜蜜爸妈手记&#xff08;wxtm01&#xff09; 作者&#xff1a;甜甜妈 创业君 导读 千主意万主意&#xff0c;如果不行动&#xff0c;永远就只是个想法而已。好想法要配得上行动才行。 看看他的爱好一个有事业心男人&#xff0c;绝对不…

php制作留言板的题_PHP实现留言板功能实例代码

本文实例为大家分享了php留言板的实现思路&#xff0c;供大家参考&#xff0c;具体内容如下&#xff1a;1.创建一个存放留言信息的文件名2.获取表单中的数据给一个变量3.判断文件的时候存在4.对文件执行写的操作&#xff0c;在这之前&#xff0c;注意打开文件的时候&#xff0c…

Java线程池,从使用到原理

转载自 Java线程池&#xff0c;从使用到原理线程池的技术背景 在面向对象编程中&#xff0c;创建和销毁对象是很费时间的&#xff0c;因为创建一个对象要获取内存资源或者其它更多资源。在Java中更是如此&#xff0c;虚拟机将试图跟踪每一个对象&#xff0c;以便能够在对象销毁…

聊聊HTTPS和SSL/TLS协议

要说清楚 HTTPS 协议的实现原理&#xff0c;至少需要如下几个背景知识。1. 大致了解几个基本术语&#xff08;HTTPS、SSL、TLS&#xff09;的含义2. 大致了解 HTTP 和 TCP 的关系&#xff08;尤其是“短连接”VS“长连接”&#xff09;3. 大致了解加密算法的概念&#xff08;尤…

php事件编程,PHP相应button中onclick事件的案例分析

PHP相应button中onclick事件的案例分析发布时间&#xff1a;2020-11-10 11:28:31来源&#xff1a;亿速云阅读&#xff1a;71作者&#xff1a;小新小编给大家分享一下PHP相应button中onclick事件的案例分析&#xff0c;相信大部分人都还不怎么了解&#xff0c;因此分享这篇文章给…

Java 中Timer和TimerTask 定时器和定时任务使用的例子

转载自 Java 中Timer和TimerTask 定时器和定时任务使用的例子 这两个类使用起来非常方便&#xff0c;可以完成我们对定时器的绝大多数需求 Timer类是用来执行任务的类&#xff0c;它接受一个TimerTask做参数 Timer有两种执行任务的模式,最常用的是schedule,它可以以两种方式执…

复制一个5G文件只需要两秒,全网最牛方法!

文章来至 微信公众号&#xff1a;中国黑客联盟 很多时候我们在复制比较大的文件的时候是一件多么痛苦的事情&#xff0c;因为少的几分钟多则十几分钟&#xff0c;这样的等待是我们无法容忍的&#xff01;那么今天我们就教大家如何快速的复制电脑大文件&#xff01; 首先我…

.NET Core也可以使用MongoDB了

可能是由于.NET Core还不是正式版的缘故吧&#xff0c;MongoDB的官方Driver(http://mongodb.github.io/mongo-csharp-driver/)一直不支持.NET Core&#xff0c;这给想在.NET Core上尝试MongoDB带来了不便&#xff0c;本人就是其中之一 &#xff1a;&#xff09; 于是Fork了官方…

Java多线程系列--“JUC线程池”06之 Callable和Future

转载自 Java多线程系列--“JUC线程池”06之 Callable和FutureCallable 和 Future 简介Callable 和 Future 是比较有趣的一对组合。当我们需要获取线程的执行结果时&#xff0c;就需要用到它们。Callable用于产生结果&#xff0c;Future用于获取结果。 1. Callable Callable 是…

php array分组,php数组分组简单例子

在php网站开发过程中有时候需要把结果集进行分组&#xff0c;使用php的内置函数array_chunk就可以实现 代码如下复制代码$teamsarray(1,2,3,4,5,6,7,8,9);$teamsarray_chunk($teams,2);print_r($teams);/*Array([0] > Array([0] > 1[1] > 2)[1] > Array([0] > 3…

SuperSocket源码解析之开篇

一 简介 官方介绍&#xff1a;SuperSocket 是一个轻量级, 跨平台而且可扩展的 .Net/Mono Socket 服务器程序框架。你无须了解如何使用 Socket, 如何维护 Socket 连接和 Socket 如何工作&#xff0c;但是你却可以使用 SuperSocket 很容易的开发出一款 Socket 服务器端软件&#…

Java守护线程概述

转载自 Java守护线程概述Java的线程分为两种&#xff1a;User Thread(用户线程)、DaemonThread(守护线程)。 只要当前JVM实例中尚存任何一个非守护线程没有结束&#xff0c;守护线程就全部工作&#xff1b;只有当最后一个非守护线程结束是&#xff0c;守护线程随着JVM一同结束…

php while循环次数,php while循环得到循环次数

php while循环得到循环次数复制代码 代码如下:$link mysql_connect(localhost,root,pwd);mysql_select_db(db);$sql "select region_id,local_name from regions where region_grade1";$result mysql_query($sql);$i 0;while ($row mysql_fetch_assoc($result)) {…

EntityFramework和EntityFramework.Extended使用说明——性能,语法和产生的sql

环境说明:EntityFramework 6.1.3和.Net Framework4.5性能注意事项:https://msdn.microsoft.com/zh-cn/library/cc853327.aspx比较精髓的一点:查询执行的各个阶段中的准备查询,每个唯一查询一次。包括编写查询命令、基于模型和映射元数据生成命令树和定义所返回数据的形状的成本…

三个水桶(看了三遍,想了五遍!)

转载至&#xff1a;微信公众号&#xff1a; 创业励志网 一 有位木匠砍了一树&#xff0c;把它做了三个木桶。 一个装粪&#xff0c;就叫粪桶&#xff0c;众人躲着&#xff1b; 一个装水&#xff0c;就叫水桶&#xff0c;众人用着&#xff1b; 一个装酒&#xff0c;就叫酒桶&…

nginx解析php失败,为什么nginx不能解析php?

只运行过这些代码yum install -y vim wget zip unzip git httpd php php-mysql php-odbc php-ldap php-gd php-mbstring php-xml php-xml-rpc php-bcmath libjpeg* mariadb ;rpm -Uvh http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarc…