使用spring框架的時候,用aop需要控制自己寫的切面的順序,例如如下切面代碼:
@Aspect
@Order(-1) //會先掃描註解的值,如果註解的值找不到,再找getOrder()的值
public class AspectJOrderLow implements Ordered {
@Pointcut("execution(* *.test(..))")
public void testPointcut() {
}
@Before("testPointcut()")
public void beforeTest() {
System.out.println("trigger [before] in " + AspectJOrderLow.class.getName());
}
@Order(-100) //同一切點的同一類型通知方法,例如Before,這個Order註解沒用,根據方法字母序決定執行先後順序
@Before("testPointcut()")
public void beforeTest() {
System.out.println("trigger [before] in " + AspectJOrderLow.class.getName());
}
@After("testPointcut()")
public void afterTest() {
System.out.println("trigger [after] in " + AspectJOrderLow.class.getName());
}
@Around("testPointcut()")
public Object aroundTest(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("trigger [beforeAround] in " + AspectJOrderLow.class.getName());
Object o = pjp.proceed();
System.out.println("trigger [afterAround] in " + AspectJOrderLow.class.getName());
return o;
}
@Override
public int getOrder() {
return 0; //這裏返回的執行的順序,數字越小,優先級越高範圍Integer
}
}
@Aspect
public class AspectJOrderHigh implements Ordered {
@Pointcut("execution(* *.test(..))")
public void testPointcut() {
}
@Before("testPointcut()")
public void beforeTest() {
System.out.println("trigger [before] in " + AspectJOrderHigh.class.getName());
}
@After("testPointcut()")
public void afterTest() {
System.out.println("trigger [after] in " + AspectJOrderHigh.class.getName());
}
@Around("testPointcut()")
public Object aroundTest(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("trigger beforeAround in " + AspectJOrderHigh.class.getName());
Object o = pjp.proceed();
System.out.println("trigger afterAround in " + AspectJOrderHigh.class.getName());
return o;
}
@Override
public int getOrder() {
return 0;
}
}
public class TestOrder {
private String testStr = "testOrder";
public String getTestStr() {
return testStr;
}
public void setTestStr(String testStr) {
this.testStr = testStr;
}
public void test() {
System.out.println(this.testStr);
}
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("aopOrder.xml");
TestOrder bean = (TestOrder) ac.getBean("testOrder");
bean.test();
}
}
testOrder.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">
<!-- AOP配置 -->
<aop:aspectj-autoproxy/>
<bean class="com.stpice.spring.demo.aop.order.AspectJOrderHigh"/>
<bean class="com.stpice.spring.demo.aop.order.AspectJOrderLow"/>
<bean id="testOrder" class="com.stpice.spring.demo.aop.order.TestOrder"/>
</beans>
定義了兩個切面類,TestOrder
是切面織入的目標類,testOrder.xml
是配置文件。運行後打印出來如下的內容,可以看到高低優先級不同的切面中的before、after、around切面的執行順序如下。
trigger beforeAround in com.stpice.spring.demo.aop.order.AspectJOrderHigh
trigger [before] in com.stpice.spring.demo.aop.order.AspectJOrderHigh
trigger [beforeAround] in com.stpice.spring.demo.aop.order.AspectJOrderLow
trigger [before] in com.stpice.spring.demo.aop.order.AspectJOrderLow
testOrder
trigger [afterAround] in com.stpice.spring.demo.aop.order.AspectJOrderLow
trigger [after] in com.stpice.spring.demo.aop.order.AspectJOrderLow
trigger afterAround in com.stpice.spring.demo.aop.order.AspectJOrderHigh
trigger [after] in com.stpice.spring.demo.aop.order.AspectJOrderHigh
因爲目前在兩個切面AspectJOrderHigh
和AspectJOrderLow
中覆寫的getOrder
方法中返回的是0,就是還沒有顯式的指定不同的順序,所以,根據跟蹤源碼,可以發現在order相同的情況下, 是根據切面類的名稱字母序進行優先級控制的,字母序越靠前,優先級越高。字母序的比較,首先將類名轉換爲字符串,然後調用String
的compareTo()
方法,對兩個類名進行比對,決定切面的排序的。如果切面類使用了@Order
註解或者是實現了Ordered
接口,那麼可以在比對的時候自動調用getOrder()
的方法,然後比較返回的值大小,值越小,優先級越高
。同一個切面類中的方法,如果有多個不同的切入方式,例如@Around,@Before,@After,@AfterReturning,@AfterThrowing
,那麼會先掃描出各個方法上的註解,對不同的方法按照上邊註解的順序進行排序,然後按照字母序進行排序,所以最終呈現出來的,同一個切面類中的不同切面方法的執行順序,就會呈現如上所示的狀態。