使用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
,那么会先扫描出各个方法上的注解,对不同的方法按照上边注解的顺序进行排序,然后按照字母序进行排序,所以最终呈现出来的,同一个切面类中的不同切面方法的执行顺序,就会呈现如上所示的状态。