程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> spring學習筆記(10)@AspectJ研磨分析[3]增強織入順序實例詳解

spring學習筆記(10)@AspectJ研磨分析[3]增強織入順序實例詳解

編輯:JAVA綜合教程

spring學習筆記(10)@AspectJ研磨分析[3]增強織入順序實例詳解


增強的織入順序

當一個連接點同時織入多個增強時,就存在順序調用問題:
1. 增強在同一個切面類中定義:依照增強在切面類中定義的順序依次織入。
2. 增強位於不同的切面,但果這些切面都實現了org.springframework.core.Ordered
接口,則由接口注解的順序號決定,順序號越小,對於不同的增強,織入順序為:
1. 前置增強->越先織入
2. 後置增強->越後織入
3. 最終增強->越後織入
4. 環繞增強->調用原方法之前的部分先織入,調用原方法之後的部分後織入
我們先來看一個實例:

1.目標對象

package test.aop2;

public class UserController {
    public void login(String name){
        System.out.println("I'm "+name+" ,I'm logining");
    }
}

2. 切面配置

/*-----------------------有序切面類1--------------------------*/
@Aspect
public class Annotation_aspect implements Ordered {//實現順序接口

    @Pointcut("target(test.aop2.UserController)")
    private void pointcut(){}//定義切點

    @AfterThrowing("pointcut()")//後置增強
    public void AfterThrowing() throws Throwable{
        System.out.println("Annotation_aspect 實施AfterThrowing,優先級為" + getOrder());
    }
    @After("pointcut()")//最終增強
    public void after() throws Throwable{
        System.out.println("Annotation_aspect 實施after,優先級為" + getOrder());
    }
    @Before("pointcut()")//前置增強
    public void before() throws Throwable{
        System.out.println("Annotation_aspect 實施@before,優先級為" + getOrder());
    }
    @Around("pointcut()")//環繞增強
    public void around(ProceedingJoinPoint joinPoint) throws Throwable{
        System.out.println("Annotation_aspect 實施around前,優先級為" + getOrder());
        joinPoint.proceed();
        System.out.println("Annotation_aspect 實施around後,優先級為" + getOrder());
    }

    @Override
    public int getOrder() {
        return 1;
    }

}
/*-----------------------有序切面類2--------------------------*/
@Aspect
public class Annotation_aspect2 implements Ordered {

    @Pointcut("target(test.aop2.UserController)")
    private void pointcut(){}


    @AfterThrowing("pointcut()")
    public void AfterThrowing() throws Throwable{
        System.out.println("Annotation_aspect2 實施AfterThrowing,優先級為" + getOrder());
    }
    @After("pointcut()")
    public void after() throws Throwable{
        System.out.println("Annotation_aspect2 實施after,優先級為" + getOrder());
    }
    @Before("pointcut()")
    public void before() throws Throwable{
        System.out.println("Annotation_aspect2 實施@before,優先級為" + getOrder());
    }
    @Around("pointcut()")
    public void around(ProceedingJoinPoint joinPoint) throws Throwable{
        System.out.println("Annotation_aspect2 實施around前,優先級為" + getOrder());
        joinPoint.proceed();
        System.out.println("Annotation_aspect2 實施around後,優先級為" + getOrder());
    }

    @Override
    public int getOrder() {
        return 2;
    }


}
/*-----------------------無序切面類1--------------------------*/
@Aspect
public class noOrder_aspect {

    @Pointcut("target(test.aop2.UserController)")
    private void pointcut(){}


    @AfterThrowing("pointcut()")
    public void AfterThrowing() throws Throwable{
        System.out.println("noOrder_aspect 實施AfterThrowing,無優先級");
    }
    @After("pointcut()")
    public void after() throws Throwable{
        System.out.println("noOrder_aspect 實施after,無優先級");
    }
    @Before("pointcut()")
    public void before() throws Throwable{
        System.out.println("noOrder_aspect 實施@before,無優先級");
    }
    @Around("pointcut()")
    public void around(ProceedingJoinPoint joinPoint) throws Throwable{
        System.out.println("noOrder_aspect 實施around前,無優先級");
        joinPoint.proceed();
        System.out.println("noOrder_aspect 實施around後,無優先級");
    }
}
/*-----------------------無序切面類2--------------------------*/
@Aspect
public class noOrder_aspect2 {

    @Pointcut("target(test.aop2.UserController)")
    private void pointcut(){}


    @AfterThrowing("pointcut()")
    public void AfterThrowing() throws Throwable{
        System.out.println("noOrder_aspect2 實施AfterThrowing,無優先級");
    }
    @After("pointcut()")
    public void after() throws Throwable{
        System.out.println("noOrder_aspect2 實施after,無優先級");
    }
    @Before("pointcut()")
    public void before() throws Throwable{
        System.out.println("noOrder_aspect2 實施@before,無優先級");
    }
    @Around("pointcut()")
    public void around(ProceedingJoinPoint joinPoint) throws Throwable{
        System.out.println("noOrder_aspect1 實施around前,無優先級");
        joinPoint.proceed();
        System.out.println("noOrder_aspect1 實施around後,無優先級");
    }

}

3. IOC容器配置

   




4. 測試方法

public static void main(String args[]) throws Exception{
    ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:test/aop2/aop.xml");
    UserController userController = (UserController) ac.getBean("userController");
    User user = new User();
    userController.login("zenghao");
}

運行測試方法,控制台輸出:

Annotation_aspect 實施around前,優先級為1
Annotation_aspect 實施@before,優先級為1
Annotation_aspect2 實施around前,優先級為2
Annotation_aspect2 實施@before,優先級為2
noOrder_aspect 實施around前,無優先級
noOrder_aspect 實施@before,無優先級
noOrder_aspect1 實施around前,無優先級
noOrder_aspect2 實施@before,無優先級
I’m zenghao ,I’m logining
noOrder_aspect1 實施around後,無優先級
noOrder_aspect2 實施after,無優先級
noOrder_aspect2 實施AfterReturning,無優先級
noOrder_aspect 實施around後,無優先級
noOrder_aspect 實施after,無優先級
noOrder_aspect 實施AfterReturning,無優先級
Annotation_aspect2 實施around後,優先級為2
Annotation_aspect2 實施after,優先級為2
Annotation_aspect2 實施AfterReturning,優先級為2
Annotation_aspect 實施around後,優先級為1
Annotation_aspect 實施after,優先級為1
Annotation_aspect 實施AfterReturning,優先級為1

針對以上信息,我們再復述前面結論來對比看,是完全符合的,順序號越小,對於不同的增強,織入順序為:
1. 前置增強->越先織入
2. 後置增強->越後織入
3. 最終增強->越後織入
4. 環繞增強->調用原方法之前的部分先織入,調用原方法之後的部分後織入

認真觀察,我們還會發現:
1. 同一切面中,不同增強的織入順序為:環繞增強前半部分->前置增強->元目標函數調用->環繞增強後半部分->最終增強->後置增強。
2. 沒有實現order接口的“優先級”總是低於實現了order接口的,如針對前置增強來看,順序為:
Annotation_aspect > Annotation_aspect2 > noOrder_aspect > noOrder_aspect
3. 先觀察無序接口,我們會發現noOrder_aspect的優先級總是高於noOrder_aspect2的優先級,這是有前面IOC容器中前面Bean的配置順序決定的:




那麼,對於同樣實現了order接口的切面,它們是否也滿足這個規律呢?我們把Annotation_aspect2的優先級也設為1,然後運行測試函數,打印信息如下:
Annotation_aspect2 實施around前,優先級為1
Annotation_aspect2 實施@before,優先級為1
Annotation_aspect 實施around前,優先級為1
Annotation_aspect 實施@before,優先級為1
noOrder_aspect 實施around前,無優先級
noOrder_aspect 實施@before,無優先級
noOrder_aspect1 實施around前,無優先級
noOrder_aspect2 實施@before,無優先級
I’m zenghao ,I’m logining
noOrder_aspect1 實施around後,無優先級
noOrder_aspect2 實施after,無優先級
noOrder_aspect2 實施AfterReturning,無優先級
noOrder_aspect 實施around後,無優先級
noOrder_aspect 實施after,無優先級
noOrder_aspect 實施AfterReturning,無優先級
Annotation_aspect 實施around後,優先級為1
Annotation_aspect 實施after,優先級為1
Annotation_aspect 實施AfterReturning,優先級為1
Annotation_aspect2 實施around後,優先級為1
Annotation_aspect2 實施after,優先級為1
Annotation_aspect2 實施AfterReturning,優先級為1

關注粗體部分,是不是優先級和IOC容器的配置順序對應上了,感興趣的同學可以把兩個沒有實現order接口的配置順序也交換一下,觀察它們的織入優先級是否也跟著變化了。

除了實現org.springframework.core.Ordered配置順序外,我們還可以使用注解@org.springframework.core.annotation.Order(優先級整數)來實現同樣的效果。在這裡,如果既使用注解,又使用接口實現的,且它們的優先級一致時,一樣是看IOC容器的bean順序,如:





其中Annotation_aspect3和Annotation_aspect4的類定義頭部為:

@Aspect
@Order(1)
public class Annotation_aspect3{
....
}
@Aspect
@Order(2)
public class Annotation_aspect4{
....
}

注釋再次運行測試程序,得到打印信息:

Annotation_aspect3 實施around前,注解優先級為1
Annotation_aspect3 實施@before,注解優先級為1
Annotation_aspect 實施around前,優先級為1
Annotation_aspect 實施@before,優先級為1
Annotation_aspect4 實施around前,注解優先級為2
Annotation_aspect4 實施@before,注解優先級為2
Annotation_aspect2 實施around前,優先級為2
Annotation_aspect2 實施@before,優先級為2
I’m zenghao ,I’m logining
Annotation_aspect2 實施around後,優先級為2
Annotation_aspect2 實施after,優先級為2
Annotation_aspect2 實施AfterReturning,優先級為2
Annotation_aspect4 實施around後,注解優先級為2
Annotation_aspect4 實施after,注解優先級為2
Annotation_aspect4 實施AfterReturning,注解優先級為2
Annotation_aspect 實施around後,優先級為1
Annotation_aspect 實施after,優先級為1
Annotation_aspect 實施AfterReturning,優先級為1
Annotation_aspect3 實施around後,注解優先級為1
Annotation_aspect3 實施after,注解優先級為1
Annotation_aspect3 實施AfterReturning,注解優先級為1
觀察IOC容器的配置順序,這裡也是對應上的。
綜上,我們得到結論:多個同一類型的增強(如都是前置增強)對同一連接點的織入順序是:配置有優先級看誰優先級高,優先級相同則看誰先在IOC容器注冊,配置了order接口或注釋的增強優先級總是高於沒配置的。

通過以上分析,我們能夠較好地總結出我們常用增強對應各種情況的織入順序。在了解這些織入順序後,有助於我們更靈活地將AOP運用到我們的項目中。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved