AOP解析——含简单AOP框架实现(包括Proxy模式实现与Attribute实现)实现Castle的AR事务低侵入性

AOP简介:

AOP(Aspect Oriented Programming)“面向切面编程”,其实和OOP(Object Oriented Programming)“面向对象编程”一样是一种编程思路,而且个人以为翻译为“切面导向编程”更为妥当,OOP也应翻译为“对象导向编程”。因为正是有了“切面”和“对象”的想法和概念才产生了“Aspect Oriented Programming”和“Object Oriented Programming”这些编程方法,所以“导向”更为贴近些

以下想法均为个人揣摩得出,具体官方概念请Google,Bing,Baidu.

AOP,个人以为是一种行为(Behavior)的注入,在不改变原有逻辑(original logic)的基础上,将一些可重用的其他逻辑(other logic)注入到原有逻辑(original logic)中。切面(Aspect)即为其他逻辑(other logic),是一些特殊的业务关注点,包括“事务处理”,“异常捕捉”,“日志记录”,“身份验证”等方面。

这种“切面”逻辑一般贯彻整个解决方案,AOP方式将这种切面提取出来,实现了解耦和代码简洁化。

简单例子:

下面举个简单的例子来说明为什么要使用AOP:

1)没有使用AOP的Castle ActiveRecord“事务处理”

代码
class  AOPTest
{
    
//  ......

    
///   <summary>
    
///  Save the retire user info.
    
///   </summary>
    
///   <param name="site"> The user will be retire user. </param>
     public   void  SaveRetireUserInfo(User user)
    {
        
using (TransactionScope transaction  =   new  TransactionScope())
        {
           
try
           {
             RetireUser retireUser 
=   new  RetireUser();
             retireUser.Name 
=  user.Name;
             retireUser.Department 
=  user.Department;
             
//  ...
             user.Delete();
             retireUser.Save();
             transaction.VoteCommit(); 
// 完成事务
           }
           
catch (Exception ex)
           {
              Log.Write(ex.Message);
              transaction.VoteRollBack(); 
// 事务回滚
           }
        }
    }

    
//  ......
}

 2)使用AOP的Castle ActiveRecord“事务处理”, 里边使用了我自己写的精简AOP框架,与原来的文章一样,看不懂没关系,这里只是个宏观的概念。重点在demo分析。

代码
///   <summary>
///  The test class for AOP use attribute for transaction.
///   </summary>
[AOPProxy(Interception  =   typeof (TransactionInterception))]
class  AOPTest : ContextBoundObject
{
    
//  ......

    
///   <summary>
    
///  Save the retire user info.
    
///   </summary>
    
///   <param name="site"> The user will be retire user. </param>
     public   void  SaveRetireUserInfo(User user)
    {
        RetireUser retireUser 
=   new  RetireUser();
        retireUser.Name 
=  user.Name;
        retireUser.Department 
=  user.Department;
        
//  ...
        user.Delete();
        retireUser.Save();
    }

    
//  ......
}

///   <summary>
///  The interception of the AOP for trasaction.
///   </summary>
class  TransactionInterception : IInterception
{
    
private  TransactionScope transaction  =   null ;

    
#region  IInterception Members

    
public   void  ExceptionHandle()
    {
        transaction.VoteRollBack(); 
// 事务回滚
    }

    
public   void  PostInvoke()
    {
        transaction.VoteCommit(); 
// 完成事务        
    }

    
public   void  PreInvoke()
    {
        transaction 
=   new  TransactionScope();  // 初始化事务
    }

    
#endregion
}

由以上可见,加入AOP后(AOPProxy Attribute实现),“其他逻辑”注入“原始逻辑”使得代码更加简洁,同时也将“切面”的逻辑和“业务”的逻辑分离开来,实现了解耦。TransactionInterception是拦截器,实现了“其他逻辑”,由AOPProxy Attribute通过type将其注入。在处理“原始逻辑”的时候会同时处理注入的“其他逻辑”。ExceptionHandle方法实现出现Exception时的“其他逻辑”注入;PreInvoke方法实现在调用“主题”方法前的“其他逻辑”注入;PostInvoke方法实现在调用“主题”方法后的“其他逻辑”注入。

简单来说执行流程如下:

1. PreInvoke();

2. 主题Method();

3.

if(调用"主题Method()"时出现Exception)
{

     ExceptionHandle();
}

else

{

     PostInvoke();
}

有下面的SaveRetireUserInfo方法可以看到“业务逻辑”变得简洁,在“业务逻辑”已经见不到扰乱代码可读性的“事务代码”和“try...catch...”语句块了,只需要给该类加上“AOPProxy”特性注入相应的“拦截器”并继承ContextBoundObject即可。

public void SaveRetireUserInfo(User user)
{
        RetireUser retireUser 
= new RetireUser();
        retireUser.Name 
= user.Name;
        retireUser.Department 
= user.Department;
        
// ...
        user.Delete();
        retireUser.Save();
 }

Proxy基础:

代理模式,说白了就是设置一个“中间层”(proxy),把对实际要操作的“主题”保护在里边,并且在操作时进行额外的操作,实现注入。对“主题”的操作均需要通过proxy来完成,就如同经济人。

比如:你是著名歌星SexyBaby,你有一个经纪人叫Underdog,你只负责唱歌,各种演唱会的举办和电视台对你邀请一律由Underdog负责,你SexyBaby就是“主题”而你的经纪人Underdog就是proxy。

具体的代理模式可以看我以前写的关于Dota的设计模式随笔和各种设计模式书籍。

下面介绍个简单的例子来了解下代理模式。

假设一个场景:IT界优秀人士均喜欢看AV,而由于为了保护我们国家未成年人幼小的心灵不受到不良网站侵害,国家屏蔽了AV站点,那我们这些IT界寂寞哥又有这样的需求,那该怎么办那?我们需要通过Online Web Proxy来解决这个问题,我们通过这样的“在线代理网站”(“在线代理网站”服务器放在不屏蔽AV站点的国家,由“在线代理网站”服务器间接访问AV站点。因为在线代理网站不直接提供AV信息,所以我们是可以访问的)来访问AV站点就可以了。这时我们是通过Proxy(“在线代理网站”)访问到“主题”(AV站点),对Proxy(“在线代理网站”)的操作和直接操作“主题”(AV站点)没有什么区别。

 下面就开始我们的AV之旅吧,由于上次有同学说我代码里用中文,怪怪的,这次都用英文,顺便让大家复习下英文了:

1) 首先我们必须有一台链接到Internet的电脑“MyComputer”。 

 

代码
//
//  Authors:
//  Xiaoliang Pang (mailto:[email protected])
//
//  Copyright (c) 2010 Landpy Software
//
//   http://www.cnblogs.com/pangxiaoliang
//
using  System;
using  System.Collections.Generic;
using  System.Text;

namespace  Landpy.ProxyPattern
{
    
///   <summary>
    
///  My PC.
    
///   </summary>
     public   class  MyComputer
    {
        
///   <summary>
        
///  Visit the site.
        
///   </summary>
        
///   <param name="site"> The site. </param>
         public   void  Visit(ISite site)
        {
            Console.ForegroundColor 
=  ConsoleColor.Green;
            Console.WriteLine(
" Site Url:{0} " , site.Url);
            Console.ForegroundColor 
=  ConsoleColor.White;
            IFilter filter 
=   new  ChinaDNSFilter();  //  Server in China, comply with the rule of China.
            site  =  filter.Parse(site);  //  Parse the site.
            Console.ForegroundColor  =  ConsoleColor.Gray;
            site.ShowInformation(); 
//  Show the information of the site.
            Console.ForegroundColor  =  ConsoleColor.White;
        }
    }
}

 

 “MyComputer”有一个Visit方法,可以访问到传入的ISite(抽象出的站点接口),Visit方法流程如下:

1) 输出当前站点ISite的Url。下面的Code是ISite的定义。

 

代码
//
//  Authors:
//  Xiaoliang Pang (mailto:[email protected])
//
//  Copyright (c) 2010 Landpy Software
//
//   http://www.cnblogs.com/pangxiaoliang
//
using  System;
using  System.Collections.Generic;
using  System.Text;

namespace  Landpy.ProxyPattern
{
    
///   <summary>
    
///  The interface of site.
    
///   </summary>
     public   interface  ISite
    {
        
///   <summary>
        
///  The url of site.
        
///   </summary>
         string  Url
        {
            
get ;
        }

        
///   <summary>
        
///  Show the information about this site.
        
///   </summary>
         void  ShowInformation();
    }
}

 

另外我们设计了几个站点以供访问,代码如下:

首先是传说中的AVSite(http://www.avsite.com/),看看介绍多么吸引人“The site is so hot, all AV stars.”。

代码
//
//  Authors:
//  Xiaoliang Pang (mailto:[email protected])
//
//  Copyright (c) 2010 Landpy Software
//
//   http://www.cnblogs.com/pangxiaoliang
//
using  System;
using  System.Collections.Generic;
using  System.Text;

namespace  Landpy.ProxyPattern
{
    
///   <summary>
    
///  The site contains AV information.
    
///   </summary>
     public   class  AVSite : ISite
    {
        
#region  ISite Members

        
///   <summary>
        
///  The url of site.
        
///   </summary>
         public   string  Url
        {
            
get  {  return   " http://www.AVSite.com " ; }
        }

        
///   <summary>
        
///  Show the information about this site.
        
///   </summary>
         public   void  ShowInformation()
        {
            Console.WriteLine(
" The site is so hot, all AV stars. " );
        }

        
#endregion
    }
}

 

然后是我们经常上的博客园“http://www.cnblogs.com”,介绍“The technology site, the home of coders.”。

代码
//
//  Authors:
//  Xiaoliang Pang (mailto:[email protected])
//
//  Copyright (c) 2010 Landpy Software
//
//   http://www.cnblogs.com/pangxiaoliang
//
using  System;
using  System.Collections.Generic;
using  System.Text;

namespace  Landpy.ProxyPattern
{
    
///   <summary>
    
///  The site of cnblogs.
    
///   </summary>
     public   class  CnblogsSite : ISite
    {
        
#region  ISite Members

        
///   <summary>
        
///  The url of site.
        
///   </summary>
         public   string  Url
        {
            
get  {  return   " http://www.cnblogs.com " ; }
        }

        
///   <summary>
        
///  Show the information about this site.
        
///   </summary>
         public   void  ShowInformation()
        {
            Console.WriteLine(
" The technology site, the home of coders. " );
        }

        
#endregion
    }
}

 

下面该我们的主角出场了,“在线代理网站”“http://www.myproxy.com”。我们可以通过构造函数传入想要代理访问的站点地址,传入站点地址后会通过DNS解析访问到相应的网站。“在线代理网站”和“DNS(Domain Name Resolution)”的实现(执行“在线代理网站”的ShowInformation方法时实际是通过代理显示要代理网站(AV站点)的信息)。

代码
//
//  Authors:
//  Xiaoliang Pang (mailto:[email protected])
//
//  Copyright (c) 2010 Landpy Software
//
//   http://www.cnblogs.com/pangxiaoliang
//
using  System;
using  System.Collections.Generic;
using  System.Text;

namespace  Landpy.ProxyPattern
{
    
///   <summary>
    
///  The online web proxy site.
    
///   </summary>
     public   class  MyProxySite : ISite
    {
        
private  ISite _site  =   null ;

        
public  MyProxySite( string  url)
        {
            _site 
=  DNS.GetSite(url);
        }

        
#region  ISite Members

        
///   <summary>
        
///  The url of site.
        
///   </summary>
         public   string  Url
        {
            
get  {  return   " http://www.myproxy.com " ; }
        }

        
///   <summary>
        
///  Show the information about this site.
        
///   </summary>
         public   void  ShowInformation()
        {
            Console.ForegroundColor 
=  ConsoleColor.Green;
            Console.WriteLine(
" Proxy start! " );
            Console.WriteLine(
" Real url:{0} " , _site.Url);
            Console.ForegroundColor 
=  ConsoleColor.Gray;
            IFilter filter 
=   new  USADNSFilter();  //  Server in USA, comply with the rule of USA.
            _site  =  filter.Parse(_site);
            _site.ShowInformation();
            Console.ForegroundColor 
=  ConsoleColor.Green;
            Console.WriteLine(
" Proxy end! " );
            Console.ForegroundColor 
=  ConsoleColor.Gray;
        }

        
#endregion
    }
}

 

DNS

 

代码
//
//  Authors:
//  Xiaoliang Pang (mailto:[email protected])
//
//  Copyright (c) 2010 Landpy Software
//
//   http://www.cnblogs.com/pangxiaoliang
//
using  System;
using  System.Collections.Generic;
using  System.Text;

namespace  Landpy.ProxyPattern
{
    
///   <summary>
    
///  Domain name resolution.
    
///   </summary>
     class  DNS
    {
        
///   <summary>
        
///  Get the site instance by the url.
        
///   </summary>
        
///   <param name="url"> The visited url. </param>
        
///   <returns> The site instance. </returns>
         public   static  ISite GetSite( string  url)
        {
            ISite site 
=   null ;
            
if  (url  ==   " http://www.AVSite.com " )
            {
                site 
=   new  AVSite();
            }
            
else   if  (url  ==   " http://www.cnblogs.com " )
            {
                site 
=   new  CnblogsSite();
            }
            
else
            {
                site 
=   new  NullSite();
            }
            
return  site;
        }
    }
}

 另外当DNS中不包含传入的网址时要返回“NullSite”,用“MyComputer”直接访问“AVSite”时,会被“ChinaFilter”过滤,返回“WarnningSite”提醒访问者触犯法律。“NullSite”和“WarnningSite”实现如下。

NullSite:

代码
//
//  Authors:
//  Xiaoliang Pang (mailto:[email protected])
//
//  Copyright (c) 2010 Landpy Software
//
//   http://www.cnblogs.com/pangxiaoliang
//
using  System;
using  System.Collections.Generic;
using  System.Text;

namespace  Landpy.ProxyPattern
{
    
///   <summary>
    
///  The site with nothing.
    
///   </summary>
     public   class  NullSite : ISite
    {
        
#region  ISite Members

        
///   <summary>
        
///  The url of site.
        
///   </summary>
         public   string  Url
        {
            
get  {  return  String.Empty; }
        }

        
///   <summary>
        
///  Show the information about this site.
        
///   </summary>
         public   void  ShowInformation()
        {
            Console.WriteLine(
" No site, please check the url. " );
        }

        
#endregion
    }
}

 

WarnningSite:

代码
//
//  Authors:
//  Xiaoliang Pang (mailto:[email protected])
//
//  Copyright (c) 2010 Landpy Software
//
//   http://www.cnblogs.com/pangxiaoliang
//
using  System;
using  System.Collections.Generic;
using  System.Text;

namespace  Landpy.ProxyPattern
{
    
///   <summary>
    
///  The site for the warnning of gov.
    
///   </summary>
     public   class  WarnningSite : ISite
    {
        
#region  ISite Members

        
///   <summary>
        
///  The url of site.
        
///   </summary>
         public   string  Url
        {
            
get  {  return  String.Empty; }
        }

        
///   <summary>
        
///  Show the information about this site.
        
///   </summary>
         public   void  ShowInformation()
        {
            Console.WriteLine(
" For the gov rule, this site can't be visited. " );
        }

        
#endregion
    }
}

 

2) 根据中国法律由ISP(Internat Service Provider)服务器过滤网站,返回相应的站点对象。

过滤接口实现如下:

代码
//
//  Authors:
//  Xiaoliang Pang (mailto:[email protected])
//
//  Copyright (c) 2010 Landpy Software
//
//   http://www.cnblogs.com/pangxiaoliang
//
using  System;
using  System.Collections.Generic;
using  System.Text;

namespace  Landpy.ProxyPattern
{
    
///   <summary>
    
///  The interface of the site visiting filter.
    
///   </summary>
     public   interface  IFilter
    {
        
///   <summary>
        
///  Parse the site.
        
///   </summary>
        
///   <param name="site"> The site. </param>
        
///   <returns> The new site. </returns>
        ISite Parse(ISite site);
    }
}

 

中国过滤器,过滤掉AVSite,过滤后返回WarnningSite,实现如下:

 

代码
//
//  Authors:
//  Xiaoliang Pang (mailto:[email protected])
//
//  Copyright (c) 2010 Landpy Software
//
//   http://www.cnblogs.com/pangxiaoliang
//
using  System;
using  System.Collections.Generic;
using  System.Text;

namespace  Landpy.ProxyPattern
{
    
///   <summary>
    
///  ISP(Internet Service Provider),filter the visited site information for comply the rule of China.
    
///   </summary>
     public   class  ChinaDNSFilter : IFilter
    {
        
#region  IFilter Members

        
///   <summary>
        
///  Parse the site.
        
///   </summary>
        
///   <param name="site"> The site. </param>
        
///   <returns> The new site. </returns>
         public  ISite Parse(ISite site)
        {
            
//  For the children, no AV information.
            ISite returnSite  =  site;
            
if  (site  is  AVSite)
            {
                returnSite 
=   new  WarnningSite();
            }
            
return  returnSite;
        }

        
#endregion
    }
}

 

美国过滤器,不过滤AVSite,直接返回AVSite,实现如下:

 

代码
//
//  Authors:
//  Xiaoliang Pang (mailto:[email protected])
//
//  Copyright (c) 2010 Landpy Software
//
//   http://www.cnblogs.com/pangxiaoliang
//
using  System;
using  System.Collections.Generic;
using  System.Text;

namespace  Landpy.ProxyPattern
{
    
///   <summary>
    
///  ISP(Internet Service Provider),filter the visited site information for comply the rule of USA.
    
///   </summary>
     class  USADNSFilter : IFilter
    {
        
#region  IFilter Members

        
///   <summary>
        
///  Parse the site.
        
///   </summary>
        
///   <param name="site"> The site. </param>
        
///   <returns> The new site. </returns>
         public  ISite Parse(ISite site)
        {
            
//  Freedom, no filter.
             return  site;
        }

        
#endregion
    }
}

 

 

3) 通过_site.ShowInformation显示站点信息。

虚拟Internat已经搭建起来,可以进行测试啦。

首先用“MyComputer”直接访问AVSite,返回WarnningSite:

 MyComputer myComputer = new MyComputer();
 ISite site = new AVSite();
 myComputer.Visit(site); // Visit AV site will be return warning.

结果:

然后用“MyComputer”通过“MyProxySite”在线代理网站,代理访问AVSite,返回AVSite站点信息,偶也~~~~

site = new MyProxySite("http://www.avsite.com/"); // Use online web proxy.
myComputer.Visit(site);

结果:

最后看完AV,我们再会博客园逛一逛

site = new CnblogsSite();
myComputer.Visit(site);

结果:

 花了很大的功夫说代理,现在该切入正题了,我们的AOP,分为代理模式实现和Attribute实现。

AOP框架实现

首先AOP实现了逻辑注入,即在调用方法之前进行了逻辑注入。我们使用System.Runtime.Remoting中呃Message机制来实现Message的截获和注入,有点像MFC框架中的钩子函数。

首先,为了实现逻辑注入,我们先要设计出逻辑注入的接口(IInterception)。为了简单起见逻辑注入我们只设计了3个Method,包括PreInvoke,PostInvoke和ExceptionHandle,分别用来注入“调用主题Method前的逻辑”,“调用主题Method后的逻辑”和“调用主题Method时发生Exception的逻辑”。具体实现如下:

代码
//
//  Authors:
//  Xiaoliang Pang (mailto:[email protected])
//
//  Copyright (c) 2010 Landpy Software
//
//   http://www.cnblogs.com/pangxiaoliang
//
using  System;

namespace  Landpy.AOP
{
    
///   <summary>
    
///  Description of IInterception.
    
///   </summary>
     public   interface  IInterception
    {
        
///   <summary>
        
///  Pre the method invoke.
        
///   </summary>
         void  PreInvoke();

        
///   <summary>
        
///  Post the method invoke.
        
///   </summary>
         void  PostInvoke();

        
///   <summary>
        
///  Handling the exception which occurs when the method is invoked.
        
///   </summary>
         void  ExceptionHandle();
    }
}

 

逻辑注入的接口(IInterception)永远不为null,根据Null Object模式设计了NullInterception(关于Null Object模式及其意义可以看我原来的文章),实现如下:

代码
//
//  Authors:
//  Xiaoliang Pang (mailto:[email protected])
//
//  Copyright (c) 2010 Landpy Software
//
//   http://www.cnblogs.com/pangxiaoliang
//
using  System;
using  System.Collections.Generic;
using  System.Text;

namespace  Landpy.AOP
{
    
///   <summary>
    
///  Null Object pattern for interception.
    
///   </summary>
     public   class  NullInterception : IInterception
    {

        
#region  IInterception Members

        
///   <summary>
        
///  Before invoke the real instance to do something.
        
///   </summary>
         public   virtual   void  PreInvoke()
        {
            
//  Do nothing.
        }

        
///   <summary>
        
///  End invoke the real instance to do something.
        
///   </summary>
         public   virtual   void  PostInvoke()
        {
            
//  Do nothing.
        }

        
///   <summary>
        
///  Handling the exception which occurs when the method is invoked.
        
///   </summary>
         public   void  ExceptionHandle()
        {
            
//  Do nothing.
        }

        
#endregion

    }
}

 

为了实现Message拦截,我们必须实现一个继承了“RealProxy”的类“AOPRealProxy”,这样我们就可以重写System.Runtime.Remoting.Messaging.IMessage Invoke(System.Runtime.Remoting.Messaging.IMessage msg)方法来注入自己的逻辑。

有的时候代码能更清楚的表达,所以先将AOPRealProxy的实现附上:

代码
//
//  Authors:
//  Xiaoliang Pang (mailto:[email protected])
//
//  Copyright (c) 2010 Landpy Software
//
//   http://www.cnblogs.com/pangxiaoliang
//
using  System;
using  System.Collections.Generic;
using  System.Text;
using  System.Runtime.Remoting;
using  System.Runtime.Remoting.Proxies;
using  System.Runtime.Remoting.Messaging;
using  System.Runtime.Remoting.Services;
using  System.Runtime.Remoting.Activation;

namespace  Landpy.AOP
{
    
///   <summary>
    
///  RealProxy is a abstract class, which is a class in Framework to provide the function about base proxy.
    
///  The Invoke method like the hook of MFC, it intercept the message, inject the custom logic and generate a new message
    
///  for system to performance.
    
///   </summary>
     class  AOPRealProxy : RealProxy, IProxyDI
    {
        
private  MarshalByRefObject _target  =   null ;
        
private  IInterception _interception  =   null ;

        
public  AOPRealProxy(Type targetType, MarshalByRefObject target)
            : 
base (targetType)
        {
            _target 
=  target;
            _interception 
=   new  NullInterception();
        }

        
///   <summary>
        
///  Overridden the method "Invoke" of the base class, invokes the method that is specified
         //   in the provided System.Runtime.Remoting.Messaging.IMessage on the remote
        
//   object that is represented by the current instance.
         ///   </summary>
        
///   <param name="msg"> A System.Runtime.Remoting.Messaging.IMessage that contains a System.Collections.IDictionary
         //   of information about the method call.
        
//   </param>
         ///   <returns> The message returned by the invoked method, containing the return value and
         //   any out or ref parameters.
        
//   </returns>
         public   override  System.Runtime.Remoting.Messaging.IMessage Invoke(System.Runtime.Remoting.Messaging.IMessage msg)
        {
            IMethodReturnMessage methodReturnMessage 
=   null ;
            IMethodCallMessage methodCallMessage 
=  msg  as  IMethodCallMessage; // Check whether the message is method call message.
             if  (methodCallMessage  !=   null )
            {
                IConstructionCallMessage constructionCallMessage 
=  methodCallMessage  as  IConstructionCallMessage;
                
if  (constructionCallMessage  !=   null ) //Constructor Method.
                {
                    RealProxy defaultProxy 
=  RemotingServices.GetRealProxy(_target);
                    defaultProxy.InitializeServerObject(constructionCallMessage);
                    methodReturnMessage 
=  EnterpriseServicesHelper.CreateConstructionReturnMessage(constructionCallMessage, (MarshalByRefObject)GetTransparentProxy()); //Create the message about constructor.
                }
                
else //Other method except constructor method.
                {
                    _interception.PreInvoke();
//Inject PreInvoke method.
                    
try
                    {
                        methodReturnMessage 
=  RemotingServices.ExecuteMessage(_target, methodCallMessage); //Invoke subject method.
                    }
                    
catch
                    {
                    }
                    
if  (methodReturnMessage.Exception  !=   null )
                    {
                        _interception.ExceptionHandle();
//Occur exception and then inject ExceptionHandle method.
                    }
                    
else
                    {
                        _interception.PostInvoke();
//Inject PostInvoke method.
                    }
                }
            }
            
return  methodReturnMessage;
        }

        
#region  IProxyDI Members

        
///   <summary>
        
///  Dependency injection the interception into proxy class.
        
///   </summary>
        
///   <param name="interception"> The interception. </param>
         public   void  InterceptionDI(IInterception interception)
        {
            _interception 
=  interception; //The pattern of interface inject, inject the interception.
        }

        
#endregion
    }
}

 

使用接口注入方式,将Interception“拦截器”注入到“AOPRealProxy”类。

注入接口“IProxyDI”设计如下:

代码
//
//  Authors:
//  Xiaoliang Pang (mailto:[email protected])
//
//  Copyright (c) 2010 Landpy Software
//
//   http://www.cnblogs.com/pangxiaoliang
//
using  System;
using  System.Collections.Generic;
using  System.Text;

namespace  Landpy.AOP
{
    
interface  IProxyDI
    {
        
void  InterceptionDI(IInterception interception);
    }
}

 

 1) 实现Proxy模式AOP:

代码
//
//  Authors:
//  Xiaoliang Pang (mailto:[email protected])
//
//  Copyright (c) 2010 Landpy Software
//
//   http://www.cnblogs.com/pangxiaoliang
//
using  System;
using  System.Collections.Generic;
using  System.Text;

namespace  Landpy.AOP
{
    
public   class  ProxyFactory
    {
        
public   static  T CreateProxyInstance < T > (IInterception interception)  where  T :  new ()
        {
            Type serverType 
=   typeof (T);
            MarshalByRefObject target 
=  Activator.CreateInstance(serverType)  as  MarshalByRefObject;
            AOPRealProxy aopRealProxy 
=   new  AOPRealProxy(serverType, target);
            aopRealProxy.InterceptionDI(interception);
            
return  (T)aopRealProxy.GetTransparentProxy();
        }
    }
}

 

实现了interception参数注入AOPRealProxy,将包装完成的传输代理类返回。此时返回的代理类对象操作起来如同直接操作“主题”。

2)实现Attribute模式AOP

 

代码
//
//  Authors:
//  Xiaoliang Pang (mailto:[email protected])
//
//  Copyright (c) 2010 Landpy Software
//
//   http://www.cnblogs.com/pangxiaoliang
//
using  System;
using  System.Runtime.Remoting.Proxies;

namespace  Landpy.AOP
{
    
///   <summary>
    
///  Description of AOPProxyAttribute.
    
///   </summary>
    [AttributeUsage(AttributeTargets.Class)]
    
public   class  AOPProxyAttribute : ProxyAttribute
    {
        
private  IInterception _interception;

        
public  Type Interception
        {
            
get  
            {
                
return  _interception.GetType();
            }
            
set
            {
                IInterception interception 
=  Activator.CreateInstance(value)  as  IInterception;
                _interception 
=  interception;
            }
        }

        
public  AOPProxyAttribute()
        {
            _interception 
=   new  NullInterception();
        }

        
public   override  MarshalByRefObject CreateInstance(Type serverType)
        {
            MarshalByRefObject target 
=   base .CreateInstance(serverType);
            AOPRealProxy aopRealProxy 
=   new  AOPRealProxy(serverType, target);
            aopRealProxy.InterceptionDI(_interception);
            
return  aopRealProxy.GetTransparentProxy()  as  MarshalByRefObject;
        }
    }
}

 

实现了interception的Attribute用type注入AOPRealProxy,将包装完成的传输代理类返回。此时返回的代理类对象操作起来如同直接操作“主题”。

测试AOP框架

(一)测试代理模式AOP。

// Proxy class to implement the AOP.
IInterception interception = new MyInterception();
AOPTestWithProxyClass aopTestTwo = ProxyFactory.CreateProxyInstance<AOPTestWithProxyClass>(interception) as AOPTestWithProxyClass;
aopTestTwo.Show();

首先实例化了一个MyInterception的拦截器,然后用ProxyFactory将Interception作为传入注入“主题”。

MyInterception实现如下:

代码
     ///   <summary>
    
///  The interception of the AOP.
    
///   </summary>
     class  MyInterception : IInterception
    {

        
#region  IInterception Members

        
///   <summary>
        
///  Before invoke the real instance to do something.
        
///   </summary>
         public   void  PreInvoke()
        {
            Console.ForegroundColor 
=  ConsoleColor.Green;
            Console.WriteLine(
" ===Pre MyInterception.=== " );
            Console.ForegroundColor 
=  ConsoleColor.Gray;
        }

        
///   <summary>
        
///  End invoke the real instance to do something.
        
///   </summary>
         public   void  PostInvoke()
        {
            Console.ForegroundColor 
=  ConsoleColor.Green;
            Console.WriteLine(
" ===Post MyInterception.=== " );
            Console.ForegroundColor 
=  ConsoleColor.Gray;
        }

        
///   <summary>
        
///  Handling the exception which occurs when the method is invoked.
        
///   </summary>
         public   void  ExceptionHandle()
        {
            Console.ForegroundColor 
=  ConsoleColor.Red;
            Console.WriteLine(
" There is a exception! " );
            Console.ForegroundColor 
=  ConsoleColor.Gray;
        }

        
#endregion
    }

 

AOPTestWithProxyClass实现如下:

代码
     ///   <summary>
    
///  The test class for AOP use proxy class.
    
///   </summary>
     class  AOPTestWithProxyClass : ContextBoundObject
    {
        
public   void  Show()
        {
            Console.ForegroundColor 
=  ConsoleColor.Gray;
            Console.WriteLine(
" Hello, I am AOPTestTwo. " );
            Console.ForegroundColor 
=  ConsoleColor.Gray;
        }
    }

结果:

可见"===Pre MyInterception.==="和"===Post MyInterception.==="已经成功实现AOP注入。

(二)测试Attribute实现AOP。

// Attribute to implement the AOP.
AOPTestWithAttribute aopTest = new AOPTestWithAttribute();
aopTest.Show();

此时的代码要比Proxy实现更为简单,直接用类的构造函数实现类的实例化,不用ProxyFactory生成实例,Interception同样还是使用了MyInterception。

AOPTestWithAttribute类的实现如下:

代码
     ///   <summary>
    
///  The test class for AOP use attribute..
    
///   </summary>
    [AOPProxy(Interception  =   typeof (MyInterception))]
    
class  AOPTestWithAttribute : ContextBoundObject
    {
        
public   void  Show()
        {
            Console.ForegroundColor 
=  ConsoleColor.Gray;
            Console.WriteLine(
" Hello, I am AOPTest. " );
            Console.ForegroundColor 
=  ConsoleColor.Gray;
        }
    }

 

结果:

(三)测试Attribute实现AOP[事务的提交和回滚]。

            AOPTestWithAttributForTrasaction aopTestWithAttributForTrasaction = new AOPTestWithAttributForTrasaction();
            // Execute the transaction successfully.
            aopTestWithAttributForTrasaction.ExecuteTransactionSuccessfully();

            WriteSplitLine();

            // Execute the transaction unsuccessfully.
            try
            {  
                aopTestWithAttributForTrasaction.ExecuteTransactionUnsuccessfully();
            }
            catch (Exception ex)
            {
                Console.ForegroundColor = ConsoleColor.Blue;
                Console.WriteLine(ex.Message);
                Console.ForegroundColor = ConsoleColor.Gray;
            }

在ExecuteTransactionUnsuccessfully方法中加入throw Excetpion代码,实现执行不成功的情况。当执行ExecuteTransactionSuccessfully方法时实现事务的提交,当执行ExecuteTransactionUnsuccessfully实现事务的回滚,此时的例子可以对照前面所将的Castle ActiveRecord的事务实现AOP的例子。

AOPTestWithAttributForTrasaction实现如下:

代码
    [AOPProxy(Interception  =   typeof (TransactionInterception))]
    
class  AOPTestWithAttributForTrasaction : ContextBoundObject
    {
        
public   void  ExecuteTransactionSuccessfully()
        {
            Console.WriteLine(
" Execute the transaction successfully:) " );
        }

        
public   void  ExecuteTransactionUnsuccessfully()
        {
            Console.WriteLine(
" Execute the transaction unsuccessfully:( " );
            
throw   new  AOPNullException();
        }
    }

 

Interception使用了新的TransactionInterception,TransactionInterception的实现如下:

代码
     ///   <summary>
    
///  The interception of the AOP for trasaction.
    
///   </summary>
     class  TransactionInterception : IInterception
    {
        
#region  IInterception Members

        
public   void  ExceptionHandle()
        {
            Console.ForegroundColor 
=  ConsoleColor.Red;
            Console.WriteLine(
" ☆☆☆Rollback transaction☆☆☆ " );
            Console.ForegroundColor 
=  ConsoleColor.Gray;
        }

        
public   void  PostInvoke()
        {
            Console.ForegroundColor 
=  ConsoleColor.Green;
            Console.WriteLine(
" ☆☆☆Commit transaction☆☆☆ " );
            Console.ForegroundColor 
=  ConsoleColor.Gray;
        }

        
public   void  PreInvoke()
        {
            Console.ForegroundColor 
=  ConsoleColor.Green;
            Console.WriteLine(
" ☆☆☆Begin transaction☆☆☆ " );
            Console.ForegroundColor 
=  ConsoleColor.Gray;
        }

        
#endregion
    }

 

结果:

AOP解析——含简单AOP框架实现(包括Proxy模式实现与Attribute实现)实现Castle的AR事务低侵入性

 注意:在Debug下执行到“throw new AOPNullException();”时会停止,继续F5即可执行,如果非Debug状态(如直接双击exe执行),则可以执行到结束。

 这是由Debug机制造成的,不必在意。

 本人实现的AOP框架是基于ContextBoundObject,MarshalByRefObject的,在效率上会差一些,当然我们可以用反射的高级内容Emit直接生成IL注入原始程序逻辑来实现AOP,有空写篇文章介绍下:)


 

<<完整Demo下载>>

 

你可能感兴趣的:(attribute)