利用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

[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

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), true) as 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), false) as 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), true) as 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:

[AttributeUsage(AttributeTargets.Class)] 
   public class ELPolicyinjectionAttribute : Attribute 
   { 
       public string Name 
       { 
           get; 
           set; 
       } 
   }

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

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配置:

<?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的例子:

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 == null) throw new ArgumentNullException("input"); 
            if (getNext == null) throw 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

时间: 2024-12-09 20:44:28

利用Attribute简化Unity框架IOC注入的相关文章

Entity Framework 实体框架的形成之旅--利用Unity对象依赖注入优化实体框架(2)

在本系列的第一篇随笔<Entity Framework 实体框架的形成之旅--基于泛型的仓储模式的实体框架(1)>中介绍了Entity Framework 实体框架的一些基础知识,以及构建了一个简单的基于泛型的仓储模式的框架,例子也呈现了一个实体框架应用的雏形,本篇继续介绍这个主题,继续深化介绍Entity Framework 实体框架的知识,以及持续优化这个仓储模式的实体框架,主要介绍业务逻辑层的构建,以及利用Unity和反射进行动态的对象注册. 1.EDMX文件位置的调整 我们从上篇例子,

利用Attribute和反射从模板生成短信

根据模板生成短信,这是一个比较常见的需求.说白了,就是如何把短信模板中的关键字替换掉,变成实际的.有意义的短信. 例如短信模板如下:"[用户名],今天是[日期],[内容]",那"[用户名]"."[日期]"."[内容]",就是关键字. 大家会说,这还不容易,我写个函数替换下不就行了? public string GetMsg(string template, string userName, string date, strin

利用Websphere Commerce计算框架提供的可定制性和可扩展性

本文介绍如何利用 Websphere http://www.aliyun.com/zixun/aggregation/3914.html">Commerce 计算框架提供的可定制性和可扩展性,将 Websphere Commerce 与第三方税务计算应用-- Avalara AvaTax 进行集成的方法 , 并且通过实例演示其应用.通过二者的结合,Websphere Commerce 将税务计算交由专业的税务计算应用来处理,为电子商务平台用户提供了更为可靠和高效的服务. 在 Websphe

微软名为Unity的依赖注入Application Block

微软模式与实践小组发布了叫做Unity或者Unity Application Block的依赖注入容器.开发人员现在能够利用可扩展的轻量级容器创建松耦合应用. InfoQ有机会采访了Unity项目的开发领头人Chris Tavares. Rob Bazinet (RB): Chris介绍一下你自己和你是如何参与Unity的? Chris Tavares (CT):我的名字叫Chris Tavares.我是微软模式与实践小组的一名高级软件开发人员.我目前正在领导Enterprise Library

利用Ruby简化你的Java测试(进阶篇)

本文是Productive Java with Ruby系列文章的第二篇,通过上一篇的介绍,我想大家对如何利用Ruby进行单元测试有了一个基本的了解,从这里开始,我将和大家一起讨论一些利用Ruby进行单元测试时的高级话题. 通常,新技术的引入只能降低解决问题的难度,而不是消除问题本身! 在"依赖"的原始丛林中挣扎... 通过Ruby我们可以更高效的处理数据准备的问题,但是真实的世界并不那么简单!随着测试的深入,我们会越发的感觉一不小心就挣扎在"依赖"的原始丛林中!有

漏洞预警:Spring Boot框架表达式注入漏洞

高危漏洞的曝光总是发生在意想不到的时刻:周末所有人都准备享受周末的时间,Spring Boot框架的SpEL表达式注入通用漏洞曝光,利用该漏洞,远程攻击者在服务器上可执行任意命令--该漏洞影响Spring Boot版本从1.1-1.3.0,建议在使用存在此缺陷版本Spring Boot的企业立即将之升级至1.3.1或以上版本. 具体的漏洞预警报告如下: 影响范围:Spring Boot版本1.1-1.3.0 修复方案:升级Spring Boot版本至1.3.1或以上版本 Spring是2003年

框架-@Autowired注入为null,空指针异常。

问题描述 @Autowired注入为null,空指针异常. Spring mvc + hibernate 的框架中,在非Controller下使用@Autowired注入失败,空指针异常.配置文件中已经加入了如下的内容 <!-- 使用annotation 自动注册bean并保证@Required@Autowired的属性被注入 --> /context:component-scanService类:@Service(""realtimeDataService"&q

基于MVC框架+IOC+Rhino Mocks的一个简单项目介绍

现在不管是企业还是科研机构,几乎所有的项目开发都是遵循一定的框架,将经过实践证明过的开发 框架和开发模式借鉴使用无可厚非,但难免会遇到某些功能实现或者基于某种考虑当前的开发框架无法达 到这样的目的.这时我们就会考虑不同技术的融合. 我们现在正在开发的平台项目正是借鉴了这样的思想,我们的平台项目首先整体的开发框架使用了 AspNet MVC框架:其次数据访问层套用了CommunityServer的开发框架,其中融合了Provider模式和传统 的三层架构:而在业务逻辑层处理中,为了保证代码的可重用

利用AnnotationMethodHandlerAdapter对Spring的Controller注入session对象

在利用spring的mvc开发过程中,需要将User对象从session中取出来使用.参照网上的做法,我利用 了AnnotationMethodHandlerAdapter来解决这个问题.下面是XML代码,放到web-inf下面的springMVC配 置文件中: <bean id="userArgumentResolver" class="com.greatwall.module.yhqxgl.interceptor.UserArgumentResolver"