[IoC容器Unity]第四回:使用范例

1.引言 

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

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

2.范例

Unity应用普遍,在不少开源项目中均可以找到Unity的身影。就拿微软的开源项目新闻发布系统 Kigg 举例,Kigg的依赖注入就是使用到了Unity,你们能够下载。Kigg是MVC应用的一个推荐范例,本节介绍一下其中的依赖注入IoC容器,该容器在Kigg.Core项目,Infrastructure目录下的IOC目录,该目录下有4个类,以下图架构

先看看 IDependencyResolver 接口声明app

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的由来。ide

 

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接口便可。post

 

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

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

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

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项目的配置文件中,以下:this

    <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能够经过编程映射和配置文件映射,推荐配置文件映射。

相关文章
相关标签/搜索