最愛Java

          書山有路勤為徑,學(xué)海無涯苦作舟

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

          二.訪問連接點環(huán)境
                  AspectJ提供了thisJoinPoint變量,用于展示this連接點環(huán)境。如果可以靜態(tài)地訪問正在訪問的環(huán)境,那么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變量包含關(guān)于觸發(fā)連接點的靜態(tài)和動態(tài)環(huán)境信息。靜態(tài)環(huán)境信息包含可以在編譯和織入時決定的任何信息。動態(tài)連接點環(huán)境信息則只能在運行時填充,因為它依賴于連接點環(huán)境實際的運行時狀態(tài)。

          三.在連接點之前執(zhí)行通知
                  使用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(
          "-----------------------------------------");        
              }

          }


          四.在連接點周圍執(zhí)行通知
                  使用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()通知是一種強大的構(gòu)造,它指示AspectJ應(yīng)該運行通知,而不是指示連接點觸發(fā)它。這允許重寫應(yīng)用程序中存在的原始邏輯。這說明了around()通知,可以依據(jù)是否從around()通知塊內(nèi)發(fā)起proceed()調(diào)用,來被動或主動地應(yīng)用這個通知。
                  proceed()調(diào)用指示around()通知應(yīng)該繼續(xù)執(zhí)行原始連接點邏輯,并傳遞原來可用的任何值。
          在示例中,第一份通知沒有參數(shù)需要傳遞;第二份通知傳遞了一個與原始值完全不同的值;第三份通知則完全返回了一個不同的值。
                  around()通知必須具有指定的返回值,但是如果不需要值,那么可以是void。

          五.在連接點之后無條件執(zhí)行通知
                  使用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(
          "-----------------------------------------");        
              }

          }


          六.僅在從連接點正常返回之后才執(zhí)行通知
                  使用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類的一個實例中,以傳遞給通知。當(dāng)通知期待的返回類型是Object類型時,并且如果返回值是基本類型,AspectJ將自動并且透明地把基本值裝箱進其對應(yīng)的Java類中。around()形式的通知也可以使用這種自動和透明的裝箱行為,其中會期待Object類型的值,并且將從通知傳遞基本值或?qū)⒒局祩鬟f給通知。
          與正常的ater()相比,after() returning形式的通知提供了更精細(xì)的過濾器。

          七.僅當(dāng)連接點中引發(fā)了一個異常之后才執(zhí)行通知
                  使用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(
          "-----------------------------------------");        
              }

          }


          八.控制通知優(yōu)先級
                  如果把位于不同方面中的相同類型的通知應(yīng)用同一連接點,則可以使用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,以根據(jù)需要為特定的方面集合或方面的整個包指示優(yōu)先級。
          當(dāng)把一個方面中的兩個相同類型的通知塊應(yīng)用于同一個連接點時,declare precedence語句就沒有意義了。為了處理這種情況,AspectJ基于方面聲明內(nèi)通知的類型和位置,來應(yīng)用隱式的優(yōu)先級次序:
          • 按在方面中聲明before()和around()通知類型的次序,來應(yīng)用他們隱式優(yōu)先級規(guī)則。如果把同一方面的兩個before()通知塊應(yīng)用于同一個連接點,那么聲明第一個塊將具有最高的優(yōu)先級,而最后一個則最低。
          • 而after()、aftr() returning和around() throwing通知類型的隱式優(yōu)先級則于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 閱讀(1560) 評論(1)  編輯  收藏 所屬分類: 《AspectJ Cookbook》讀書筆記

          評論

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

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

          公告


          導(dǎo)航

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

          統(tǒng)計

          常用鏈接

          留言簿(4)

          隨筆分類

          隨筆檔案

          收藏夾

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 乐都县| 夏津县| 大安市| 惠安县| 克山县| 呼图壁县| 百色市| 临高县| 沙雅县| 兴化市| 农安县| 图们市| 民权县| 宁阳县| 芜湖县| 瓦房店市| 谢通门县| 道孚县| 平顺县| 宜良县| 宣城市| 台南市| 时尚| 仪陇县| 宿松县| 青神县| 石河子市| 阜阳市| 麻栗坡县| 卓资县| 武义县| 德令哈市| 新绛县| 高青县| 汝南县| 新津县| 福泉市| 波密县| 从江县| 鄂州市| 平湖市|