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

posted @ 2010-12-21 20:34  Lawson  阅读(2359)  评论(0编辑  收藏  举报