前面幾個章節介紹了Unity的基本使用,主要分爲程序和配置文件兩種方法的使用,能夠參考一下連接,html
本節做爲結束篇,將介紹一下在項目中如何應用Unity。 編程
Unity應用普遍,在不少開源項目中均可以找到Unity的身影。就拿微軟的開源項目新聞發佈系統 Kigg 舉例,Kigg的依賴注入就是使用到了Unity,你們能夠下載。Kigg是MVC應用的一個推薦範例,本節介紹一下其中的依賴注入IoC容器,該容器在Kigg.Core項目,Infrastructure目錄下的IOC目錄,該目錄下有4個類,以下圖架構
先看看 IDependencyResolver 接口聲明app
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的實現函數
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性能
public interface IDependencyResolverFactory { /// <summary> /// 建立IDependencyResolver的實例 /// </summary> /// <returns></returns> IDependencyResolver CreateInstance(); }
看到定義,只有一個方法CreateInstance,就是用來建立IDependencyResolver對象,咱們能夠實現該工廠,能夠直接new UnityDependencyResolver來建立,Kigg中利用配置文件方式,看DependencyResolverFactory的聲明以下:ui
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類的聲明
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類以下:
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文件中找到,聲明以下
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的依賴容器就介紹完畢了。
咱們使用時若是想要IoC容器容易擴展容易使用能夠參照Kigg。
IUnityContainer容器能夠聲明N個對象,那樣就很差管理了,咱們應該只要一個,即建立一次,可使用static靜態成員。
不用擔憂一個IUnityContainer容器中註冊了太多對象關係而影響解析性能,IUnityContainer中是維護着許多字典,就是說註冊100個跟註冊100W個映射是同樣的。
IUnityContainer能夠經過編程映射和配置文件映射,推薦配置文件映射。