1.引言 

前面几个章节介绍了Unity的基本使用,主要分为程序和配置文件两种方法的使用,可以参考一下链接,

  • [IoC容器Unity]第一回:Unity预览
  • [IoC容器Unity]第二回:Lifetime Managers生命周期
  • [IoC容器Unity]第三回:依赖注入

本节作为结束篇,将介绍一下在项目中如何应用Unity。   

2.范例

Unity应用广泛,在很多开源项目中都可以找到Unity的身影。就拿微软的开源项目新闻发布系统 Kigg 举例,Kigg的依赖注入就是使用到了Unity,大家可以下载。Kigg是MVC应用的一个推荐范例,本节介绍一下其中的依赖注入IoC容器,该容器在Kigg.Core项目,Infrastructure目录下的IOC目录,该目录下有4个类,如下图

先看看 IDependencyResolver 接口声明

IDependencyResolver 声明

    public interface IDependencyResolver : IDisposable{/// <summary>/// 注册 T类型实例/// </summary>/// <typeparam name="T"></typeparam>/// <param name="instance"></param>void Register<T>(T instance);/// <summary>/// 注入 /// </summary>/// <typeparam name="T"></typeparam>/// <param name="existing"></param>void Inject<T>(T existing);/// <summary>/// 解析/// </summary>/// <typeparam name="T"></typeparam>/// <param name="type"></param>/// <returns></returns>T Resolve<T>(Type type);T Resolve<T>(Type type, string name);T Resolve<T>();T Resolve<T>(string name);IEnumerable<T> ResolveAll<T>();}

看到该接口定义,我们很快会想到Unity中的IUnityContainer容器接口,对的,里面的方法和作用 跟IUnityContainer接口类似。
那为什么不直接使用IUnityContainer而要定义一个类似的接口IDependencyResolver呢? 
可以看到Kigg的IDependencyResolver是定义在核心层Kigg.Core相当于基础架构层中,而这个层是一个核心库,其它层都会引用它,Kigg应用了一种像 适配器模式来进行封装。
就是系统中要应用其它的外部接口,比如Unity 和Sping.net的依赖注入的方法不统一,我们要进行封装,可以先定义一个公共接口,再利用Unity和其它组件来实现它,这就是IDependencyResolver的由来。

Kigg中已经利用Unity来实现IDependencyResolver接口,当然我们也可以用其他的依赖注入容器来实现它,下面看看UnityDependencyResolver的实现

UnityDependencyResolver 声明

public class UnityDependencyResolver : DisposableResource, IDependencyResolver{//注入容器private readonly IUnityContainer _container;[DebuggerStepThrough]public UnityDependencyResolver() : this(new UnityContainer()){UnityConfigurationSection configuration = (UnityConfigurationSection) ConfigurationManager.GetSection("unity");configuration.Containers.Default.Configure(_container);}[DebuggerStepThrough]public UnityDependencyResolver(IUnityContainer container){Check.Argument.IsNotNull(container, "container");_container = container;}[DebuggerStepThrough]public void Register<T>(T instance){Check.Argument.IsNotNull(instance, "instance");//注册实例
            _container.RegisterInstance(instance);}[DebuggerStepThrough]public void Inject<T>(T existing){Check.Argument.IsNotNull(existing, "existing");//注入加载
            _container.BuildUp(existing);}[DebuggerStepThrough]public T Resolve<T>(Type type){Check.Argument.IsNotNull(type, "type");//解析return (T) _container.Resolve(type);}[DebuggerStepThrough]public T Resolve<T>(Type type, string name){Check.Argument.IsNotNull(type, "type");Check.Argument.IsNotEmpty(name, "name");return (T) _container.Resolve(type, name);}[DebuggerStepThrough]public T Resolve<T>(){return _container.Resolve<T>();}[DebuggerStepThrough]public T Resolve<T>(string name){Check.Argument.IsNotEmpty(name, "name");return _container.Resolve<T>(name);}[DebuggerStepThrough]public IEnumerable<T> ResolveAll<T>(){//解析容器中所有IEnumerable<T> namedInstances = _container.ResolveAll<T>();T unnamedInstance = default(T);try{unnamedInstance = _container.Resolve<T>();}catch (ResolutionFailedException){//When default instance is missing
            }if (Equals(unnamedInstance, default(T))){return namedInstances;}return new ReadOnlyCollection<T>(new List<T>(namedInstances) { unnamedInstance });}[DebuggerStepThrough]protected override void Dispose(bool disposing){if (disposing){_container.Dispose();}base.Dispose(disposing);}}

可以看到UnityDependencyResolver的默认构造函数是加载配置文件(配置文件在Web.Config中)来初始化IUnityContainer,你也可以用编程的方式。
实现方式中没有继承IUnityContainer或者UnityContainer,而是和IUnityContainer是组合关系,这样更加的灵活,这是对象的Adapter模式,就是组合模式。如果有其它的IoC容器,如Windsor/StructureMap/Spring.Net等等,可以实现IDependencyResolver接口即可。

使用时,只需要实例化对应的IDependencyResolver对象就可以了,Kigg中为了更好的控制IDependencyResolver对象的创建,利用了工厂方法来创建。
先看看工厂接口IDependencyResolverFactory

IDependencyResolverFactory定义

    public interface IDependencyResolverFactory{/// <summary>/// 创建IDependencyResolver的实例/// </summary>/// <returns></returns>
        IDependencyResolver CreateInstance();}

看到定义,只有一个方法CreateInstance,就是用来创建IDependencyResolver对象,我们可以实现该工厂,可以直接new UnityDependencyResolver来创建,Kigg中利用配置文件方式,看DependencyResolverFactory的声明如下:

DependencyResolverFactory 定义

    public class DependencyResolverFactory : IDependencyResolverFactory{private readonly Type _resolverType;public DependencyResolverFactory(string resolverTypeName){Check.Argument.IsNotEmpty(resolverTypeName, "resolverTypeName");//GetType(名字,是否区分大小,是否异常)_resolverType = Type.GetType(resolverTypeName, true, true);}public DependencyResolverFactory() : this(new ConfigurationManagerWrapper().AppSettings["dependencyResolverTypeName"]){}public IDependencyResolver CreateInstance(){//根据类型创建实例对象return Activator.CreateInstance(_resolverType) as IDependencyResolver;}}

可以看到默认构造函数是读取配置文件dependencyResolverTypeName节点,利用反射Activator.CreateInstance进行创建,看看dependencyResolverTypeName节点定义,在Kigg.Web项目的配置文件中,如下:

    <appSettings><clear/><add key="dependencyResolverTypeName" value="Kigg.Infrastructure.EnterpriseLibrary.UnityDependencyResolver, Kigg.Infrastructure.EnterpriseLibrary"/></appSettings>

还有其它IoC容器实现时,只要更改配置文件就行。

使用时可以调用工厂方法进行创建IDependencyResolver对象,每次使用时都得利用工厂来创建,IDependencyResolver里面的方法肯定都是实例方法,使用也不方便,Kigg为我们进行封装成静态方法,看IoC类的声明

IoC 定义

 public static class IoC{//解析器private static IDependencyResolver _resolver;/// <summary>/// 初始化,创建实例对象/// </summary>/// <param name="factory"></param>
        [DebuggerStepThrough]public static void InitializeWith(IDependencyResolverFactory factory){Check.Argument.IsNotNull(factory, "factory");_resolver = factory.CreateInstance();}/// <summary>/// 注册对象/// </summary>/// <typeparam name="T"></typeparam>/// <param name="instance"></param>
        [DebuggerStepThrough]public static void Register<T>(T instance){Check.Argument.IsNotNull(instance, "instance");_resolver.Register(instance);}/// <summary>/// 注入对象/// </summary>/// <typeparam name="T"></typeparam>/// <param name="existing"></param>
        [DebuggerStepThrough]public static void Inject<T>(T existing){Check.Argument.IsNotNull(existing, "existing");_resolver.Inject(existing);}/// <summary>/// 解析对象/// </summary>/// <typeparam name="T"></typeparam>/// <param name="type"></param>/// <returns></returns>
        [DebuggerStepThrough]public static T Resolve<T>(Type type){Check.Argument.IsNotNull(type, "type");return _resolver.Resolve<T>(type);}/// <summary>/// 解析对象/// </summary>/// <typeparam name="T"></typeparam>/// <param name="type"></param>/// <param name="name"></param>/// <returns></returns>
        [DebuggerStepThrough]public static T Resolve<T>(Type type, string name){Check.Argument.IsNotNull(type, "type");Check.Argument.IsNotEmpty(name, "name");return _resolver.Resolve<T>(type, name);}/// <summary>/// 解析对象/// </summary>/// <typeparam name="T"></typeparam>/// <returns></returns>
        [DebuggerStepThrough]public static T Resolve<T>(){return _resolver.Resolve<T>();}/// <summary>/// 解析对象/// </summary>/// <typeparam name="T"></typeparam>/// <param name="name"></param>/// <returns></returns>
        [DebuggerStepThrough]public static T Resolve<T>(string name){Check.Argument.IsNotEmpty(name, "name");return _resolver.Resolve<T>(name);}/// <summary>/// 解析对象/// </summary>/// <typeparam name="T"></typeparam>/// <returns></returns>
        [DebuggerStepThrough]public static IEnumerable<T> ResolveAll<T>(){return _resolver.ResolveAll<T>();}/// <summary>/// 销毁/// </summary>
        [DebuggerStepThrough]public static void Reset(){if (_resolver != null){_resolver.Dispose();}}}

IDependencyResolver是IoC的一个私有静态成员,私有的,那怎么创建对象,IoC类有一个InitializeWith(IDependencyResolverFactory factory),利用工厂方法来创建,以后我们只要使用IoC这个类就行。IoC静态类并没有在静态构造函数中初始化IDependencyResolver,考虑到依赖,只依赖比较稳定的接口,而不会依赖具体的实现如DependencyResolverFactory,这样就可以提供方法供外面访问来进行创建IDependencyResolver对象。

那IDependencyResolver什么时候会创建,由于没有在构造函数中实现创建,必定要调用IoC的InitializeWith方法,我们可以找到引用,看到一个启动引导Bootstrapper类如下:

Bootstrapper定义

    public static class Bootstrapper{static Bootstrapper(){try{IoC.InitializeWith(new DependencyResolverFactory()); }catch (ArgumentException){// Config file is Missing
            }}public static void Run(){IoC.ResolveAll<IBootstrapperTask>().ForEach(t => t.Execute());}}

在Bootstrapper的构造函数中进行了IDependencyResolver的创建,即在第一次使用Bootstrapper时会创建,那肯定的是Bootstrapper一定要在IoC之前使用啊,不然在使用IoC类时肯定报错,不用担心,Bootstrapper使用的很早,因为它是一个引导启动类,查找引用,可以看到在Kigg.Web下的Global.asax文件中找到,声明如下

GlobalApplication 定义

    public class GlobalApplication : HttpApplication{public static void OnStart(){Bootstrapper.Run();Log.Info("Application Started");}public static void OnEnd(){Log.Warning("Application Ended");IoC.Reset();}protected void Application_Start(){OnStart();}protected void Application_End(){OnEnd();}}

原来在Application_Start中,程序启动时就使用到了,好了,以后就直接使用Ioc来创建依赖对象吧,不用new了,Unity的配置文件都是在Web.Config中,就不介绍了,Kigg的依赖容器就介绍完毕了。

3.小结

我们使用时如果想要IoC容器容易扩展容易使用可以参照Kigg。

IUnityContainer容器可以声明N个对象,那样就不好管理了,我们应该只要一个,即创建一次,可以使用static静态成员。

不用担心一个IUnityContainer容器中注册了太多对象关系而影响解析性能,IUnityContainer中是维护着许多字典,就是说注册100个跟注册100W个映射是一样的。

IUnityContainer可以通过编程映射和配置文件映射,推荐配置文件映射。

转载于:https://www.cnblogs.com/qqlin/archive/2012/10/18/2720830.html

[IoC容器Unity]第四回:使用范例相关推荐

  1. [IoC容器Unity]第三回:依赖注入

    上节介绍了,Unity的Lifetime Managers生命周期,Unity具体实现依赖注入包含构造函数注入.属性注入.方法注入,所谓注入相当赋值,下面一个一个来介绍. 2.构造函数注入 Unity ...

  2. [IoC容器Unity]第一回:Unity预览

    出处:http://www.cnblogs.com/qqlin/archive/2012/10/16/2717964.html 请看原文,三篇文章. 转载于:https://blog.51cto.co ...

  3. Spring中IOC容器

    IOC入门案例思路分析 1.管理什么(Service和Dao) 2.如何将管理的对象存放到IOC容器(配置applicationContext.xml)第二步 3.将管理的对象存放到IOC容器,如何获 ...

  4. SpringBoot启动流程分析(四):IoC容器的初始化过程

    SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一) ...

  5. 回客科技 面试的 实现ioc 容器用到的技术,简述BeanFactory的实现原理,大搜车面试的 spring 怎么实现的依赖注入(DI)...

    前言:这几天的面试,感觉自己对spring 的整个掌握还是很薄弱.所以需要继续加强. 这里说明一下spring的这几个面试题,但是实际的感觉还是不对的,这种问题我认为需要真正读了spring的源码后说 ...

  6. Unity实现IOC容器

    测试代码链接 控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度.其中最常见的方式叫做依赖注入(Dependency ...

  7. IOC容器特性注入第四篇:容器初始化

    IOC容器,就是把各种服务都注入到容器里,想要什么就去拿什么,不仅解决服务类和接口类的耦合度还可以提高性能方便管理. 这里封装一个接口类和一个实现类 1.IContainerManager接口 pub ...

  8. 大白话聊框架设计(入门篇) | 第四章:简单实现IOC容器

    文章目录 **1.简单实现IOC容器** **2.简单介绍IOC容器** **3.创建Inject注解** **4.创建IocContrainer** **5.初始化IOC容器** **6.改造原有N ...

  9. [Spring 深度解析]第7章 IoC容器的初始化过程

    7. IoC容器的初始化过程 ​ 简单来说,IoC容器的初始化是由前面介绍的refresh()方法来启动的,这个方法标志着IoC容器的正式启动.具体来说,这个启动包括BeanDefinition的Re ...

最新文章

  1. 职场老鸟的焦虑与出路
  2. 近期数据挖掘学习_计划安排及相关资料(定期更新)
  3. 基于java的InputStream.read(byte[] b,int off,int len)算法学习!
  4. hal库开启中断关中断_「正点原子NANO STM32开发板资料连载」第十章 外部中断实验...
  5. Yii的应用主体的配置
  6. redhat server 5.3内核升极2.6.18 升级到 3.5 装systemtap 原创
  7. yarn : 无法加载文件 E:\leading\NodeJs\info\node_global\yarn.ps1,因为在此系统上禁止运行脚本
  8. python应用实例论文_浅谈Python在科学计算中的应用
  9. 监控linux内存,系统运维|用 Bash 脚本监控 Linux 上的内存使用情况
  10. 记录自定义view的基本使用
  11. ios懒人笔记应用源码
  12. JSP和Servlet传值中文乱码解决
  13. 【PyTorch教程】P30 GPU加速
  14. (二维树状数组)E - Stars
  15. Google Gson 格式化日期时间
  16. 智能驾驶是什么意思_智能驾驶当道,谁还在谈驾驶乐趣?
  17. 酷狗 KRC 文件的解析
  18. Python:抽象基类(abc模块)
  19. 安装Office OneNote 2007
  20. unity2D学习(2)Tilemap绘制地图

热门文章

  1. c语言simpson积分计算方法,数值分析复化Simpson积分公式和复化梯形积分公式计算积分的通用程序...
  2. mysql 分区_搞懂MySQL分区
  3. NodeJS 使用redis实现定时执行方法
  4. Android-room的学习
  5. python package_Python之package、module
  6. 同一个类 cannot be cast to_留学热门assignment之 税收筹划类essay
  7. ant table表格整行点击事件并获取当前行的数据
  8. hadoop无法访问50070端口怎么办?
  9. 【Project Euler】530 GCD of Divisors 莫比乌斯反演
  10. CCIE-MPLS基础篇-实验手册