用过Spring作过开发的同窗,多少都对Spring的AOP有所了解和使用的经验.也都知道有@Around,@Before,@After等Advice.至于Spring AOP的基本概念,我想你们也都清楚,这里也就再也不赘述.html
今天在论坛里看到了一个问题,谈到了Spring AOP的Advice执行顺序的问题,看到问题之后,忽然发现本身对这方面的理解也不是十分的深刻.在回答问题的同时,正好对这个知识点深刻的了解一下.spring
本文基于Spring AspectJ AOP的方式来进行描述.less
参考文档: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
2. 在spring的配置中添加aspect aop支持
<aop:aspectj-autoproxy/>
3. 编写Aspect的Advice,请注意图一红框的方法名
4. 编写一个Service,符合上面的切入点规则便可
5. 执行单元测试,调用TestService.test()方法,输出结果以下
----Order1:checkAuth:Annotation---- ----Order1:checkAuthPackage:Execution---- ----Order2:checkAuthPackage:Execution---- ---Service:Test---
屡次运行之后,咱们会发现一个问题,就是Order1的checkAuth方法一直是第一个执行.这是否是说明,以注解方式的PointCut是否是会有首先执行的优先级?
若是是的话,这就不符合上面Spring官方文档的说法了.来让咱们看看为何?
该类的做用是基于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的方法名顺序进行排序的.
当调用到getAdvisors方法的时候,会调用getAdvisorMethods方法,来获取全部的advice Method对象.同时根据METHOD_COMPARATOR的规则进行排序.
咱们修改OrderOneAspect这个类中,checkAuthPackage方法的名字为aCheckAuthPackage,在执行一次单元测试的结果以下:
----Order1:checkAuthPackage:Execution---- ----Order1:checkAuth:Annotation---- ----Order2:checkAuthPackage:Execution---- ---Service:Test---
输出的结果中,咱们能够看到,优先执行的再也不是注解方式的PonitCut.因而可知,当同一个Aspect中对同一个Join Point有两个Advice的话,执行的顺序与方法的名称有关.