微软企业库4.1学习笔记(四十一)依赖注入模块Unity 简介
2010-05-07 13:41 Virus-BeautyCode 阅读(3218) 评论(1) 编辑 收藏 举报模块Unity是一个轻量的、可扩展的依赖注入容器,支持构造函数注入、属性注入、方法调用注入。你可以用它创建企业库对象,也可以创建自定义的业务对象。Unity和企业库中的其他模块有一些不同点:
- 你可以独立的使用Unity模块来实现依赖注入技术,不需要其他模块的辅助。
- Unity支持用配置文件来准备容器,也支持在运行的时候用代码动态注册依赖关系。
- Unity和企业库的核心库没有依赖关系。它包含了内置的配置信息读取方法,如果需要的话,这些配置信息也可以从企业库的配置中读取。
本节包含下面的内容
- 简介
- 在应用中使用Unity
- 典型的解决方案
- 设计Unity的目的
- 扩展和修改Unity模块
- 部署和实施
- 示例代码
1 简介
模块Unity是一个轻量的、可扩展的依赖注入容器,支持构造函数注入、属性注入、方法调用注入。它为开发者提供了下面的好处:
- 支持简单的创建对象,尤其是对于有继承关系和依赖关系的对象,简化了应用在这方面的代码。
- 支持抽象的需求,允许开发者在配置中或者是在运行的时候指定依赖关系。
- 通过拖延组建配置到容器中,增加了灵活性。
- 具有服务定位的能力。允许客户端存储或者是缓存容器。这尤其在ASP.NET应用中有用,开发者可以将容器持久到Session或者是Application中。
包含下面的一些话题,通过这些话题,你可以看看Unity模块是否适合于你。
- 常用的解决方案
- 示例代码
- Unity模块的亮点
- 什么时候该用Unity模块
1.1 常用解决方案
Unity模块解决了一些开发者在基于组建开发的过程中遇到的问题。现代的商业应用,为了满足特殊的需求,都包含有自定义的业务对象和自定义的组件。组件还可能独立的实现横跨日志、验证、授权、缓存和异常处理的需求。
成功构建这种类型应用的关键是完成一个解耦的、松散耦合的设计。松散耦合的应用更灵活、更容易维护。而且在开发的过程中更容易测试。你可以在测试的过程中伪造一些具有强依赖的对象,来辅助测试。例如:数据库连接、网络连接、ERP连接、富UI组件。
依赖注入是构建松散耦合应用的首选技术。它提供了处理对象之间的依赖关系的方法。例如:一个处理客户信息的对象,可能会依赖于数据访问对象,验证信息的对象,检查用户是否被授权用户。依赖注入技术可以保证客户类被正确的初始化,并且加载上面所需的对象,尤其是当依赖于抽象的时候。
下面的模式都是用来架构和简化这个开发过程的;
- Inversion of Control (IOC)pattern:反转控制模式,这个模式支持插件式的架构,对象可以在需要的时候,查询它所需的其他对象。
- Dependency Injection(DI) pattern:依赖注入模式,这个模式是IOC的一种特殊应用,是一种不改变类接口的前提下修改类行为的接口编程技术。开发者面向接口编程,使用容器在类中注入依赖对象的实例。注入对象的实例的技术是接口注入、构造函数注入、属性注入setter和方法调用注入。
- Interception pattern:拦截模式,这个模式引入了另一个层次的间接性。在客户端和真实对象之间建立一个对象,一个代理在客户端和真是对象之间。客户端操作真实对象的行为,被代理拦截,通过代理来完成他们之间的交互。
Unity模块的使用步骤:
- 建立Unity容器
- 获取指定类型的对象
- 获取指定类型和注册名称的对象
- 获取一个特殊类型的所有对象
- 使用BuildUp创建一个容器没有创建的对象
- 注释对象为构造函数注入
- 注释对象为属性注入
- 注释对象为方法调用注入
1.2 示例代码
使用依赖注入框架和反转控制技术,开发者可以创建程序集中的自定义类的实例和依赖对象的实例。Unity支持这个功能,使得开发者可以容器配置注入、构造函数注入、属性注入、方法调用注入技术创建对象和依赖对象的实例。
Unity提供了两个方法了来注册类型和映射他们的关系:
- RegisterType。这个方法在容器中注册一个类型,在适当的时候容器创建一个指定类型的实例。发生在通过类attribute初始化依赖注入和调用Resolve方法的时候。对象的声明周期可以在RegisterType方法中指定,如果没有指定,生命周期将是短暂的,意味着每次调用Resolve都会创建一个新的实例。
容器配置注册类型
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.Practices.Unity;
namespace BeautyCode.Web.Unity
{
public interface IMyService
{ }
public class CustomService : IMyService
{ }
public class UnityDemo
{
public UnityDemo()
{
IUnityContainer ucontainer = new UnityContainer();
ucontainer.RegisterType<IMyService, CustomService>();
IMyService myService = ucontainer.Resolve<IMyService>();
}
}
}
- RgisterInstance。这个方法用来注册一个已经存在的对象实例,同时指定生命周期。容器在生命周期之内返回这个已经存在的对象。如果没有指定生命周期,生命周期将由容器来管理。
容器配置注册一个已经存在的对象实例
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.Practices.Unity;
namespace BeautyCode.Web.Unity
{
public interface IMyService
{ }
public class LogService : IMyService
{ }
public class UnityDemo
{
public void UnityDemo1()
{
IUnityContainer uContainer = new UnityContainer();
LogService myExistingObject = new LogService();
uContainer.RegisterInstance<IMyService>(myExistingObject);
IMyService myServiceInstance = uContainer.Resolve<IMyService>();
}
}
}
构造函数注入
如果开发者使用Unity容器的Resolve方法实例化的一个类,这个类包含一个构造函数,构造函数对另外的一个对象有依赖。Unity容器会自动创建构造函数以来的对象。
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.Practices.Unity;
namespace BeautyCode.Web.Unity
{
public interface IMyService
{ }
public class CustomService : IMyService
{
public CustomService(LogService log)
{
log.WriteLog("loginfo");
}
}
public class LogService : IMyService
{
public void WriteLog(string logMsg)
{ }
}
public class UnityDemo
{
public UnityDemo()
{
IUnityContainer ucontainer = new UnityContainer();
ucontainer.RegisterType<IMyService, CustomService>();
ucontainer.RegisterType<IMyService, LogService>();
CustomService myService = ucontainer.Resolve<CustomService >();
}
}
}
在运行的时候,开发者通过Resolve方法创建了一个CustomService类的实例,导致容器自动创建一个LogService对象,对象的范围是CustomService范围内。
属性注入
除了使用构造函数注入,Unity还支持属性注入和方法调用注入。下面的代码演示了属性注入。
{
public string Name { get; set; }
}
public class ProductService
{
private SupplierData _supplier;
[Dependency]
public SupplierData Supplier
{
get { return _supplier; }
set { _supplier = value; }
}
}
这时候创建一个ProductService类的实例,会自动创建一个SupplierData实例,作为ProductService实例的属性SupplierData的值。
1.3 设计亮点
Unity模块具有下面的功能:
- 提供了一个创建对象的方法,也可能包括依赖的其他对象。
- 提供了RegisterType方法,可以在容器中注册类型和映射关系,用Resolve方法可以返回对象的实例。
- 通过提供的预先配置注入对象,实现了反转控制。你可以在构造函数中指定一个接口或者是类,你也可以在属性或者是方法上添加attribute实现注入。
- 支持容器的继承。一个容器可以包含子容器,对象可以从子容器传递到父容器。
- 可以从标准的配置系统中读取配置信息,例如xml文件,用它来配置容器。
- 对类的定义没有要求。在类上不用使用attribute(除非你使用属性注入和方法调用注入),在类声明中也没有要求。
- 支持对容器的扩展,你可以实现自己的容器,支持额外的对象构造,和其他的容器功能,例如缓存等。
1.4什么时候选用Unity模块
依赖注入提供了简化代码、抽象对象之间的依赖、自动创建依赖对象的实例等机会。但是,过程还是会对性能有一点影响,在简化依赖的基础上还是增加了一点复杂性。
通常情况下,你可以在下面的情形中使用Unity模块:
- 你的对象和类对于其他对象和类有依赖关系。
- 你的依赖关系复杂,需要抽象。
- 你想要使用构造函数注入、属性注入和方法调用注入技术。
- 你想要管理对象的生命周期。
- 你想要在代码运行的时候配置和管理对象之间的依赖关系。
- 你想要在Web应用中缓存和持久化依赖关系。
在下面的情况,就不需要使用Unity模块了:
- 你的对象和类对其他对象和类没有依赖。
- 你的依赖关系简单,不需要抽象。
Unity 容器使用顺序图
未完待续。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。