小結:各種通知的運行順序

小結:各種通知的運行順序

這篇博客主要是來總結一下基於註解配置的AOP,通知的執行順序會有一些小問題。

AOP是通過動態代理實現的,它的大致過程如下:

	advicer.before();
	try{
		target.foo();
		advicer.afterReturning();
	}catch(Exception e){
		advicer.afterThrowing();
		throw new RuntimeException(e);
	}finally{
		advicer.after();
	}

前置通知和最終通知一定會執行,後置通知和異常通知只有一個會執行

所以,運行的順序分爲兩種情況:

正常結束

  1. 前置通知
  2. 切入點方法
  3. 後置通知
  4. 最終通知

異常結束

  1. 前置通知
  2. 切入點方法
  3. 異常通知
  4. 最終通知

驗證XML配置的AOP的運行順序

/**
 * 通知類
 */
@Component
public class Advicer {
    public void beforAdvice(){
        System.out.println("前置通知");
    }

    public void afterReturning(){
        System.out.println("後置通知");
    }

    public void afterThrowing(){
        System.out.println("異常通知");
    }

    public void after(){
        System.out.println("最終通知");
    }
}

/**
 * 目標(被代理)
 */
@Component
public class Target {
    public void foo(){
        System.out.println("Target.foo()");
    }
}
    <aop:config>
        <aop:aspect id="aspect" ref="advicer">
            <aop:pointcut id="pointcut" expression="execution(* aop.test.basedAnno.Target.foo())"/>
            <aop:before method="beforAdvice" pointcut-ref="pointcut"></aop:before>
            <aop:after-returning method="afterReturning" pointcut-ref="pointcut"></aop:after-returning>
            <aop:after-throwing method="afterThrowing" pointcut-ref="pointcut"></aop:after-throwing>
            <aop:after method="after" pointcut-ref="pointcut"></aop:after>
        </aop:aspect>
        
    </aop:config>

  public void runTarget(){
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        Target t = (Target) context.getBean("target");
        t.foo();
    }

運行結果:
(正常退出)
在這裏插入圖片描述

(異常退出)
在這裏插入圖片描述

可以看到,和前面的預計順序是相同的

驗證註解配置的AOP的運行順序

@Component
@Aspect
public class Advicer {

    @Pointcut("execution(* aop.test.basedAnno.Target.foo(..))")
    private void pointcutFoo(){}

    @Before("pointcutFoo()")
    public void beforAdvice(){
        System.out.println("前置通知");
    }

    @AfterReturning("pointcutFoo()")
    public void afterReturning(){
        System.out.println("後置通知");
    }

    @AfterThrowing("pointcutFoo()")
    public void afterThrowing(){
        System.out.println("異常通知");
    }

    @After("pointcutFoo()")
    public void after(){
        System.out.println("最終通知");
    }
}


運行結果:
(正常退出)
在這裏插入圖片描述

(異常退出)
在這裏插入圖片描述

可以看到,這裏的順序除了一些問題,最終通知會提前到後置通知/異常通知之前執行

關於環繞通知

環繞通知是將切入點方法替換爲另一個方法,所以關於各種通知的執行順序,由編碼實現,所以基於XML和基於註解的環繞通知,執行的結果沒有變化。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章