基於AspectJ的Spring AOP Advice執行順序

前言

用過Spring作過開發的同窗,多少都對Spring的AOP有所瞭解和使用的經驗.也都知道有@Around,@Before,@After等Advice.至於Spring AOP的基本概念,我想你們也都清楚,這裏也就再也不贅述.html

今天在論壇裏看到了一個問題,談到了Spring AOP的Advice執行順序的問題,看到問題之後,忽然發現本身對這方面的理解也不是十分的深刻.在回答問題的同時,正好對這個知識點深刻的瞭解一下.spring

本文基於Spring AspectJ AOP的方式來進行描述.less

Spring官方對Advice執行順序的解釋

參考文檔:aop-ataspectj-advice-orderingide

When two pieces of advice defined in different aspects both need to run at the same join point, unless you specify otherwise the order of execution is undefined. You can control the order of execution by specifying precedence. This is done in the normal Spring way by either implementing the org.springframework.core.Ordered interface in the aspect class or annotating it with the Order annotation. Given two aspects, the aspect returning the lower value from Ordered.getValue() (or the annotation value) has the higher precedence.單元測試

上面的內容簡單的說就是,當對於同一個Join Point有兩個Advice定義在不一樣的Aspect中的時候,他們的執行順序是根據Aspect類的@Order註解的值,或者經過實現Order並重寫getValue方法的值來決定的.同時,Order的值越小,優先級越高.測試

When two pieces of advice defined in the same aspect both need to run at the same join point, the ordering is undefinedspa

當同一個Aspect中對同一個Join Point有兩個Advice的話,這兩個Advice的順序是不固定的.3d

實例

首先咱們創建一個Spring的工程,而後基於spring-test進行下面的操做.本文的spring版本是:4.3.11.RELEASEcode

1. 創建一個AuthAnnotation註解類,該註解做用在方法上便可orm

clipboard.png

2. 在spring的配置中添加aspect aop支持

<aop:aspectj-autoproxy/>

3. 編寫Aspect的Advice,請注意圖一紅框的方法名

clipboard.png
clipboard.png

4. 編寫一個Service,符合上面的切入點規則便可

clipboard.png

5. 執行單元測試,調用TestService.test()方法,輸出結果以下

----Order1:checkAuth:Annotation----
----Order1:checkAuthPackage:Execution----
----Order2:checkAuthPackage:Execution----
---Service:Test---

屢次運行之後,咱們會發現一個問題,就是Order1的checkAuth方法一直是第一個執行.這是否是說明,以註解方式的PointCut是否是會有首先執行的優先級?
若是是的話,這就不符合上面Spring官方文檔的說法了.來讓咱們看看爲何?

ReflectiveAspectJAdvisorFactory

該類的做用是基於AspectJ時,建立Spring AOP的Advice.

static {
        CompoundComparator<Method> comparator = new CompoundComparator<Method>();
        comparator.addComparator(new ConvertingComparator<Method, Annotation>(
                new InstanceComparator<Annotation>(
                        Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class),
                new Converter<Method, Annotation>() {
                    @Override
                    public Annotation convert(Method method) {
                        AspectJAnnotation<?> annotation =
                                AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method);
                        return (annotation != null ? annotation.getAnnotation() : null);
                    }
                }));
        comparator.addComparator(new ConvertingComparator<Method, String>(
                new Converter<Method, String>() {
                    @Override
                    public String convert(Method method) {
                        return method.getName();
                    }
                }));
        METHOD_COMPARATOR = comparator;
    }

從該類的靜態方法塊中咱們能夠看到,Advice列表的添加順序是按照Around/Before/After/AfterReturning/AfterThrowing的順序,同時根據Advice的方法名順序進行排序的.

clipboard.png

clipboard.png

當調用到getAdvisors方法的時候,會調用getAdvisorMethods方法,來獲取全部的advice Method對象.同時根據METHOD_COMPARATOR的規則進行排序.

最後的測試

咱們修改OrderOneAspect這個類中,checkAuthPackage方法的名字爲aCheckAuthPackage,在執行一次單元測試的結果以下:

clipboard.png

----Order1:checkAuthPackage:Execution----
----Order1:checkAuth:Annotation----
----Order2:checkAuthPackage:Execution----
---Service:Test---

輸出的結果中,咱們能夠看到,優先執行的再也不是註解方式的PonitCut.因而可知,當同一個Aspect中對同一個Join Point有兩個Advice的話,執行的順序與方法的名稱有關.

相關文章
相關標籤/搜索