概念

  • Aspect-Oriented Programming(AOP):想想OOP是不是有些熟悉,AOP翻譯過來的意思就是面向切面編程。先來關(guān)注一下涉及到的以下幾個概念點(diǎn)。

  • 橫切關(guān)注點(diǎn):
    存在于項(xiàng)目的絕大多數(shù)業(yè)務(wù)中可以通用的一些輔助性的功能。例如日志、安全、持久化等模塊。它們存在于核心業(yè)務(wù)代碼塊的各個地方,卻又獨(dú)立于這些核心業(yè)務(wù)邏輯。
    如圖所示:


    Paste_Image.png

  • 切面:
    這些橫切關(guān)注點(diǎn)的統(tǒng)一抽象。

  • 所以面向切面編程,就是將項(xiàng)目的輔助性功能(如日志、異常處理、緩存處理等)與業(yè)務(wù)邏輯進(jìn)行分離,把繁瑣的輔助性代碼抽離出來不用重復(fù)Copy,使得程序具備更高的模塊化。


實(shí)現(xiàn)方式

  • 靜態(tài)織入
    即編譯時(shí)織入,實(shí)現(xiàn)原理是對編譯器做擴(kuò)展,使得在代碼編譯時(shí)編譯器將切面代碼織入到指定的切點(diǎn)。

  • 動態(tài)織入
    即運(yùn)行時(shí)織入,編譯器在編譯時(shí)對切面代碼和業(yè)務(wù)代碼分別獨(dú)立編譯,而在運(yùn)行的時(shí)候由CLR進(jìn)行代碼混合。


.Net平臺的切面實(shí)現(xiàn)——PostSharp

  • 為什么選用PostSharp

    1. 輕量級的靜態(tài)織入實(shí)現(xiàn)(可以通過反編譯清晰的知道你的代碼構(gòu)成)

    2. 使用簡單,獨(dú)立編寫切面類,更好的實(shí)現(xiàn)模塊化,繼承自PostSharp提供的各種切面類型的抽象類,并重寫其中的攔截方法即可,可以像使用類庫內(nèi)置的Attribute那樣使用AOP

    3. 對調(diào)用方法有更多的控制點(diǎn),比如輸入?yún)?shù)、返回結(jié)果、異常捕獲等

    4. 但是,但是自從2.0版本之后就不免費(fèi)了

  • PostSharp的切面類

    1. OnMethodBoundaryAspect,針對方法內(nèi)的各種可能存在切點(diǎn)的情況進(jìn)行代碼注入,實(shí)現(xiàn)切面思想,提供了OnEntry,OnExit,OnSuccess,OnException等可重寫的虛方法,顧名思義分別是在進(jìn)入方法、退出方法、方法體成功執(zhí)行、方法內(nèi)發(fā)生異常的攔截。后續(xù)的實(shí)例是通過OnEntry來修改方法的輸入?yún)?shù)來展示的。

    2. OnFiledAccessAspect,對Filed的讀寫進(jìn)行攔截處理,提供了OnGetValue,OnSetValue的虛方法。

    3. OnExceptionAspect,實(shí)現(xiàn)異常的捕獲。

    4. OnMethodInvocationAspect,方法調(diào)用攔截,提供OnInvocation虛方法。

    5. ImplementMethodAspect,用于extern方法、abstract類的方法進(jìn)行攔截。

  • PostSharp的版本差異
    3.0版本是個分水嶺,目前最新版本是5.0.28,他們的使用方式有一小點(diǎn)差異。

    • 3.0版本之前下載了安裝包,在項(xiàng)目中引用postsharp.dll,之后編碼就可以了

    • 但是3.0之后是類似于VS插件的方式工作的,下載postsharp安裝包安裝之后會在vs的菜單中新增一個postsharp菜單(如下圖),可以進(jìn)行一些設(shè)置,在使用的時(shí)候不再是引用,而是需要項(xiàng)目上右擊“添加postsharp到項(xiàng)目”


PostSharp示例

  1. 做前期準(zhǔn)備工作,從PostSharp官網(wǎng)下載最新版本的安裝包,并安裝。

  2. 打開VisualStudio,新建解決方案,添加命令行項(xiàng)目。項(xiàng)目上右鍵后點(diǎn)擊“Add PostSharp to project”后在彈出窗口按提示操作,會發(fā)現(xiàn)已經(jīng)多了postsharp的引用。

  3. 添加AspectAttribute切面類,實(shí)現(xiàn)對核心方法的輸入?yún)?shù)修改。需要注意的是postsharp提供的幾種切面類型都是繼承自Attribute基類,而且是通過對要實(shí)現(xiàn)攔截的類或方法添加特性的方式實(shí)現(xiàn)切面思想的。所以我們的切面類 需要按照約定以xxxAttribute的格式命名。

      [Serializable]
      [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)]  public class AspectAttribute : OnMethodBoundaryAspect
      {      //方法進(jìn)入時(shí)      public override void OnEntry(MethodExecutionArgs args)
          {          //修改輸入?yún)?shù)
              args.Arguments[0] = "jingdong";          //設(shè)置方法是否繼續(xù)執(zhí)行或退出,若設(shè)置的是FlowBehavior.Return方法會直接退出,不執(zhí)行后續(xù)的所有代碼。
              args.FlowBehavior = FlowBehavior.Continue;
          }      //方法離開時(shí)      public override void OnExit(MethodExecutionArgs args)
          {
              Console.WriteLine("exit");
          }      //方法成功執(zhí)行時(shí)      public override void OnSuccess(MethodExecutionArgs args)
          {
              Console.WriteLine("success");
          }
      }
  4. 在program中添加我們的核心方法Start,打印輸入?yún)?shù)。在需要實(shí)現(xiàn)攔截的方法添加上一個步驟中實(shí)現(xiàn)的切面類特性

      public class Program
      {      static void Main(string[] args)
          {          var arg = "tmall";
              Console.WriteLine($"original argument:{arg}");
              Start(ref arg);
              Console.Read();
          }
    
          [Aspect]      static void Start(ref string arg)
          {
              Console.WriteLine($"real argument:{arg}");
              Thread.Sleep(1000);
              Console.WriteLine("finished");
          }
      }
  5. 由此就簡單通過postsharp實(shí)現(xiàn)了對方法的攔截,修改輸入?yún)?shù),監(jiān)聽方法成功執(zhí)行以及退出??聪聢?zhí)行結(jié)果,成功的篡改了輸入?yún)?shù),并且可以看出攔截方法的方法體是先于OnSuccess執(zhí)行的,OnSuccess的攔截執(zhí)行完成之后才是OnExit。

  6. 之前有說過postsharp是靜態(tài)織入來實(shí)現(xiàn)AOP編程的,那么肯定是通過編譯器在編譯的時(shí)候?qū)Υa進(jìn)行了織入,可以通過反編譯exe文件來看下。


    可以看到start方法被加入了若干行代碼。

  7. 有一個小點(diǎn)需要注意,使用postsharp的時(shí)候?qū)η忻骖惐仨毺砑覵erializable特性,否則在編譯的時(shí)候就會報(bào)錯。

  • 小結(jié)

    文章內(nèi)的小例子主要是為了說明postsharp實(shí)現(xiàn)AOP的基本原理,以及實(shí)現(xiàn)過程。并沒有如同實(shí)際項(xiàng)目中使用AOP來做一些日志、安全、持久化之類的輔助功能。

http://www.cnblogs.com/holdhappiness/p/7199650.html