代码改变世界

微软企业库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;
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;
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;
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 class SupplierData
    {
        
public string Name { getset; }
    }
    
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 容器使用顺序图

  

  未完待续。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。