天天看點

自己實作簡單的AOP(一)簡介

AOP 和 OOP,在我看來是兩種相輔相成的技術,作為OOP的補充,AOP 有着自己特殊的應用場景。

假設,我們需要在Service層實作以下幾項基本功能:

/// <para>1、自動管理資料庫連接配接[可選]</para>

/// <para>2、自動管理資料庫事務,當接收到異常後(無論什麼異常)事務将自動復原[可選]</para>

/// <para>3、服務級加鎖[必選]</para>

/// <para>4、以統一方式處理 服務異常 及 錯誤, 包括資料庫異常 和 主動抛出的異常[必選]</para>

解釋:

1、在 執行Service方法前 打開資料庫連接配接, 在 執行Service方法後 關閉資料庫連接配接

2、在 執行Service方法前 Begin資料庫事務, 在 執行Service方法後 Commit資料庫事務, Catch異常後 RollBack資料庫事務

3、将 整個Service方法 lock 進去,lock Service 的私有靜态對象,以達到服務級方法的 線程安全及同步工作

4、捕獲Service方法中所有未捕獲的異常,捕獲異常後,如果需要将自動關閉連接配接和復原事務。并記錄異常資訊。

即、主動報告錯誤時,隻需要抛出異常即可。

為了 實作如上的功能,并能簡單友善實作,而且不打破現有的C#編碼規範。

是以,引入AOP、 使用 Attribute 為方法 指定增強對象,

以便在調用Service方法前,執行方法的前置增強(包括打開連接配接、開啟事務等)

在調用Service方法後,執行方法的後置增強(包括關閉連接配接、送出事務等)

及 對整個調用方法實作 Try...Catch異常捕獲 和 Lock 加鎖。

C# 引入了 Proxy (代理)的概念,即 System.Runtime.Remoting.Proxies.RealProxy 提供了 代理的基本功能。利用該對象可以自己實作AOP程式設計。

RealProxy 可以可以為任何 “直接或間接繼承于 System.MarshalByRefObject” 的類型 提供代理。

RealProxy 可以為指定類型建立一個代理對象, 被建立的代理對象的類型 可以看做是 指定類型的 子類(但 被指定的類型可以是密封類)。

【PS: 看做子類,更容易了解,本質上為被建立的代理對象的類型 和 指定類型直接為 組合關系,并不是繼承關系 】

RealProxy 的工作原理:

假設:

T 為 需要被代理的類型, t 為對象

ProxyT 為 被建立的代理類型, proxyT 為對象

T 類型中存在 成員方法 Test();

ProxyT 繼承于 T【實際上不為繼承關系,應該為組合,為友善了解看做繼承關系】, ProxyT 同樣也存在方法 Test

當執行如下代碼時:

proxyT.Test();

.NET runtime 會自動調用 System.Runtime.Remoting.Proxies.RealProxy.Invoke(...)方法。

而該方法為抽象方法,自己重寫該方法,在方法内部調用 t.Test()。

在調用之前、執行前置增強;在調用之後、執行後置增強; 及 其他處理操作。

由此可實作 AOP 程式設計,織入增強。

自定義的RealProxy

自己實作簡單的AOP(一)簡介
自己實作簡單的AOP(一)簡介

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Proxies;

namespace AOPDemo.Common
{
    public class DelayProxy<T> : RealProxy
    {
        private static object objLock = new object();

        /// <summary>
        /// 被代理的對象
        /// </summary>
        private T target;


        public DelayProxy(T target)
            : base(typeof(T))
        {
            this.target = target;

        }

        public override IMessage Invoke(IMessage msg)
        {
            IMethodCallMessage callMessage = (IMethodCallMessage)msg;

            Console.WriteLine("方法被調用前");

            Console.WriteLine("調用方法名:" + callMessage.MethodName);

            IMessage message = DelayProxyUtil.InvokeBeProxy(this.target, callMessage);

            Console.WriteLine("方法被調用後");

            return message;
        }

    }

}      

RealProxy

輔助工具類

自己實作簡單的AOP(一)簡介
自己實作簡單的AOP(一)簡介
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Runtime.Remoting.Proxies;
using System.Runtime.Remoting.Messaging;
using System.Reflection;

namespace AOPDemo.Common
{

    /// <summary>
    /// 延遲初始化代理工具類
    /// </summary>
    public static class DelayProxyUtil
    {
        /// <summary>
        /// 調用被代理對象中方法,傳回 被代理對象的 方法傳回值
        /// <para>支援 out ref 參數</para>
        /// </summary>
        /// <param name="target"></param>
        /// <param name="callMessage"></param>
        /// <returns></returns>
        public static IMessage InvokeBeProxy(object target, IMethodCallMessage callMessage)
        {
            var args = callMessage.Args;

            object returnValue = callMessage.MethodBase.Invoke(target, args);

            return new ReturnMessage(returnValue, args, args.Length, callMessage.LogicalCallContext, callMessage);
        }

        /// <summary>
        /// 向上層抛出異常
        /// </summary>
        /// <param name="ex"></param>
        /// <param name="callMessage"></param>
        /// <returns></returns>
        public static IMessage ReturnExecption(Exception ex, IMethodCallMessage callMessage)
        {
            return new ReturnMessage(ex, callMessage);
        }

        /// <summary>
        /// 擷取對象的代理
        /// </summary>
        /// <param name="type"></param>
        /// <param name="instance"></param>
        /// <param name="delay"></param>
        /// <returns></returns>
        public static object GetTransparentProxy(Type type, object instance)
        {
            Type tmpType = typeof(DelayProxy<>);

            tmpType = tmpType.MakeGenericType(type);

            RealProxy proxy = Activator.CreateInstance(tmpType, new object[] { instance }) as RealProxy;

            return proxy.GetTransparentProxy();
        }

    }
}      

簡單的Demo

自己實作簡單的AOP(一)簡介
自己實作簡單的AOP(一)簡介
public class HomeController : Controller
    {
        //
        // GET: /Home/

        public ActionResult Index()
        {
            Service service = new Service();

            Service proxy = Common.DelayProxyUtil.GetTransparentProxy(typeof(Service), service) as Service;

            proxy.Test();

            return View();
        }

    }


    public class Service : MarshalByRefObject
    {
        public void Test()
        {
            Console.WriteLine("調用Test方法");
        }
    }
          

View Code

由于例子很簡單,就不上傳源碼了。 

未完待續...

傳回導讀目錄,閱讀更多随筆

分割線,以下為部落格簽名:

軟體臭蟲情未了

  • 編碼一分鐘
  • 測試十年功

随筆如有錯誤或不恰當之處、為希望不誤導他人,望大俠們給予批評指正。