zoukankan      html  css  js  c++  java
  • 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:mv@live.cn)
    //
    // 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:mv@live.cn)
    //
    // 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:mv@live.cn)
    //
    // 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:mv@live.cn)
    //
    // 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:mv@live.cn)
    //
    // 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:mv@live.cn)
    //
    // 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:mv@live.cn)
    //
    // 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:mv@live.cn)
    //
    // 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:mv@live.cn)
    //
    // 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:mv@live.cn)
    //
    // 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:mv@live.cn)
    //
    // 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:mv@live.cn)
    //
    // 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:mv@live.cn)
    //
    // 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:mv@live.cn)
    //
    // 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:mv@live.cn)
    //
    // 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:mv@live.cn)
    //
    // 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:mv@live.cn)
    //
    // 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
        }

    结果:

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

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

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


    <<完整Demo下载>>

    敬告

    作者:pangxiaoliang
    出处:http://www.cnblogs.com/pangxiaoliang
    本文版权归pangxiaoliang和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,谢谢合作。
  • 相关阅读:
    【第五年-创业路】
    【工具与解决方案】从做项目中积累学习
    【原理篇】人工智能
    【原理】分布式系统
    攻克Spring
    工具篇集锦
    最好用的JQuery插件集合以及组合拳
    设计模式 之状态模式
    设计模式 之组合模式
    设计模式之 封装算法
  • 原文地址:https://www.cnblogs.com/pangxiaoliang/p/1680673.html
Copyright © 2011-2022 走看看