AspectJ 基礎用法

引貼:java

  Aspectj與Spring AOP比較
  AspectJ語法詳解 
 Spring中的AOP(五)——在Advice方法中獲取目標方法的參數spring

配置方法

  1. < aop:aspect>:定義切面(切面包括通知和切點), 只須要定義通常的bean就行。
    //定義切面
    public class SleepHelperAspect{
        public void beforeSleep(){
            System.out.println("睡覺前要脫衣服!");
        }
    
        public void afterSleep(){
            System.out.println("起牀後要穿衣服!");
        }
    }
    <bean id="sleepHelperAspect" class="com.ghs.aop.SleepHelperAspect"></bean>
    
    <aop:aspectj-autoproxy/>
    <aop:config>
    <aop:pointcut expression="execution(* *.sleep(..))" id="sleepPointcut"/>
    <aop:aspect ref="sleepHelperAspect">
    <!--前置通知-->
    <aop:before method="beforeSleep" pointcut-ref="sleepPointcut"/>
    <!--後置通知-->
    <aop:after method="afterSleep" pointcut-ref="sleepPointcut"/>
    </aop:aspect>
    </aop:config>
  2. < aop:advisor>:定義通知器(通知器跟切面同樣,也包括通知(advice)和切點(PointCut)),通知必須實現Advice接口。
    //定義通知
    public class SleepHelper implements MethodBeforeAdvice,AfterReturningAdvice{
        @Override
        public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
            System.out.println("睡覺前要脫衣服!");
        }
    
        @Override
        public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable {
            System.out.println("起牀後要穿衣服!");
        }
    }
    <bean id="sleepHelper" class="com.noob.aop.SleepHelper"></bean>
    
    <aop:aspectj-autoproxy/>
    <aop:config>
       <aop:pointcut expression="execution(* *.sleep(..))" id="sleepPointcut"/>
       <aop:advisor advice-ref="sleepHelper" pointcut-ref="sleepPointcut"/>
    </aop:config>

基本概念

  1. Advice(通知、切面): 某個鏈接點所採用的處理邏輯,也就是向鏈接點注入的代碼, AOP在特定的切入點上執行的加強處理。
    1. @Before: 標識一個前置加強方法,至關於BeforeAdvice的功能.
    2. @After: final加強,無論是拋出異常或者正常退出都會執行.
    3. @AfterReturning:  後置加強,似於AfterReturningAdvice, 方法正常退出時執行.
    4. @AfterThrowing:  異常拋出加強,至關於ThrowsAdvice.
    5. @Around: 環繞加強,至關於MethodInterceptor.
  2. JointPoint(鏈接點):程序運行中的某個階段點,好比方法的調用、異常的拋出等。
  3. Pointcut(切入點):   JoinPoint的集合,是程序中須要注入Advice的位置的集合,指明Advice要在什麼樣的條件下才能被觸發,在程序中主要體現爲書寫切入點表達式。
  4. Advisor(加強): PointCut和Advice的綜合體,完整描述了一個advice將會在pointcut所定義的位置被觸發
  5. @Aspect(切面):  一般是一個類的註解,類中能夠定義切入點和通知
  6. AOP Proxy:AOP框架建立的對象,代理就是目標對象的增強。Spring中的AOP代理可使JDK動態代理,也能夠是CGLIB代理,前者基於接口,後者基於子類。

Pointcut

表示式(expression)和簽名(signature)express

//Pointcut表示式
@Pointcut("execution(* com.savage.aop.MessageSender.*(..))")
//Point簽名
private void log(){}

由下列方式來定義或者經過 &&、 ||、 !、 的方式進行組合:框架

  • execution:用於匹配方法執行的鏈接點;ide

  • within:用於匹配指定類型內的方法執行;this

  • this:用於匹配當前AOP代理對象類型的執行方法;注意是AOP代理對象的類型匹配,這樣就可能包括引入接口也類型匹配;        spa

  • target:用於匹配當前目標對象類型的執行方法;注意是目標對象的類型匹配,這樣就不包括引入接口也類型匹配;.net

  • args:用於匹配當前執行的方法傳入的參數爲指定類型的執行方法;3d

  • @within:用於匹配因此持有指定註解類型內的方法;代理

  • @target:用於匹配當前目標對象類型的執行方法,其中目標對象持有指定的註解;

  • @args:用於匹配當前執行的方法傳入的參數持有指定註解的執行;

  • @annotation:用於匹配當前執行方法持有指定註解的方法;

格式

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)throws-pattern?)

其中後面跟着「?」的是可選項

括號中各個pattern分別表示:

  • 修飾符匹配(modifier-pattern?)
  • 返回值匹配(ret-type-pattern):   能夠爲*表示任何返回值, 全路徑的類名等
  • 類路徑匹配(declaring-type-pattern?)
  • 方法名匹配(name-pattern):能夠指定方法名 或者 *表明全部, set* 表明以set開頭的全部方法
  • 參數匹配((param-pattern)):能夠指定具體的參數類型。多個參數間用「,」隔開,各個參數也能夠用"*" 來表示匹配任意類型的參數,".."表示零個或多個任意參數。
    eg. (String)表示匹配一個String參數的方法;(*,String) 表示匹配有兩個參數的方法,第一個參數能夠是任意類型,而第二個參數是String類型。
  • 異常類型匹配(throws-pattern?)

eg.

  • 任意公共方法的執行:execution(public * *(..))
  • 任何一個以「set」開始的方法的執行:execution(* set*(..))
  • AccountService 接口的任意方法的執行:execution(* com.xyz.service.AccountService.*(..))
  • 定義在service包裏的任意方法的執行: execution(* com.xyz.service.*.*(..))
  • 定義在service包和全部子包裏的任意類的任意方法的執行:execution(* com.xyz.service..*.*(..))
    第一個*表示匹配任意的方法返回值, ..(兩個點)表示零個或多個,第一個..表示service包及其子包,第二個*表示全部類, 第三個*表示全部方法,第二個..表示方法的任意參數個數
  • 定義在pointcutexp包和全部子包裏的JoinPointObjP2類的任意方法的執行:execution(* com.test.spring.aop.pointcutexp..JoinPointObjP2.*(..))")
  • pointcutexp包裏的任意類: within(com.test.spring.aop.pointcutexp.*)
  • pointcutexp包和全部子包裏的任意類:within(com.test.spring.aop.pointcutexp..*)
  • 實現了Intf接口的全部類,若是Intf不是接口,限定Intf單個類:this(com.test.spring.aop.pointcutexp.Intf)
    當一個實現了接口的類被AOP的時候,用getBean方法必須cast爲接口類型,不能爲該類的類型
  • 帶有@Transactional標註的全部類的任意方法: 
    • @within(org.springframework.transaction.annotation.Transactional)
    • @target(org.springframework.transaction.annotation.Transactional)
  • 帶有@Transactional標註的任意方法:@annotation(org.springframework.transaction.annotation.Transactional)
    @within和@target針對類的註解,@annotation是針對方法的註解
  • 參數帶有@Transactional標註的方法:@args(org.springframework.transaction.annotation.Transactional)
  • 參數爲String類型(運行是決定)的方法: args(String)

JoinPoint

當使用@Around處理時,須要將第一個參數定義爲ProceedingJoinPoint類型,該類是JoinPoint的子類。

經常使用的方法:

  • Object[] getArgs:返回目標方法的參數
  • Signature getSignature:返回目標方法的簽名
  • Object getTarget:返回被織入加強處理的目標對象
  • Object getThis:返回AOP框架爲目標對象生成的代理對象

織入

@AfterReturning(
            pointcut="execution(* com.abc.service.*.access*(..)) && args(time, name)",
            returning="returnValue")
    public void access(Date time, Object returnValue, String name) {
        System.out.println("目標方法中的參數String = " + name);
        System.out.println("目標方法中的參數Date = " + time);
        System.out.println("目標方法的返回結果returnValue = " + returnValue);
    }

表達式中增長了args(time, name)部分,意味着能夠在加強處理的簽名方法(access方法)中定義"time"和"name"兩個同名屬性。
這兩個形參的類型由access方法同名參數類型指定,一旦指定了, 則這兩個形參類型將用於限制該切入點只匹配第一個參數類型爲Date,第二個參數類型爲String的方法(方法參數個數和類型如有不一樣均不匹配);
access方法只須要知足"time", "name"參數的順序和pointcut中args(time, name)的順序相同便可,"returnValue"位置順序無所謂。 

eg.

//將被access方法匹配
public String accessAdvice(Date d, String n) {
    System.out.println("方法:accessAdvice");
    return "aa";
}

切面執行順序

一個方法只被一個Aspect類攔截

正常:

one-ok

異常:
one-exception

同一個方法被多個Aspect類攔截

優先級高的切面類裏的加強處理的優先級老是比優先級低的切面類中的加強處理的優先級高。       
在「進入」鏈接點時,最高優先級的加強處理將先被織入(eg.給定的兩個不一樣切面類Before加強處理中,優先級高的那個會先執行);在「退出」鏈接點時,最高優先級的加強處理會最後被織入(eg.給定的兩個不一樣切面類After加強處理中,優先級高的那個會後執行)。

eg.

優先級爲1的切面類Bean1包含了@Before,優先級爲2的切面類Bean2包含了@Around,雖然@Around優先級高於@Before,但因爲Bean1的優先級高於Bean2的優先級,所以Bean1中的@Before先被織入。
Spring提供了以下兩種解決方案指定不一樣切面類裏的加強處理的優先級:

  1. 讓切面類實現org.springframework.core.Ordered接口:實現該接口的int getOrder()方法,該方法返回值越小,優先級越高
  2. 直接使用@Order註解來修飾一個切面類:使用這個註解時能夠配置一個int類型的value屬性,該屬性值越小,優先級越高

同一個切面類裏的兩個相同類型的加強處理在同一個鏈接點被織入時,Spring AOP將以隨機的順序來織入這兩個加強處理,沒有辦法指定它們的織入順序。即便給這兩個 advice 添加了 @Order 這個註解,也不行!

相關文章
相關標籤/搜索