Autofac全面解析系列(版本:3.5) – [使用篇(推荐篇):1.类型注册]
前言
Autofac
Autofac是一套高效的依赖注入框架。
Autofac官方网站:http://autofac.org/
Autofac在Github上的开源项目:https://github.com/autofac/Autofac
Autofac安装:通过VS的Nuget可以很方便的获取。
IoC/DI
关于IoC与DI的概念,网上有很多相关的博客,大家可以稍微了解一下,对比一下。
我个人的理解就是按照英文的中文翻译来理解的:
IoC: Inversion of Control 控制反转,将控制权进行反转,将本由自身控制的对象初始化交由外部IoC容器进行初始化;
DI: Dependency Injection 依赖注入,将对象依赖的其他对象,通过注入的方式进行初始化。
简单示例
我们先通过一个简单的例子来看看Autofac的基本使用方式以及一些概念:
class Program
{
static void Main(string[] args)
{
var builder = new ContainerBuilder();
builder.RegisterType<Class_1>(); //将Class_1注册到Autofac容器中 IContainer container = builder.Build();
Class_1 obj = container.Resolve<Class_1>(); //从autofac容器中获取Class_1对象
Console.WriteLine(obj.Id); Console.Write("Press any key to continue...");
Console.ReadKey();
}
}class Class_1
{
public Guid Id { get; set; } public Class_1()
{
Id = Guid.NewGuid();
}
}上面的代码演示了最简单注册/获取方式。我们先通过ContainerBuilder进行类型注册,然后在后面可以通过IContainer进行获取类型实例。这里我们也明白了一点,类型是需要先进行注册,然后才能够通过Autofac进行获取(后面会谈到一些特殊的配置,但是这也属于另类的注册方式)。
然后我们能知道在Autofac中,先通过ContainerBuilder进行类型注册,然后通过ContainerBuilder的Build方法来获取IContainer类型实例,后面则可以通过该IContainer实例来获取注册类型的实例对象。
Autofac类型注册
类型/泛型注册
在简单实例中,我们已经看到了一种注册方式,那就是泛型注册:
builder.RegisterType<Class_1>();这种注册方式很方便也很简单,比较常用,但是有一个缺点就是,注册的类型必须在当前项目或被当前项目引用,因为使用泛型,必须类型明确。针对这点,还有一种通过Type对象进行注册的方式:
//字符串为类型完全名称
builder.RegisterType(Type.GetType("AutofacBlog.Class_1"));使用这种方式进行类型注册,被注册的类型可以不是被直接引用,但是注意,类型所在的程序集必须被加载。
这种注册方式,在有插件或类似需要动态加载程序集的情况下比较使用,通过扫描程序集,获取一些满足指定条件的类型,来进行注册。
程序集批量注册
类型注册中提到了通过扫描程序集,来获取部分类型进行注册。Autofac对此提供了一个方便的方式,可以直接通过程序集来筛选类型注册:
//获取当前应用程序加载程序集(C/S应用中使用)
var assembly = Assembly.GetExecutingAssembly();
var builder = new ContainerBuilder();
builder.RegisterAssemblyTypes(assembly); //注册所有程序集类定义的非静态类型上述代码中,通过RegisterAssemblyTypes方法,将assembly中所有自定义的非静态类型都注册到Autofac中,后面可以使用IContainer对象获取所有该程序集中自定义的类型对象。
这种方式达到了批量的效果,但是通常,我们并不需要把所有的类型都进行注册,所以Autofac提供了几种过滤方式:
builder.RegisterAssemblyTypes(assembly)
.Where(type => type.Namespace.Equals("IocAutofac.Example")); //条件判断这种方式相信大家都比较熟悉,Where+lambda的方式来进行条件判断,lambda参数为Type类型,也就是程序集中的type。
builder.RegisterAssemblyTypes(assembly)
.Except<Program>(); //排除Program类型这种方式用来排除指定类型的注册,当排除的个例比较少时,会比较适用。Except还有另一种用法,但是用法比较复杂,在此不进行介绍。
builder.RegisterAssemblyTypes(assembly)
.InNamespace("IocAutofac.Example"); //类型在IocAutofac.Example命名空间中被注册的类型需要在指定命名空间中。
builder.RegisterAssemblyTypes(assembly)
.InNamespaceOf<Program>(); //类型在Program所在的命名空间中*/这种方式与上面一种方式比较相似,也是用来判断命名空间的,这种方式是根据类型来获取命名空间。
通过这种方式,我们可以对程序集中的类型进行批量注册,类型/泛型方式在被注册类型较少的情况下还是不错的,但当被注册类型很多的时候,一个一个的手写注册会显得很无力,这时候就是程序集批量注册显威的时候了。
Lambda注册
上面讲到的两种方式都是通过类型进行直接注册的,这种注册方式,在获取时,会直接通过构造函数new出对象(关于构造函数的优选选择在后面的博文中将进行说明),不会做更多的操作。有时,我们希望能够在获取对象时能够自动的做更多的事情时,我们可以通过Lambda注册来解决:
builder.Register(cc =>
{
var clas1 = new Class_1();
while (clas1.Id.ToString().Contains("a"))
{
clas1.Id = Guid.NewGuid();
}
return clas1;
});上述代码,实际注册了Class_1类型,因为最后返回的对象类型为Class_1。
Register方法接收了一个lambda表达式作为参数,在lambda表达式中,我们可以做很多事,包括一些属性注入(后续说明)、方法注入(后续说明)、条件判断等等。
我们在通过Autofac获取Class_1对象时,实际会执行这样的一个表达式。另外,lambda表达式的参数cc的类型是IComponentContext,这里我们可以简单的当做IContainer进行使用。
实例注册
var clas1 = new Class_1();
clas1.Id = Guid.Empty; builder.RegisterInstance(clas1);通过RegisterInstance进行实例注册,进行实例注册时,我们需要注意,实例注册可以作为一种单例注册的方式,也就是在后面通过Autofac获取Class_1对象时,获取到的是注册时的那个对象。并且,如果一个在某处修改了该对象,其他地方再获取时,获取到的就是修改后的对象。
Module注册
在日常开发中,可能不同开发会负责不同的模块进行单独开发。在开发过程中,不同模块不同开发可能都有自己的类型需要注册到autofac中,但是如果每个人在注册时,都去修改一个指定地方的代码,这在进行代码合并时,是令人痛苦的。更好的方式是,每个开发不同的模块都有自己指定的类型注册区域,这样,在代码合并时,会减少很多代码冲突。
对于这种方式,Autofac已经为我们提供了:
class Program
{
static void Main(string[] args)
{
var builder = new ContainerBuilder(); builder.RegisterModule<ModuleA>();
//这两种注册方式达到的效果都一样
builder.RegisterModule(new ModuleB()); IContainer container = builder.Build();
Class_1 clas1 = container.Resolve<Class_1>();
Class_2 clas2 = container.Resolve<Class_2>();
Console.WriteLine(clas1.Id);
Console.WriteLine(clas2.ToString()); Console.Write("Press any key to continue...");
Console.ReadKey();
}
} class ModuleA : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<Class_1>();
}
} class ModuleB : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<Class_2>();
}
}class Class_2
{ }上述代码中,有两个继承自Module类的类:ModuleA、ModuleB,这两个类型重写了父类的Load方法,并在load方法中,分别注册了Class_1与Class_2类型。然后在主程序中,通过RegisterModule对Module进行注册。
通过这种方式,不同的开发就可以各自创建一个类继承自Module,然后重写Load方法,在Load方法进行自己的类型注册,最后再进行Module的统一注册。
Module注意说明
实际上,RegisterModule需要的参数,并不是继承自Module类的,而是实现了IModule接口的类,而Module也是实现了IModule接口的。也就是我们也可以写一个实现了IModule接口的类型,然后在RegisterModule时传入。但是一般我们直接去继承Module就好了,这种方式比较简单方便,实现IModule的方式更为复杂,当然,功能也更多,在此就不进行介绍了。
程序集Module注册
Module注册,为多人开发提供了一种方便的注册方式,但是我们也可以发现,这种方式,还是会需要手动注册Module,如果Module过多,Module注册代码也会显得多而杂,当然,可以通过人工管理来控制Module的量。但是Autofac还提供了一种更方便的方式,并且,对于类似Orchard的模块开发(子模块与主模块无引用关系,通过程序集加载方式来加载子模块)或是插件开发,我们没办法通过Registerodule来注册无直接引用关系的Module。
对于上述的情况,Autofac提供了很好的方式来解决:
var builder = new ContainerBuilder();
var assembly = Assembly.GetExecutingAssembly();
builder.RegisterAssemblyModules(assembly);上述代码会注册assembly程序集中所有实现了IModule接口的类型(多层继承也算),这样,我们只需要将取出所有程序集,然后通过RegisterAssemblyModules进行一次性注册,就可以自动注册所有Module了。
RegisterAssemblyModule还可以指定一个泛型类型:
builder.RegisterAssemblyModules<ModuleA>(assembly);这样注册,是指定只注册assembly程序集中继承自ModuleA的Module。
尾述
本篇博文主要讲述Autofac中比较常用也比较好用的注册方式,并没有把所有的注册方式都讲述出来。
个人非常推荐使用Module,每个项目拥有自己的一个Module,这样的一个Module都有固定的未知,便于查找该项目中的注册及依赖关系。
通过本篇博文,可以了解到几种常用的注册方式,以及最简单的对象获取方式,初学者可以简单的试试。
本篇博文讲述的内容可能与大家平时使用autofac的方式不一样,平时使用时还会使用As,但是我个人认为这个不属于单纯注册的内容,所以将这部分放到后面的博文中。
Autofac全面解析系列(版本:3.5) – [使用篇(推荐篇):1.类型注册]的更多相关文章
- Autofac全面解析系列(版本:3.5) – [使用篇(推荐篇):2.解析获取]
前言 Autofac是一套高效的依赖注入框架. Autofac官方网站:http://autofac.org/ Autofac在Github上的开源项目:https://github.com/auto ...
- 【原】Android热更新开源项目Tinker源码解析系列之一:Dex热更新
[原]Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Tinker是微信的第一个开源项目,主要用于安卓应用bug的热修复和功能的迭代. Tinker github地址:http ...
- ETL利器Kettle实战应用解析系列一【Kettle使用介绍】
本系列文章主要索引如下: 一.ETL利器Kettle实战应用解析系列一[Kettle使用介绍] 二.ETL利器Kettle实战应用解析系列二 [应用场景和实战DEMO下载] 三.ETL利器Kettle ...
- Telegram学习解析系列(二):这我怎么给后台传输数据?
写在前面: 在iOS开发的过程中,有很多时候我们都在和数据打交道,最基本的就是数据的下载和上传了,估计很多很多的小伙伴都在用AFNetworking与后台数据打交道,可有没有想过,哪天AFNetwor ...
- 蓝鲸DevOps深度解析系列(2):蓝盾流水线初体验
关注嘉为科技,获取运维新知 前面一篇文章<蓝鲸DevOps深度解析系列(1):蓝盾平台总览>,我们总览了蓝鲸DevOps平台的背景.应用场景.特点和能力: 接下来我们继续解析蓝盾平台的 ...
- ECShop全系列版本远程代码执行高危漏洞分析+实战提权
漏洞概述 ECShop的user.php文件中的display函数的模版变量可控,导致注入,配合注入可达到远程代码执行.攻击者无需登录站点等操作,可以直接远程写入webshell,危害严重. 漏洞评级 ...
- TiKV 源码解析系列文章(三)Prometheus(上)
本文为 TiKV 源码解析系列的第三篇,继续为大家介绍 TiKV 依赖的周边库 rust-prometheus,本篇主要介绍基础知识以及最基本的几个指标的内部工作机制,下篇会介绍一些高级功能的实现原理 ...
- Android源码解析系列
转载请标明出处:一片枫叶的专栏 知乎上看了一篇非常不错的博文:有没有必要阅读Android源码 看完之后痛定思过,平时所学往往是知其然然不知其所以然,所以为了更好的深入Android体系,决定学习an ...
- [转帖]TPC-C解析系列04_TPC-C基准测试之数据库事务引擎的挑战
TPC-C解析系列04_TPC-C基准测试之数据库事务引擎的挑战 http://www.itpub.net/2019/10/08/3331/ OceanBase这次TPC-C测试与榜单上Oracl ...
随机推荐
- idea配置maven并添加镜像配置
1.打开maven存放文件夹找到 conf ->settings.xml 找到<mirrors>节点把下面内容写入节点内 配置为阿里云的镜像 <mirror> <i ...
- 编译安装php-amq扩展
用途:这个扩展是用来操作rabbitmq服务端的 一.安装总括 1.编译安装librabbitmq库 这是一个开源c语言的库.用来与rabbitmq进行通信 而php的php-amqp扩展就是使用这个 ...
- CentOS6.5安装telnet命令
安装好memcache之后想进入连接测试,telnet localhost 11211发现竟然提示没有telnet这个命令,于是需要自己进行安装. 一.查看本机是否安装telnet #rpm -qa ...
- mesos 学习笔记1 -- mesos安装和配置
参考资料: 官方文档:http://mesos.apache.org/documentation 中文翻译:http://mesos.mydoc.io/ GitHub:https://github.c ...
- [转]Dcloud App离线本地存储方案
原文地址:http://ask.dcloud.net.cn/article/166 HTML5+的离线本地存储有如下多种方案:HTML5标准方案:cookie.localstorage.session ...
- Select-or-Die演示11种美化下拉框select方法
在线预览 下载地址 在线实例 <div class="main"> <div class="mianc"> <h1>默认&l ...
- Linux下Oracle重启问题
一.切换成oracle用户 $ su - oracle 注意:不要写成“su oracle ”不然是没办法使用下面的命令的. 如下所示:将会报:command not found的错误 二.使用命令 ...
- [deviceone开发]-viewShower和listView
一.简介 viewshower里嵌套listview,实现复杂的列表效果. 二.效果图 三.相关下载 http://source.deviceone.net/source-detail.html?do ...
- js资源加载优化
互联网应用或者访问量大的应用,对js的加载优化是不可少的.下面记录几种优化方法 CDN + 浏览器缓存 CDN(content delivery network)内容分发网络, 最传统的优化方式.其 ...
- Struts2详细教程
Struts2详细教程:http://www.yiibai.com/struts_2/