利用Attribute简化Unity框架IOC注入

简介:

      在我们的领域驱动设计(DDD)开发中,我们经常需要IOC框架使得我的框架依赖翻转,依赖抽象,避免直接new依赖于我们的具体实现。这些使得我们的框架整个项目结构不变,很方便的改变具体实现,使得项目提供可测试性,模块之间实现高内聚低耦合,减少我们的后期维护成本。IOC框架一般基于容器,在容器中存储着各个抽象和具体实现的依赖关系,当我们需要发出请求的时候,IOC框架会在当前容器中找到我们所需要的具体实现返回给我们,当然这里还有DI注入(属性,方法,构造),在我们的使用者(客户端)不需要了解具体实现,如何初始化,如何流转等具体,只需明白我们的契约接口暴露给我们的服务,IOC框架是解决抽象和具体直接的创建问题。其他资料可以参见Inversion of Control Containers and the Dependency Injection pattern

     当然Unity框架中为我们提供了RegisterInstance,RegisterType方法我们可以在代码中注册到容器,比如NLayerApp中就在IoCFactory中注册一大堆抽象-具体关联。但是在我们的实际实践中一般会选择另一种方式xml配置配置,因为这样我们会得到更大的灵活性,需求变化只要抽象接口不变,我们也只需要在xml配置文件中修改一行配置加入我们的具体实现,加入我们的程序集,就可以适应需求变化,这更满足oo设计“开闭原则”。

   在这里个人实践利用抽象(接口)定义Attribute制定具体ConfigFile(配置文件),Container(容器),Name(名称)解决IOC植入,减少我们多次去读取配置文件。Unity为我们提供了在Web.config,App.config中配置注入信息,或者注册外部配置,但是很多时候我们更希望,在我们的 不同模块下,应用不同的IOC配置信息,这些可以减少维护的关联少些,清晰,同时文件夹的出现便于我们的配置信息的管理。

Attribute实现:UnityInjectionAttribute

ExpandedBlockStart.gif
复制代码
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple =  false, Inherited =  true)] 
    public  class UnityInjectionAttribute : Attribute 
   { 

        public UnityInjectionAttribute( string Container) 
       { 
            this.Container = Container;            
       } 

        public  string Container 
       { 
            get
            set
       } 

        public  string ConfigFile 
       { 
            get
            set
       } 

        public  string Name 
       { 
            get
            set
       } 

        public Microsoft.Practices.Unity.Configuration.UnityConfigurationSection GetUnityConfigurationSection() 
       { 
            if (! string.IsNullOrEmpty( this.ConfigFile)) 
           { 
                var fileMap =  new System.Configuration.ExeConfigurationFileMap { ExeConfigFilename = System.IO.Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory,  this.ConfigFile) }; 
               System.Configuration.Configuration configuration = System.Configuration.ConfigurationManager.OpenMappedExeConfiguration(fileMap, System.Configuration.ConfigurationUserLevel.None); 
                return configuration ==  null ?  null : configuration.GetSection(Microsoft.Practices.Unity.Configuration.UnityConfigurationSection.SectionName)  as Microsoft.Practices.Unity.Configuration.UnityConfigurationSection; 
           } 
            return System.Configuration.ConfigurationManager.GetSection(Microsoft.Practices.Unity.Configuration.UnityConfigurationSection.SectionName)  as Microsoft.Practices.Unity.Configuration.UnityConfigurationSection; 
       } 
   } 
复制代码

  在这里我们GetUnityConfigurationSection根据ConfigFile获取UnityConfigurationSection ,ConfigFile为空则当前应用配置文件,不空则为路径。在这里我们为了性能,减少过多的IOC操作,读取配置文件,我们可以更具具体需要加入对配置文件UnityConfigurationSection的缓存(ConfigFile作为key,UnityConfigurationSection为value )。

   同时提供操作辅助方法:ELUnityUtility

ExpandedBlockStart.gif
复制代码
public  static  class ELUnityUtility 
   { 
        public  static T Resolve<T>()  where T :  class 
       { 
            return Resolve( typeof(T))  as T; 
       } 

        public  static  object Resolve( this Type type) 
       { 
            var attrs = type.GetCustomAttributes( typeof(Utils.UnityInjectionAttribute),  trueas Utils.UnityInjectionAttribute[]; 
            if (attrs !=  null && attrs.Length >  0
           { 
                var attr = attrs[ 0]; 
                var unitySection = attr.GetUnityConfigurationSection(); 
                if (unitySection !=  null
               { 
                    var container =  new Microsoft.Practices.Unity.UnityContainer().LoadConfiguration(unitySection,  string.IsNullOrEmpty(attr.Container) ? unitySection.Containers.Default.Name : attr.Container); 
                    var obj =  string.IsNullOrEmpty(attr.Name) ? container.Resolve(type) : container.Resolve(type, attr.Name); 
                    if (obj !=  null
                   { 
                        var piabAtttr = obj.GetType().GetCustomAttributes( typeof(ELPolicyinjectionAttribute),  falseas ELPolicyinjectionAttribute[]; 
                        if (piabAtttr.Length >  0
                       { 
                           obj = Microsoft.Practices.EnterpriseLibrary.PolicyInjection.PolicyInjection.Wrap(type, obj); 
                       } 
                        return obj; 
                   } 
               } 
           } 
            return  null
       } 

        public  static IEnumerable<T> ResolveAll<T>()  where T :  class 
       { 
            return ResolveAll( typeof(T))  as IEnumerable<T>; 
       } 

        public  static  object ResolveAll( this Type type) 
       { 
            var attrs = type.GetCustomAttributes( typeof(Utils.UnityInjectionAttribute),  trueas Utils.UnityInjectionAttribute[]; 
            if (attrs !=  null && attrs.Length >  0
           { 
                var attr = attrs[ 0]; 
                var unitySection = attr.GetUnityConfigurationSection(); 
                if (unitySection !=  null
               { 
                    var container =  new Microsoft.Practices.Unity.UnityContainer().LoadConfiguration(unitySection,  string.IsNullOrEmpty(attr.Container) ? unitySection.Containers.Default.Name : attr.Container); 
                    return container.ResolveAll(type); 
               } 
           } 
            return  null
       } 

   }
复制代码

这里我们就可以很简便的获取IOC翻转。注:这里还有根据具体实现是否具体ELPolicyinjectionAttribute来决定是否进行PIAB的AOP操作,当然我们也可以在Unity配置文件中引入节点扩展

Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, 
                    Microsoft.Practices.Unity.Interception.Configuration

(PIAB利用的是透明代理速度较慢所以一般很少使用,当然你也可以实现具体的PIAB AOP方式比如注入MSIL,但我们已经有了很多注入MSIL的AOP框架了,我不准备去造轮子),ELPolicyinjectionAttribute:

ExpandedBlockStart.gif
复制代码
[AttributeUsage(AttributeTargets.Class)] 
    public  class ELPolicyinjectionAttribute : Attribute 
   { 
        public  string Name 
       { 
            get
            set
       } 
   }
复制代码

这样:我们的客户端 就可以很简单的使用了:

ExpandedBlockStart.gif
复制代码
class Program 
   { 
        static  void Main( string[] args) 
       { 

           ELUnityUtility.Resolve<IClass2>().Show(); 
           ( typeof(IClass2).Resolve()  as IClass2).Show(); 
           Console.Read(); 
       } 
   } 

    public  interface IClass1 
   { 
        void Show(); 
   } 

   [Green.Utils.ELPolicyinjection] 
    public  class Class1 : IClass1 
   { 

        #region IClass1 成员 
       [TestCallHandler] 
        public  void Show() 
       { 
           Console.WriteLine( this.GetType()); 
       } 

        #endregion 
   } 

   [Green.Utils.UnityInjection( " First ", Name =  " class2 ", ConfigFile =  " App1.config ")] 
    public  interface IClass2 
   { 
        void Show(); 
   } 

     public  class Class2 : ConsoleApplication1.IClass2 
   { 
       [Microsoft.Practices.Unity.Dependency( " class1 ")] 
        public IClass1 Class1 
       { 
            get
            set
       } 

             public  void Show() 
       { 
           Console.WriteLine( this.GetType()); 
           Class1.Show(); 
       } 
   }   
复制代码

App1.Config配置:

ExpandedBlockStart.gif
复制代码
<? xml version="1.0" encoding="utf-8"  ?> 
< configuration > 
   < configSections > 
     < section  name ="unity"  
             type
="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, 
             Microsoft.Practices.Unity.Configuration"
/> 
   </ configSections > 
   < unity  xmlns ="http://schemas.microsoft.com/practices/2010/unity%22> 
    <container name="
First" > 
       < register  type ="ConsoleApplication1.IClass1,ConsoleApplication1"  mapTo ="ConsoleApplication1.Class1,ConsoleApplication1"  name ="class1"   /> 
       < register  type ="ConsoleApplication1.IClass2,ConsoleApplication1"  mapTo ="ConsoleApplication1.Class2,ConsoleApplication1"  name ="class2"    /> 
     </ container > 
   </ unity > 
</ configuration >
复制代码

下边是一个完整的带PIAB的例子:

ExpandedBlockStart.gif
复制代码
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using Green.Utils; 
using Microsoft.Practices.Unity.InterceptionExtension; 
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration; 

namespace ConsoleApplication1 

     class Program 
    { 
         static  void Main( string[] args) 
        { 

            ELUnityUtility.Resolve<IClass2>().Show(); 
            ( typeof(IClass2).Resolve()  as IClass2).Show(); 
            Console.Read(); 
        } 
    } 

     public  interface IClass1 
    { 
         void Show(); 
    } 

    [Green.Utils.ELPolicyinjection] 
     public  class Class1 : IClass1 
    { 

         #region IClass1 成员 
        [TestCallHandler] 
         public  void Show() 
        { 
            Console.WriteLine( this.GetType()); 
        } 

         #endregion 
    } 

    [Green.Utils.UnityInjection( " First ", Name =  " class2 ", ConfigFile =  " App1.config ")] 
     public  interface IClass2 
    { 
         void Show(); 
    } 

    [Green.Utils.ELPolicyinjection] 
     public  class Class2 : ConsoleApplication1.IClass2 
    { 
        [Microsoft.Practices.Unity.Dependency( " class1 ")] 
         public IClass1 Class1 
        { 
             get
             set
        } 

        [TestCallHandler] 
         public  void Show() 
        { 
            Console.WriteLine( this.GetType()); 
            Class1.Show(); 
        } 
    } 

    [Microsoft.Practices.EnterpriseLibrary.Common.Configuration.ConfigurationElementType( typeof(CustomCallHandlerData))] 
     public  class TestCallHandler : ICallHandler 
    { 
         #region ICallHandler 成员 

         public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext) 
        { 
             if (input ==  nullthrow  new ArgumentNullException( " input "); 
             if (getNext ==  nullthrow  new ArgumentNullException( " getNext "); 
            Console.WriteLine( " begin.... "); 
             var result = getNext()(input, getNext); 
            Console.WriteLine( " end.... "); 
             return result; 
        } 

         public  int Order 
        { 
             get
             set
        } 

         #endregion 
    } 

    [AttributeUsage(AttributeTargets.Method)] 
     public  class TestCallHandlerAttribute : HandlerAttribute 
    { 
         public  override ICallHandler CreateHandler(Microsoft.Practices.Unity.IUnityContainer container) 
        { 
             return  new TestCallHandler(); 
        } 
    } 
}
复制代码
 

欢迎大家指正,批评,交流是的大家都功能进步。代码下载


作者:破  狼 
出处:http://www.cnblogs.com/whitewolf/ 
本文版权归作者,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。该文章也同时发布在我的独立博客中-个人独立博客博客园--破狼51CTO--破狼。http://www.cnblogs.com/whitewolf/archive/2011/11/29/2268379.html


相关文章
|
5月前
|
Java Spring
spring框架之AOP模块(面向切面),附带通知类型---超详细介绍
spring框架之AOP模块(面向切面),附带通知类型---超详细介绍
51 0
|
API
.net core工具组件系列之Autofac—— 第二篇:Autofac的3种依赖注入方式(构造函数注入、属性注入和方法注入),以及在过滤器里面实现依赖注入
本篇文章接前一篇,建议可以先看前篇文章,再看本文,会有更好的效果。前一篇跳转链接:https://www.cnblogs.com/weskynet/p/15046999.html
410 0
.net core工具组件系列之Autofac—— 第二篇:Autofac的3种依赖注入方式(构造函数注入、属性注入和方法注入),以及在过滤器里面实现依赖注入
|
6月前
|
Java Spring 容器
05Spring - IOC中bean标签和管理对象细节
05Spring - IOC中bean标签和管理对象细节
25 0
|
Java 程序员 网络安全
spring4.1.8扩展实战之五:改变bean的定义(BeanFactoryPostProcessor接口)
通过自定义BeanFactoryPostProcessor接口的实现类,来对bean实例做一些控制
247 0
spring4.1.8扩展实战之五:改变bean的定义(BeanFactoryPostProcessor接口)
|
Android开发
【IOC 控制反转】IOC 简介 ( 依赖注入的两种实现方式 | 编译期注入 | 运行期注入 )
【IOC 控制反转】IOC 简介 ( 依赖注入的两种实现方式 | 编译期注入 | 运行期注入 )
141 0
|
Java API Spring
SPRING01_概述、配置文件、bean实例化、依赖注入的方式、依赖注入的数据类型、分模块开发、API使用(二)
SPRING01_概述、配置文件、bean实例化、依赖注入的方式、依赖注入的数据类型、分模块开发、API使用(二)
SPRING01_概述、配置文件、bean实例化、依赖注入的方式、依赖注入的数据类型、分模块开发、API使用(二)
|
Java API 容器
SPRING01_概述、配置文件、bean实例化、依赖注入的方式、依赖注入的数据类型、分模块开发、API使用(五)
SPRING01_概述、配置文件、bean实例化、依赖注入的方式、依赖注入的数据类型、分模块开发、API使用(五)
SPRING01_概述、配置文件、bean实例化、依赖注入的方式、依赖注入的数据类型、分模块开发、API使用(五)
SPRING01_概述、配置文件、bean实例化、依赖注入的方式、依赖注入的数据类型、分模块开发、API使用(四)
SPRING01_概述、配置文件、bean实例化、依赖注入的方式、依赖注入的数据类型、分模块开发、API使用(四)
102 0
|
Java API Spring
SPRING01_概述、配置文件、bean实例化、依赖注入的方式、依赖注入的数据类型、分模块开发、API使用(三)
SPRING01_概述、配置文件、bean实例化、依赖注入的方式、依赖注入的数据类型、分模块开发、API使用(三)
105 0

热门文章

最新文章