zoukankan      html  css  js  c++  java
  • spring.net、castle windsor、unity实现aop、ioc的方式和简单区别

    本文不讲这3大框架的内部实现原理,只是提供了一个demo,分别实现了它们实现注入属性、拦截消息的例子,以写日志为例,写日志方式用异步还是同步ILogType作为写日志方式,注入日志存放地方ILogStore来演示基本的aop、ioc功能。spring.net用的1.3.1,官网http://www.springframework.net/,castle windsor用的2.5.2,官网http://www.castleproject.org/,unity用的2.0,它是微软开源项目,可在http://unity.codeplex.com/下载,该demo用的这3大框架里的依赖注入容器均为最新版本,部分配置等实现方式有细微变化,中文资料很少找,我也作为入门学习,做一个技术备份吧。

    之前对spring.net熟悉点,中文资料也比较多,比如刘冬的博客http://www.cnblogs.com/GoodHelper。spring.net项目里它封装和扩展了很多其他项目,比如常用的NHibernate,windows消息队列,作业调度,asmx,wcf服务等,castle项目也是相当的庞大,monorail,activerecord,windsor,dynamicproxy等,terrylee好几年前就写过系列博文activerecord和windsor的介绍,http://www.cnblogs.com/Terrylee/archive/2006/04/28/387503.html,unity是微软企业库EntLib发展中演变出来的依赖注入容器,artech的系列文章http://www.cnblogs.com/artech/tag/Unity/  kyo-yo的系列文章 http://www.cnblogs.com/kyo-yo/tag/Entlib/等都是相当有技术含量的。

    先看下整个demo的结构:

    本程序通过写日志的方式来说明注入过程,ILogType申明写日志的方式,IlogStore申明日志存放方式: 

        /// <summary>
        
    /// http://lawson.cnblogs.com
        
    /// </summary>
        public interface ILogType
        {
            ILogStore Logs { 
    get;set;}
            
    void Log(string content);
        }
        /// <summary>
        
    /// http://lawson.cnblogs.com
        
    /// </summary>
        public interface ILogStore
        {
            
    void Log(string content);
        }

     DirectLogType用来表示日志直接同步存放,ThreadLogType表示日志异步存放(这里简单处理直接new线程处理了),ConsoleLog表示日志存放控制台展现,TextLog表示日志用文本文档存放。

    下面看Spring.net的代码,为了直接在Main函数看到所有代码,这里直接在Main里从容器获取对象:

    Spring.net

            
    static void Main(string[] args)
            {
                IApplicationContext ctx 
    = ContextRegistry.GetContext();

                ILogType logtype 
    = (ILogType)ctx.GetObject("LogType");
                
    //ILogType logtype = SpringObjectManager.GetObject<ILogType>("LogType");            

                logtype.Log(
    "log spring test");

                Console.ReadKey();

            }

    输出结果如下:

    从代码里看不到多余的代码,它是通过配置文件注入了consoleLog,并且添加了前置后置环绕通知实现的,配置文件如下:

    App.config
      <configSections>
        
    <sectionGroup name="spring">
          
    <section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core" />
          
    <section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
        
    </sectionGroup>
      
    </configSections>

      
    <spring>
        
    <context>
          
    <resource uri="file://objects.xml" />
        
    </context>
      
    </spring>

      

    objects.xml
    <?xml version="1.0" encoding="utf-8" ?>
    <objects xmlns="http://www.springframework.net"
        xmlns:xsi
    ="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation
    ="http://www.springframework.net
            http://www.springframework.net/xsd/spring-objects.xsd"
    >

      
    <object id="LogType" type="Common.ThreadLogType, Common" >  <!--singleton="false" lazy-init="false"-->
        
    <property name="Logs" ref="ConsoleLog"/>
      
    </object>
      
      
    <object id="ConsoleLog" type="Spring.Aop.Framework.ProxyFactoryObject">
        
    <property name="Target">
          
    <object type="Common.ConsoleLog, Common">        
          
    </object>
        
    </property>
        
    <property name="InterceptorNames">
          
    <list>
            
    <value>beforeAdvice</value>
            
    <value>aroundAdvice</value>
            
    <value>afterAdvice</value>
            
    <value>throwsAdvice</value>
          
    </list>
        
    </property>
      
    </object>

      
    <object id="beforeAdvice" type="SpringNetConsole.Advice.BeforeAdvice, SpringNetConsole" />
      
    <object id="aroundAdvice" type="SpringNetConsole.Advice.InvokeAdvice, SpringNetConsole" />
      
    <object id="afterAdvice" type="SpringNetConsole.Advice.AfterAdvice, SpringNetConsole" />
      
    <object id="throwsAdvice" type="SpringNetConsole.Advice.ExceptionAdvice, SpringNetConsole" />


    </objects>

      

     spring.net的环绕通知通过配置后继承AopAlliance.Intercept.IMethodInterceptor接口的public object Invoke(IMethodInvocation invocation)即可拦截,前置后置通知继承Spring.Aop下的IMethodBeforeAdvice,IAfterReturningAdvice接口实现拦截,具体配置文件的说明可以查看相关文档或者spring.net专题的详细说明。

    Castle的最新版本和以前有一定的差别,Castle.core已经封装了以前的DynamicProxy的代码,windsor在ioc方面的配置方式差不多,思路都一样的,引用其他对象,它的关键字符是$,如

      <component id="LogType" type="Common.ThreadLogType, Common" service="Common.ILogType, Common">
        
    <parameters>
          
    <Logs>${Log}</Logs>
        
    </parameters>
      
    </component>

    它也有自己的环绕通知和前置后置通知,环绕通知Castle.DynamicProxy.IInterceptor,前置后置通知的拦截只在一个类里Castle.DynamicProxy.StandardInterceptor。

    Unity用起来,和官方资料看起来,感觉更希望大家通过写代码的方式注入对象和拦截对象,但是我更喜欢配置文件注入的方式,因此也用配置文件来注入对象:

    objects.xml
    <?xml version="1.0" encoding="utf-8" ?>
    <unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
      
    <alias alias="singleton" type="Microsoft.Practices.Unity.ContainerControlledLifetimeManager, Microsoft.Practices.Unity" />
      
    <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension,
                        Microsoft.Practices.Unity.Interception.Configuration"
     />
      
    <container name="abc">
        
    <extension type="Interception" />
        
    <register type="IInterceptionBehavior" mapTo="UnityConsole.Advice.MyInterceptionBehavior,UnityConsole" 
                  name
    ="MyInterception"></register>
        
    <register type="Common.ILogType, Common" mapTo="Common.ThreadLogType, Common">
          
    <property name="Logs">
            
    <dependency name="regLogs"></dependency>
          
    </property>
        
    </register>

        
    <register name="regLogs" type="Common.ILogStore, Common" mapTo="Common.ConsoleLog, Common">
          
    <interceptionBehavior name="MyInterception"/>
          
    <interceptor type="InterfaceInterceptor"/>
        
    </register>
      
    </container>
    </unity>

    具体配置方式可以查询相关文档,有意思的是我没有发现它明确的前置后置通知,只有一个通用的环绕通知拦截,Microsoft.Practices.Unity.InterceptionExtension.IInterceptionBehavior接口内的public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext),通过注入后,继承它可以拦截到消息的执行。

    但可以通过继承它的Microsoft.Practices.Unity.UnityContainerExtension扩展,完成事件的拦截,如artech的文章-IoC+AOP的简单实现http://www.cnblogs.com/artech/archive/2010/09/01/1815221.html,或者国外的http://www.machinaaurum.com.br/blog/post/AOP-With-Unity-20.aspx3篇文章,这个我也在学习中,还不是很熟。

    这3大框架都是相当庞大的系统,需要慢慢学习,根据项目需要应用他们,也许会发现更合理更合适的实现方式。本篇博文只是简单的对3大容器完成aop、ioc的简单讲解,由于我现在对他们也是了解皮毛,文章或者程序有不对的地方,欢迎提出,我也可以多学习学习。

    本demo源代码如下:

    /Files/Lawson/IOCTests-lawson.rar

  • 相关阅读:
    设计模式的四个基本要素
    拖拉记录上下移动--Ajax UI
    Rails-Treasure chest2 嵌套表单;
    YAML(摘录)
    Rails-Treasure chest1 (自定义Model网址;多语言包; 时区设置, TimeZone类; 格式日期时间; 表单单选UI; 表单多选UI;Select2 Plugin)
    iTerm2的设置和Zsh.
    **优化--后端**: 计数缓存counter_cache; rack-mini-profiler(2300🌟) ; bullet(5000✨):侦测N+1query
    优化--前端(全占课,未完成作业:);CDN; Http/2的设置(未完成)
    null值的判断
    if else
  • 原文地址:https://www.cnblogs.com/Lawson/p/1913107.html
Copyright © 2011-2022 走看看