微软企业库Unity学习笔记
本文主要介绍:
关于Unity container配置,注册映射关系、类型,单实例、已存在对象和指出一些container的基本配置,这只是我关于Unity的学习心得和笔记,希望能够大家多交流相互学习到更多知识,谢谢大家的支持。
我们可以通过以下两种方法给Unity container中创建映射:
- RegisterType:这个方法可以往container中注册一种类型或映射关系,当我们需要调用该类型的实例时,container会自动实例化该类型的对象,无需通过new someName方法实例化对象(例如:使用Resolve或ResolveAll方法获取注册类型的实例),当没有指定实例化对象的生命周期,将使用默认的TransientLifetimeManager(每次调用Resolve或ResolveAll方法时都会实例化一个新的对象)。
- RegisterInstance:这个方法是往container中注册一个已存在实例,通过Resolve或ResolveAll方法获取该类型的实例,默认使用ContainerControlledLifetimeManager管理对象生命周期,而且container中会保持对象的引用(简而言之每次调用Resolve或ResolveAll方法都会调用同一个对象的引用)。
1.1 注册一个接口或类的映射到具体类型:
使用Register方法可以往容器中注册一种类型或映射关系
- l 往容器中注册一种类型RegisterType<Type>
- l 往容器中注册一种映射关系RegisterType< RegisteredType, TargetType >
调用RegisterType<RegisteredType, TargetType>()方法可以往容器中注册一种映射关系,RegisteredType是一个接口或类,而TargetType必需实现该接口或继承该类。
1.2 注册一个单例类或单例类型实例:
涉及到对象的生命周期(Lifetime Managers):
- l 默认的情况下使用TransientLifetimeManager管理对象的生命周期,以下两种方法效果一样:
container.RegisterType<IMyService, CustomerService>(new TransientLifetimeManager());
- l 使用ContainerControlledLifetimeManager创建单例实例
- l 使用ExternallyControlledLifetimeManager只可以保持对象的弱引用
关于强引用和弱引用:
强引用:当一个根指向一个对象时,该对象不可能被执行垃圾收集,因为程序代码还在访问该对象。
弱引用:允许垃圾收集器收集对象,同时允许应用程序访问该对象,结果是执行哪个要取决于时间。
- l 使用PerThreadLifetimeManager在同一个线程返回同一个对象实例,不同线程对象实例不相同
在使用RegisterType注册类型或映射,如果对对象生命周期进行,将使用默认的TransientLifetimeManager,它不会在container中保存对象的引用,简而言之每当调用Resolve或ResolveAll方法时都会实例化一个新的对象。当我们想在container中保存对象的引用的时我们可以使用ContainerControlledLifetimeManager管理对象的生命周期,简而言之每次调用Resolve或ResolveAll方法都会调用同一个对象的引用。
1.3 注册一个存在对象作为单件实例:
注册一个存在的对象我们使用的是RegisterInstance,它默认使用ContainerControlledLifetimeManager管理对象的生命周期,回顾以下
RegisterType和RegisterInstance区别:
Method |
Default Lifetime Managers |
Same Lifetime Managers |
RegisterType |
TransientLifetimeManager |
ContainerControlledLifetimeManager |
RegisterInstance |
ContainerControlledLifetimeManager |
ContainerControlledLifetimeManager |
当RegisterType和RegisterInstance都使用ContainerControlledLifetimeManager时的区别:
MSDN:If you used the RegisterType method to register a type, Unity creates a new instance of the registered type during the first call to the Resolve or ResolveAll method or when the dependency mechanism injects instances into other classes. Subsequent requests return the same instance.
If you used the RegisterInstance method to register an existing object, Unity returns this instance every time you call the Resolve or ResolveAll method or when the dependency mechanism injects instances into other classes.
翻译:如果使用RegisterType方法注册一种类型,当第一次调用Resolve 或ResolveAll 方法或依赖机制注入一个实例到其他类时,Unity会实例化该注册类型,之后的调用都返回相同实例。
如果使用RegisterInstance方法注册一个存在对象,当我们调用Resolve和ResolveAll方法或赖机制注入一个实例到其他类时,Unity每次都返回该对象实例。
1.4 使用container的fluent interface属性:
这意味着你可以在一条语句中使用方法链
IUnityContainer myContainer =new UnityContainer()
.RegisterType<IMyService, DataService>()
.RegisterType<IMyUtilities, DataConversions>()
.RegisterInstance<IMyService>(myEmailService);
由于IUnityContainer 接口实现了IDispose接口,所有我们可以使用Using控制container资源释放
////IUnityContainer实现接口IDisposable,所以可以使用 ////using有效释放对象占用的系统资源。 using (IUnityContainer container =new UnityContainer()) { ////实现 }
接下来介绍一下依赖注入的方式:
- 构造函数注入
- 属性注入
- 方法注入
一、 构造函数注入
我们将介绍单构造函数和多构造函数注入
1) 单构造函数使用自动注入
- 单构造函数自动注入,这里我们使用一个简单的例子具体类MyObject依赖于具体类MyDependentClass。
////具体类型的依赖关系
publicclass MyOjbect
{
privatestring description; publicstring Description
{
get { return description; }
set { description = value; }
} public MyOjbect(MyDependentClass myDependent)
{
this.Description = myDependent.Description;
}
}
////注入依赖
MyOjbect objlist = container.Resolve<MyOjbect>();
- 当然除了具体类型我们还可以使用接口或者基类类型作为参数注入依赖,这里我们定义一个接口和一个抽象类。
//// MyServiceBase是一个抽象类,然后objIMyService继承于该抽象类
//// IMyService是一个接口,objMyService实现该接口
publicclass MyOjbect
{
privatestring description; publicstring Description
{
get { return description; }
set { description = value; }
} public MyOjbect(MyServiceBase objIMyService, IMyService objMyService)
{
////TODO:
}
}
////注册抽象类和接口的映射关系
container.RegisterType<IMyService, MyServiceDependent>();
container.RegisterType<MyServiceBase, DataService>(); MyOjbect objlist = container.Resolve<MyOjbect>();
2) 多重载构造函数通过属性指定注入构造函数
通过InjectionConstructor属性指定要注入构造函数,和单构造函数功能一样,但要注意一点是当有多重载构造函数,如果我们没有使用属性指定注入构造函数,Unity会根据构造函数参数最多的进行依赖注入,如果不存在唯一最多参数的构造函数(例如:有两个或者两个以上构造函数具有最多参数时候),Unity会抛出异常。
publicclass MyOjbect
{
privatestring description; publicstring Description
{
get { return description; }
set { description = value; }
} public MyOjbect(MyServiceBase objIMyService)
{
////
} [InjectionConstructor]
public MyOjbect(MyServiceBase objIMyService, IMyService objMyService)
{
////
}
}
通过前面的介绍我们初步明白了Unity的作用就是给我们一个更方便实现类与类的解耦,假设在一般情况一个类依赖于其他类的时候,我们必须实例化该依赖类,然后把实例传递给我们要调用类,但有了Unity它帮我们实例了这些。OK接下来讲一个具体例子。
///<summary>
/// 父母类
///</summary>
publicclass Parent
{
privatereadonly ChildA _classA;
privatereadonly ChildB _classB; public Parent() { } //指定依赖注入构造函数
[InjectionConstructor]
public Parent(ChildA chA, ChildB chB)
{
this._classA = chA;
this._classB = chB;
} publicoverridestring ToString()
{
// 年长的父母依赖与孩子。
returnstring.Format("The elder depend on {0} and {1}.", this._classA.ToString(), this._classB.ToString());
}
}
///<summary>
/// 孩子类
///</summary>
publicclass ChildA : Parent
{
publicoverridestring ToString()
{
return"ChildA";
}
} ///<summary>
/// 孩子类
///</summary>
publicclass ChildB : Parent
{
publicoverridestring ToString()
{
return"ChildB";
}
} class Program
{
staticvoid Main(string[] args)
{
using (IUnityContainer container =new UnityContainer())
{
Parent objParent = container.Resolve<Parent>(); Console.WriteLine(objParent.ToString()); Console.ReadKey();
}
}
}
接下通过一个简单的配置文件实例例子进一步说明,Unity是如何实现类与类之间的解耦的。
首先我们先定义一个Foo类,它依赖于一个接口ILogger,它有两个实现分别是LoggerA和LoggerB,然后我们的Foo类要调用LoggerA。在一般情况下我们可以实例化一个LoggerA的实例,然后传递给Foo就OK了,这就是hard code给我们带来了一个紧的耦合,如果要我们修改成调用LoggerB,那么我们可以再实例化一个LoggerB对象,眼前看来是可以这样实现,但如果我们工程很大,这种做法是十分危险,当我们使用配置文件可以简单实现,来讲讲简单实现。
staticvoid Main(string[] args)
{
using (IUnityContainer container =new UnityContainer())
{
////Parent objParent = container.Resolve<Parent>(); ////Console.WriteLine(objParent.ToString()); ////Console.ReadKey(); //获取指定名称的配置节
UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity"); //获取container名称为CfgClass下的配置
section.Containers["CfgClass"].Configure(container); Foo myFoo = container.Resolve<Foo>(); Console.WriteLine(myFoo.ToString()); Console.ReadKey(); }
}
App.config中的配置如下:
<configuration>
<configSections>
<!-- 每次都必须定义的开头 -->
<section name ="unity" type ="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,
Microsoft.Practices.Unity.Configuration"/>
</configSections> <!-- 使用unity的xsd -->
<!--<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">-->
<unity>
<!-- 声明一种是用类型 -->
<typeAliases>
<typeAlias alias ="ILogger" type ="MSEnterpriseUnitity.ILogger, MSEnterpriseUnitity"/>
</typeAliases>
<containers>
<container name="CfgClass">
<!-- 设定该类型的映射关系 -->
<types>
<type type ="ILogger" mapTo="MSEnterpriseUnitity.LoggerA, MSEnterpriseUnitity"/>
</types>
</container>
</containers>
</unity>
</configuration>
二、方法注入
当一个类的方法依赖于其他类的时候(例如构造函数参数依赖与其他类),在一般情况下通过实例化该被依赖类对象,然后将参数传递给我们依赖类的方法,如果使用方法注入可以避免实例化被依赖类对象,这里就仅仅需要在依赖方法中设置一个属性InjectionMethod就OK了。
2.1方法依赖于具体类
首先我们定义两个类MyTargetOjbect和OtherObject,然后定义在MyTargetOjbect中定义一个方法Initialize(OtherObject dep),该方法的参数依赖于OtherObject类。
///<summary>
/// 依赖类包含一个Description和OutPut方法。
///</summary>
publicclass OtherObject
{
privatestring _description; publicstring Description
{
get { return _description; }
set { _description = value; }
} publicvoid OutPut()
{
Console.WriteLine(this.Description);
}
}
///<summary>
/// 目标类的方法Initialize参数依赖于OtherObject类。
///</summary>
publicclass MyTargetOjbect
{
public OtherObject dependentObject;
[InjectionMethod]
publicvoid Initialize(OtherObject dep)
{
this.dependentObject = dep;
}
}
using (IUnityContainer container =new UnityContainer())
{
MyTargetOjbect myTargetObject = container.Resolve<MyTargetOjbect>(); myTargetObject.dependentObject.Description ="Injection successful.";
myTargetObject.dependentObject.OutPut();
}
2.2 方法依赖于接口或者基类
定义一个抽象类MyBaseClass,然后MyInheritBase继承该抽象类,定义一个接口IMyInterface然后ImplementInterface实现该接口。
///<summary>
/// 接口包含一个属性和一个方法
///</summary>
publicinterface IMyInterface
{
string Description
{
get;
set;
} void OutPut();
}
///<summary>
/// 实现IMyInterface的属性和方法
///</summary>
publicclass ImplementInterface : IMyInterface
{
privatestring _description; #region IMyInterface 成员 publicstring Description
{
get
{
return _description;
}
set
{
_description = value;
}
} publicvoid OutPut()
{
Console.WriteLine(this.Description);
} #endregion
}
///<summary>
/// 一个抽象类包含一个属性和一个方法
///</summary>
publicabstractclass MyBaseClass
{
privatestring _description; publicvirtualstring Description
{
get { return _description; }
set { _description = value; }
}
publicabstractvoid OutPut();
}
///<summary>
/// 实现抽象类的抽象方法
///</summary>
publicclass MyInheritBase : MyBaseClass
{
publicoverridevoid OutPut()
{
Console.WriteLine(this.Description);
}
}
///<summary>
/// 目标类的方法Initialize参数依赖于OtherObject类。
///</summary>
publicclass MyTargetOjbect
{
public IMyInterface myInterface;
public MyBaseClass myBase;
[InjectionMethod]
publicvoid Initialize(IMyInterface myInterface, MyBaseClass myBase)
{
this.myInterface = myInterface;
this.myBase = myBase;
}
}
////设置抽象类和接口的映射关系
container.RegisterType<MyBaseClass, MyInheritBase>();
container.RegisterType<IMyInterface, ImplementInterface>(); MyTargetOjbect myTargetObject = container.Resolve<MyTargetOjbect>(); myTargetObject.myInterface.Description ="Injection Successful."; myTargetObject.myInterface.OutPut(); myTargetObject.myBase.Description ="Injection Successful."; myTargetObject.myBase.OutPut();
三、属性注入
当一个类的属性依赖于其他类,一般情况初始化该属性需要实例化该类型对象,然而我们可以使用Dependency属性,指定属性注入无限手动实例化类型对象。
3.1 具体类型属性
publicclass MyObject
{
private SomeOtherObject _dependentObject; [Dependency]
public SomeOtherObject DependentObject
{
get { return _dependentObject; }
set { _dependentObject = value; }
}
} IUnityContainer uContainer =new UnityContainer();
MyObject myInstance = uContainer.Resolve<MyObject>(); // now access the property containing the dependency
SomeOtherObject depObj = myInstance.DependentObject;
3.2抽象类或接口属性
publicclass MyObject
{ private IMyInterface _interfaceObj;
private MyBaseClass _baseObj; [Dependency]
public IMyInterface InterfaceObject
{
get { return _interfaceObj; }
set { _interfaceObj = value; }
} [Dependency]
public MyBaseClass BaseObject
{
get { return _baseObj; }
set { _baseObj = value; }
} } IUnityContainer uContainer =new UnityContainer()
.RegisterType<IMyInterface, FirstObject>()
.RegisterType<MyBaseClass, SecondObject>();
MyObject myInstance = uContainer.Resolve<MyObject>(); // now access the properties containing the dependencies
IMyInterface depObjA = myInstance.InterfaceObject;
MyBaseClass depObjB = myInstance.BaseObject;
3.3 给属性注入命名
给属性命名只需在Dependency(“name”)定义一个名字就OK了。
publicclass MyTargetOjbect
{
public IMyInterface myInterface;
public MyBaseClass myBase; private IMyInterface _MyProperty1, _MyProperty2; //命名属性注入
[Dependency("Property2")]
public IMyInterface MyProperty2
{
get { return _MyProperty2; }
set { _MyProperty2 = value; }
} //命名属性注入
[Dependency("Property1")]
public IMyInterface MyProperty1
{
get { return _MyProperty1; }
set { _MyProperty1 = value; }
}
}
//调用Property1属性注入
container.RegisterType<IMyInterface, ImplementInterface>("Property1");
//调用Property2属性注入
container.RegisterType<IMyInterface, ImplementInterface2>("Property2"); MyTargetOjbect myTargetObject = container.Resolve<MyTargetOjbect>(); IMyInterface myProperty1 = myTargetObject.MyProperty1;
IMyInterface myProperty2 = myTargetObject.MyProperty2;
3.4 构造函数参数的属性注入
构造函数参数依赖于其他类时候,我们可以考虑使用构造函数注入或者属性注入
publicclass Foo
{
private ILogger _iLogger; public Foo([Dependency] ILogger iLogger)
{
this._iLogger = iLogger;
} publicoverridestring ToString()
{
returnstring.Format("Foo depends on {0}.", this._iLogger.ToString());
}
}
[出处]: http://www.cnblogs.com/rush/
微软企业库Unity学习笔记的更多相关文章
- 微软企业库Unity依赖注入
Unity Application Block 1.0系列(4): 方法调用注入(Method Call Injection ) http://www.cnblogs.com/inrie/archiv ...
- [EntLib]微软企业库5.0 学习之路——第一步、基本入门
话说在大学的时候帮老师做项目的时候就已经接触过企业库了但是当初一直没明白为什么要用这个,只觉得好麻烦啊,竟然有那么多的乱七八糟的配置(原来我不知道有配置工具可以进行配置,请原谅我的小白). 直到去年在 ...
- 使用微软企业库5.0提供的unity配置解藕系统demo(源码)
最近公司集50多号开发人员的人力围绕一个系统做开发,框架是免不了要统一的,公司提供的架构,利于分工合作,便于维护,扩展,升级,其中使用了到微软的企业库来解藕系统,只是因为框架封装,于是在网上学习了一个 ...
- 微软企业库5.0 学习之路——第八步、使用Configuration Setting模块等多种方式分类管理企业库配置信息
在介绍完企业库几个常用模块后,我今天要对企业库的配置文件进行处理,缘由是我打开web.config想进行一些配置的时候发现web.config已经变的异常的臃肿(大量的企业库配置信息充斥其中),所以决 ...
- 微软企业库5.0 学习之路——第七步、Cryptographer加密模块简单分析、自定义加密接口及使用—下篇
在上一篇文章中, 我介绍了企业库Cryptographer模块的一些重要类,同时介绍了企业库Cryptographer模块为我们提供的扩展接口,今天我就要根据这些 接口来进行扩展开发,实现2个加密解密 ...
- 微软企业库5.0 学习之路——第六步、使用Validation模块进行服务器端数据验证
前端时间花了1个多星期的时间写了使用jQuery.Validate进行客户端验证,但是那仅仅是客户端的验证,在开发项目的过程中,客户端的信息永远是不可信的,所以我们还需要在服务器端进行服务器端的验证已 ...
- 微软企业库5.0 学习之路——第五步、介绍EntLib.Validation模块信息、验证器的实现层级及内置的各种验证器的使用方法——下篇
一.独立验证器 我上篇中我将AndCompositeValidator和OrCompositeValidator归为独立验证器,这2个验证器主要是为了第一类验证服务,可以进行多种验证组合在一起进行复杂 ...
- 微软企业库5.0 学习之路——第四步、使用缓存提高网站的性能(EntLib Caching)
首先先补习下企业库的Caching Application Block的相关知识: 1.四大缓存方式,在Caching Application Block中,主要提供以下四种保存缓存数据的途径,分别是 ...
- 微软企业库5.0 学习之路——第二步、使用VS2010+Data Access模块建立多数据库项目
现在我就开始进入学习之路的第二步——Data Access模块,这个模块是企业库中被使用频率最高的模块,它很好的封装了数据库操作应用,为我们进行多数据库系统开发提供了便利,只需更改配置文件就 可以很快 ...
随机推荐
- Asp.net Vnext TagHelpers
概述 本文已经同步到<Asp.net Vnext 系列教程 >中] TagHelpers 是vnext中引入的新功能之一.TagHelper 的作用是类似于发挥在以前版本的 ASP.NET ...
- 【58沈剑架构系列】mysql并行复制优化思路
一.缘起 mysql主从复制,读写分离是互联网用的非常多的mysql架构,主从复制最令人诟病的地方就是,在数据量较大并发量较大的场景下,主从延时会比较严重. 为什么mysql主从延时这么大? 回答:从 ...
- PHP session 写入数据库中的方法
首先解释下为什么要把session 写到数据库中呢,session 一般默认是以文件的形式放在php.ini 配置的目录中的, 如果你的网站实现了多台服务器负载均衡,这样用户访问你的网站,可能进入的服 ...
- MVC图片上传并显示缩略图
前面已经说了怎么通过MVC来上传文件,那么这次就说说如何上传图片然后显示缩略图,这个的实用性还是比较大.用UpLoad文件夹来保存上传的图片,而Temp文件夹来保存缩略图,前面文件上传部分就不再重复了 ...
- SPOJ - SUBLEX 后缀自动机
SPOJ - SUBLEX 思路:求第k大字串,求出sam上每个节点开始能识别多少字串,然后从起点开始跑就好啦. #include<bits/stdc++.h> #define LL lo ...
- 自定义Counter使用
自定义计数器的使用(记录敏感单词) package counter; import java.net.URI; import org.apache.hadoop.conf.Configuration; ...
- Bad connection to FS. command aborted. exception: Call to chaoren/192.168.80.100:9000 failed on connection exception: java.net.ConnectException: Connection refused
Bad connection to FS. command aborted. exception: Call to chaoren/192.168.80.100:9000 failed on conn ...
- Java学习笔记之:Spring MVC 环境搭建
一.创建项目 1.新建java动态项目 2.在web-inf/lib文件夹下导入jar 3.创建所需要的包和文件 二.搭建SpringMVC 1.配置web.xml(WEB-INF下) <?xm ...
- 【定时任务】Timer
Java原生api Timer类就可以实现简单的定时任务.下面将简单介绍一下Timer. 一.使用 Timer 实现定时任务 具体代码如下. 可以看到我们主要是分三步进行的 1.new Timer() ...
- Sass 和 SCSS 有什么区别?
Sass 官网上是这样描述 Sass 的: Sass 是一门高于 CSS 的元语言,它能用来清晰地.结构化地描述文件样式,有着比普通 CSS 更加强大的功能. Sass 能够提供更简洁.更优雅的语法, ...