最愛Java

          書山有路勤為徑,學海無涯苦作舟

          《AspectJ Cookbook》讀書筆記十三: 定義通知

          一.訪問類成員 

          package com.aspectj;

          public privileged aspect MemberAccessRecipe {
              
          /**
               * Specifies calling advice whenever a method 
               * matching the following rules gets executed:
               * 
               * Class Name: MyClass
               * Method Name:foo
               * Method Return Type:void
               * Method Parameters:an int followed by a String
               
          */

              pointcut executionOfFooPointCut() : execution(
          void MyClass.foo(int,String));
              
              
          //Advice declaration
              after(MyClass myClass):executionOfFooPointCut() && this(myClass){
                  System.out.println(
          "---------- Aspect Advice Logic ----------");
                  System.out.println(
          "Accessing the set(float) member of the MyClass object");
                  System.out.println(
          "Privileged access not  required for this method call as it is public");
                  myClass.setF(
          2.0f);
                  System.out.println(
          "Using the privileged aspect access to the private f member variable");
                  System.out.println(
          "The current value of f is: ");
                  System.out.println(myClass.f);
                  System.out.println(
          "Signature: " + thisJoinPoint.getSignature());
                  System.out.println(
          "Source Line: " + thisJoinPoint.getSourceLocation());
                  System.out.println(
          "-----------------------------------------");        
              }

          }


                  通過使用this(Identifier)切入點定義,使得MyClass類的對象可供通知使用。this(Identifier)切入點定義有效地把通知展示給被觸發連接點處的this引用指向的對象。從通知內調用setF(float)方法,并顯示對MyClass對象的公共方法的訪問。為了獲得對MyClass.f私有屬性的訪問,方面不得不對其結構執行一些額外的更改。方面嘗試通過直接訪問私有成員來破快封裝性,因此,必須把方面聲明為privileged,因為它正在提交潛在的侵入動作。
                  AspectJ提供了privieged關鍵字,它用在方面需要完全不受限制地訪問類的地方,包括那些未在類的公共接口上聲明的成員變量和方法。方面的privileged狀態應該充當一個警告,在對方面或者它所應用的類執行任何更改時,必須當心這個警告,因為這些更改可能潛在地在整個應用程序中引發其他問題。

          二.訪問連接點環境
                  AspectJ提供了thisJoinPoint變量,用于展示this連接點環境。如果可以靜態地訪問正在訪問的環境,那么thisJoinPointStaticPart也是有用的。

          package com.aspectj;

          public aspect ThisJoinPointRecipe {
              
          /**
               * Specifies calling advice whenever a method 
               * matching the following rules gets executed:
               * 
               * Class Name: MyClass
               * Method Name:foo
               * Method Return Type:void
               * Method Parameters:an int followed by a String
               
          */

              pointcut callPointCut():call(
          void MyClass.foo(int,String));
              
              
          //Advice declaration
              before():callPointCut()&&!within(ThisJoinPointRecipe+){
                  System.out.println(
          "---------- Aspect Advice Logic ----------");
                  System.out.println(
          "Exercising the static parts of AspectJ 1.1.1 thisJoinPoint");
                  System.out.println(
          "Source Line: " + thisJoinPointStaticPart.getSourceLocation());
                  System.out.println(
          "JoinPoint Kind: " + thisJoinPointStaticPart.getKind());
                  System.out.println(
          "Simple toString: " + thisJoinPointStaticPart.toString());
                  System.out.println(
          "Simple toShortString: " + thisJoinPointStaticPart.toShortString());
                  System.out.println(
          "Simple toLongString: " + thisJoinPointStaticPart.toLongString());
                  System.out.println(
          "Exercising the join point generic signature of AspectJ 1.1.1 thisJoinPoint");
                  System.out.println(
          "Signature name:" + thisJoinPointStaticPart.getSignature().getName());
                  System.out.println(
          "Signature declaring type:" + thisJoinPointStaticPart.getSignature().getDeclaringType());
                  System.out.println(
          "-----------------------------------------");        
              }

              
              before():callPointCut()
          &&!within(ThisJoinPointRecipe+{
                  System.out.println(
          "---------- Aspect Advice Logic ----------");
                  System.out.println(
          "Exercising the dynamic parts of AspectJ 1.1.1 thisJoinPoint");
                  System.out.println(
          "Get the this reference: " + thisJoinPoint.getThis());
                  System.out.println(
          "Getting the Target: " + thisJoinPoint.getTarget());
                  System.out.println(
          "Join Point Arguments:");
                  Object[] args 
          = thisJoinPoint.getArgs();
                  
          for (int count = 0; count < args.length ; count++{
                      System.out.println(args[count]);
                  }

                  System.out.println(
          "-----------------------------------------");        
              }

          }

                  thisJoinPoint變量包含關于觸發連接點的靜態和動態環境信息。靜態環境信息包含可以在編譯和織入時決定的任何信息。動態連接點環境信息則只能在運行時填充,因為它依賴于連接點環境實際的運行時狀態。

          三.在連接點之前執行通知
                  使用before()類型的通知

           

          package com.aspectj;

          public aspect BeforeAdviceRecipe {
              
          /**
               * Specifies calling advice whenever a method 
               * matching the following rules gets executed:
               * 
               * Class Name: MyClass
               * Method Name:foo
               * Method Return Type:void
               * Method Parameters:an int followed by a String
               
          */

              pointcut callPointCut() : call(
          void MyClass.foo(int,String));
              
              
          //Advice declaration
              before():callPointCut()&&!within(BeforeAdviceRecipe+{
                  System.out.println(
          "---------- Aspect Advice Logic ----------");
                  System.out.println(
          "Source Location: " + thisJoinPoint.getStaticPart().getSourceLocation());        
                  System.out.println(
          "-----------------------------------------");        
              }

          }


          四.在連接點周圍執行通知
                  使用around()類型的通知。

          package com.aspectj;

          public aspect AroundAdviceRecipe {
              
          /**
               * Specifies calling advice whenever a method 
               * matching the following rules gets called:
               * 
               * Class Name: MyClass
               * Method Name:foo
               * Method Return Type:void
               * Method Parameters:an int followed by a String
               
          */

              pointcut callFooPointCut() : call(
          int MyClass.foo());
              
              
          /**
               * Specifies calling advice whenever a method 
               * matching the following rules gets called:
               * 
               * Class Name: MyClass
               * Method Name:bar2
               * Method Return Type:int
               * Method Parameters:an int 
               
          */

              pointcut callBarPointCut(
          int value) : call(int MyClass.bar(int)) && args(value);
              
              
          /**
               * Specifies calling advice whenever a method 
               * matching the following rules gets called:
               * 
               * Class Name: MyClass
               * Method Name:baz
               * Method Return Type:int
               * Method Parameters: 
               
          */

              pointcut callBazPointCut() : call(
          int MyClass.baz());
              
              
          //Advice declaration
              
          //This advice will be executed before the pointcut that picks it
              int around() : callFooPointCut()&& !within(AroundAdviceRecipe+){
                  System.out.println(
          "---------- Aspect Advice Logic ----------");
                  System.out.println(
          "Signature: " + thisJoinPoint.getSignature());
                  System.out.println(
          "Source Location: " + thisJoinPoint.getStaticPart().getSourceLocation());
                  System.out.println(
          "-----------------------------------------");
                  
          return proceed();
              }

              
              
          //Advice declaration
              
          //This advice will be executed before the pointcut that picks it
              int around(int value):callBarPointCut(value)&&!within(AroundAdviceRecipe+){
                  System.out.println(
          "---------- Aspect Advice Logic ----------");
                  System.out.println(
          "Signature: " + thisJoinPoint.getSignature());
                  System.out.println(
          "Source Location: " + thisJoinPoint.getStaticPart().getSourceLocation());
                  System.out.println(
          "-----------------------------------------");
                  
          return proceed(value);        
              }

              
              
          //Advice declaration
              
          //This advice will be executed before the pointcut that picks it
              int around(int value):callBarPointCut(value)&&!within(AroundAdviceRecipe+){
                  System.out.println(
          "---------- Aspect Advice Logic ----------");
                  System.out.println(
          "Signature: " + thisJoinPoint.getSignature());
                  System.out.println(
          "Source Location: " + thisJoinPoint.getStaticPart().getSourceLocation());
                  System.out.println(
          "-----------------------------------------");
                  
          return proceed(value);        
              }

              
              
          //Advice declaration
              
          //This advice will be executed before the pointcut that picks it
              int around() : callBazPointCut() && !within(AroundAdviceRecipe+{
                  System.out.println(
          "---------- Aspect Advice Logic ----------");
                  System.out.println(
          "Signature: " + thisJoinPoint.getSignature());
                  System.out.println(
          "Source Location: " + thisJoinPoint.getStaticPart().getSourceLocation());
                  System.out.println(
          "-----------------------------------------");
                  
          return 200;            
              }

          }


                  around()通知是一種強大的構造,它指示AspectJ應該運行通知,而不是指示連接點觸發它。這允許重寫應用程序中存在的原始邏輯。這說明了around()通知,可以依據是否從around()通知塊內發起proceed()調用,來被動或主動地應用這個通知。
                  proceed()調用指示around()通知應該繼續執行原始連接點邏輯,并傳遞原來可用的任何值。
          在示例中,第一份通知沒有參數需要傳遞;第二份通知傳遞了一個與原始值完全不同的值;第三份通知則完全返回了一個不同的值。
                  around()通知必須具有指定的返回值,但是如果不需要值,那么可以是void。

          五.在連接點之后無條件執行通知
                  使用after()類型的通知

           

          package com.aspectj;

          public aspect AfterAdviceRecipe {
              
          /**
               * Specifies calling advice whenever a method 
               * matching the following rules gets called:
               * 
               * Class Name: MyClass
               * Method Name:foo
               * Method Return Type:void
               * Method Parameters:an int followed by a String
               
          */

              pointcut callPointCut() : call(
          void MyClass.foo(int,String));
              
              
          //Advice declaration
              after():callPointCut()&&!within(AfterAdviceRecipe+){
                  System.out.println(
          "---------- Aspect Advice Logic ----------");
                  System.out.println(
          "Source Location: " + thisJoinPoint.getStaticPart().getSourceLocation());
                  System.out.println(
          "-----------------------------------------");        
              }

          }


          六.僅在從連接點正常返回之后才執行通知
                  使用after() returning或after() returning(<ReturnType> <Identifier>)類型的通知

           

          package com.aspectj;

          public aspect AfterReturningAdviceRecipe {
              
          /**
               * Specifies calling advice whenever a method 
               * matching the following rules gets called:
               * 
               * Class Name: MyClass
               * Method Name:foo
               * Method Return Type:void
               * Method Parameters:an int followed by a String
               
          */

              pointcut callPointCut():call(
          void MyClass.foo(int));
              
              
          //Advice declaration
              after() returning:callPointCut()&&!within(AfterReturningAdviceRecipe+{
                  System.out.println(
          "---------- Aspect Advice Logic ----------");
                  System.out.println(
          "Source Location: " + thisJoinPoint.getStaticPart().getSourceLocation());
                  System.out.println(
          "-----------------------------------------");        
              }

          }

           

          package com.aspectj;

          public aspect AfterReturningValueAdviceRecipe {
              
          /**
               * Specifies calling advice whenever a method 
               * matching the following rules gets called:
               * 
               * Class Name: MyClass
               * Method Name:foo
               * Method Return Type:void
               * Method Parameters:an int followed by a String
               
          */

              pointcut callPointCut():call(
          void MyClass.foo(int));
              
              
          //Advice declaration
              after() returning(Object value):callPointCut()&&!within(AfterReturningAdviceRecipe+{
                  System.out.println(
          "---------- Aspect Advice Logic ----------");
                  System.out.println(
          "Source Location: " + thisJoinPoint.getStaticPart().getSourceLocation());
                  System.out.println(
          "Value being returned: " + value);
                  System.out.println(
          "-----------------------------------------");        
              }

          }


                  使用after() returning(<ReturnType> <Identifier>)通知訪問基本類型的一個有趣作用是:必須把基本的int值裝箱進Integer類的一個實例中,以傳遞給通知。當通知期待的返回類型是Object類型時,并且如果返回值是基本類型,AspectJ將自動并且透明地把基本值裝箱進其對應的Java類中。around()形式的通知也可以使用這種自動和透明的裝箱行為,其中會期待Object類型的值,并且將從通知傳遞基本值或將基本值傳遞給通知。
          與正常的ater()相比,after() returning形式的通知提供了更精細的過濾器。

          七.僅當連接點中引發了一個異常之后才執行通知
                  使用after() throwing或after() throwing(<ExceptionType> <Identifier>)類型的通知。

           

          package com.aspectj;

          public aspect AfterThrowingAdviceRecipe {
              
          /**
               * Specifies calling advice whenever a method 
               * matching the following rules gets called:
               * 
               * Class Name: MyClass
               * Method Name:foo
               * Method Return Type:void
               * Method Parameters:an int followed by a String
               
          */

              pointcut callPointCut():call(
          void MyClass.foo(int));
              
              
          //Advice declaration
              after() throwing:callPointCut()&&!within(AfterThrowingAdviceRecipe+){
                  System.out.println(
          "---------- Aspect Advice Logic ----------");
                  System.out.println(
          "Source Location: " + thisJoinPoint.getStaticPart().getSourceLocation());
                  System.out.println(
          "-----------------------------------------");        
              }

          }


          八.控制通知優先級
                  如果把位于不同方面中的相同類型的通知應用同一連接點,則可以使用declare precedence通知。其語法如下:
                  declare precedence:TypePattern,TypePattern,...;

          package com.aspectj;

          public aspect AspectA {
              
          // Declare precedence rules
              declare precedence:AspectA,AspectB;

              
          /**
               * Specifies calling advice whenever a method matching the following rules
               * gets called:
               * 
               * Class Name: MyClass Method Name:foo Method Return Type:void Method
               * Parameters:an int followed by a String
               
          */

              pointcut callPointCut():call(
          void MyClass.foo(int,String));

              
          // Advice declaration
              before():callPointCut()&&!within(AspectA+){
                  System.out.println(
          "---------- Aspect Advice Logic ----------");
                  System.out.println(
          "In the advice of AspectA");
                  System.out.println(
          "Target: " + thisJoinPoint.getTarget());
                  System.out.println(
          "This: " + thisJoinPoint.getThis());
                  System.out.println(
          "Aspect Instance: " + AspectA.aspectOf());
                  System.out.println(
          "-----------------------------------------");
              }

          }


                  在declare precedence語句中使用TypePattern來指定不同的方面,以及他們的顯式次序。可以使用通配符來指定TypePatterns,以根據需要為特定的方面集合或方面的整個包指示優先級。
          當把一個方面中的兩個相同類型的通知塊應用于同一個連接點時,declare precedence語句就沒有意義了。為了處理這種情況,AspectJ基于方面聲明內通知的類型和位置,來應用隱式的優先級次序:
          • 按在方面中聲明before()和around()通知類型的次序,來應用他們隱式優先級規則。如果把同一方面的兩個before()通知塊應用于同一個連接點,那么聲明第一個塊將具有最高的優先級,而最后一個則最低。
          • 而after()、aftr() returning和around() throwing通知類型的隱式優先級則于before()相反。

          九.通知方面

          package com.aspectj;

          public aspect AdviseAspectRecipe {
              
          /**
               * Specifies calling advice whenever a method 
               * matching the following rules gets called:
               * 
               * Class Name: MyClass
               * Method Name:foo
               * Method Return Type:void
               * Method Parameters:an int followed by a String
               
          */

              pointcut callPointCut():call(
          void MyClass.foo(int,String));
              
              
          //Advice declaration
              before() : callPointCut()&&within(AdvisedAspect+{
                  System.out.println(
          "---------- Aspect Advice Logic ----------");
                  System.out.println(
          "In the advice attached to the call point cut");
                  System.out.println(
          "Signature: " + thisJoinPoint.getStaticPart().getSignature());
                  System.out.println(
          "Source Line: " + thisJoinPoint.getStaticPart().getSourceLocation());
                  System.out.println(
          "-----------------------------------------");        
              }

          }


          posted on 2008-08-26 13:45 Brian 閱讀(1561) 評論(1)  編輯  收藏 所屬分類: 《AspectJ Cookbook》讀書筆記

          評論

          # re: 《AspectJ Cookbook》讀書筆記十三: 定義通知 2008-08-26 18:05 隔葉黃鶯

          AspectJ 確實很靈活,我很早也看過了這本書,只是實際中寫 aj 文件的機會還沒有,學到相關的知識可運用于 Spring 2.0 的 AspectJ 方式 AOP 相關配置。  回復  更多評論   

          公告


          導航

          <2008年8月>
          272829303112
          3456789
          10111213141516
          17181920212223
          24252627282930
          31123456

          統計

          常用鏈接

          留言簿(4)

          隨筆分類

          隨筆檔案

          收藏夾

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 凤庆县| 东光县| 长寿区| 奈曼旗| 嘉兴市| 绥化市| 绥德县| 缙云县| 瑞安市| 平果县| 平遥县| 南投县| 阿拉尔市| 永嘉县| 新建县| 阳新县| 棋牌| 东乌| 油尖旺区| 旅游| 昌图县| 阿拉善左旗| 长海县| 玉树县| 琼结县| 班戈县| 连平县| 呼和浩特市| 西城区| 临澧县| 木兰县| 西畴县| 平定县| 巴楚县| 邳州市| 民权县| 耒阳市| 安多县| 临夏县| 临城县| 莱州市|