基于AspectJ的Spring AOP Advice执行顺序

数字探秘者
• 阅读 7086

前言

用过Spring做过开发的同学,多少都对Spring的AOP有所了解和使用的经验.也都知道有@Around,@Before,@After等Advice.至于Spring AOP的基本概念,我想大家也都清楚,这里也就不再赘述.

今天在论坛里看到了一个问题,谈到了Spring AOP的Advice执行顺序的问题,看到问题以后,突然发现自己对这方面的理解也不是十分的深入.在回答问题的同时,正好对这个知识点深入的了解一下.

本文基于Spring AspectJ AOP的方式来进行描述.

Spring官方对Advice执行顺序的解释

参考文档:aop-ataspectj-advice-ordering

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 undefined

当同一个Aspect中对同一个Join Point有两个Advice的话,这两个Advice的顺序是不固定的.

实例

首先我们建立一个Spring的工程,然后基于spring-test进行下面的操作.本文的spring版本是:4.3.11.RELEASE

1. 建立一个AuthAnnotation注解类,该注解作用在方法上即可

基于AspectJ的Spring AOP Advice执行顺序

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

<aop:aspectj-autoproxy/>

3. 编写Aspect的Advice,请注意图一红框的方法名

基于AspectJ的Spring AOP Advice执行顺序
基于AspectJ的Spring AOP Advice执行顺序

4. 编写一个Service,符合上面的切入点规则即可

基于AspectJ的Spring AOP Advice执行顺序

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的方法名顺序进行排序的.

基于AspectJ的Spring AOP Advice执行顺序

基于AspectJ的Spring AOP Advice执行顺序

当调用到getAdvisors方法的时候,会调用getAdvisorMethods方法,来获取所有的advice Method对象.同时根据METHOD_COMPARATOR的规则进行排序.

最后的测试

我们修改OrderOneAspect这个类中,checkAuthPackage方法的名字为aCheckAuthPackage,在执行一次单元测试的结果如下:

基于AspectJ的Spring AOP Advice执行顺序

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

输出的结果中,我们可以看到,优先执行的不再是注解方式的PonitCut.由此可见,当同一个Aspect中对同一个Join Point有两个Advice的话,执行的顺序与方法的名称有关.

点赞
收藏
评论区
推荐文章
Spring源码核心剖析
SpringAOP作为Spring最核心的能力之一,其重要性不言而喻。然后需要知道的是AOP并不只是Spring特有的功能,而是一种思想,一种通用的功能。而SpringAOP只是在AOP的基础上将能力集成到SpringIOC中,使其作为bean的一种,从而我们能够很方便的进行使用。
Stella981 Stella981
3年前
Spring Aspect Oriented Programming
  本文是一篇SpringAOP的基础知识分析文章,其中不牵扯源码分析,只包含AOP中重要概念的讲解,分析,以及SpringAOP的用法。    Spring从2.0版本引入了更加简单却强大的基于xml和AspectJ注解的面向切面的编程方式。在深入了解如何用Spring进行面向切面的编程前,我们先了解AOP中的几个重要的基本概念,这几个概念
Easter79 Easter79
3年前
Spring的AOP的注解的通知类型,切入点的注解
Spring的注解的AOP的通知类型@Before:前置通知@AfterReturning:后置通知@Around:环绕通知@AfterThrowing:异常抛出通知@After:最终通知@Pointcut:切入点的注解1/
Wesley13 Wesley13
3年前
Java——基于AspectJ的AOP开发
1.AspectJ简介AspectJ是一个基于Java语言的AOP框架。Spring2.0以后新增了对AdpectJ切点表达式的支持。@AspectJ是AspectJ1.5新增功能,通过JDK5注解技术,允许直接在Bean类中定义切面。新版本Spring框架,建议使用AspectJ方式来开发AOP。使用AspectJ需要导
Easter79 Easter79
3年前
Spring简介,搭建Spring环境——轻量级容器框架(一)
Spring是什么?      Spring是一个集成了许多第三方框架的大杂烩,其核心技术是IOC(控制反转,也称依赖注入)和AOP(面向切面编程),所以spring既是一个IoC容器,也是一个AOP框架。知道了什么是Spring是学习的开端,下面说一下为什么使用Spring。为什么使用Spring?
Easter79 Easter79
3年前
Spring中的AOP(三)——基于Annotation的配置方式(一)
    AspectJ允许使用注解用于定义切面、切入点和增强处理,而Spring框架则可以识别并根据这些注解来生成AOP代理。Spring只是使用了和AspectJ5一样的注解,但并没有使用AspectJ的编译器或者织入器,底层依然使用SpringAOP来实现,依然是在运行时动态生成AOP代理,因此不需要增加额外的编译,也不需要AspectJ的织入器支持。
Stella981 Stella981
3年前
Spring 2.0 的AOP介绍及其通知类型
Spring2.0的AOP在Spring2.0中最激动人心的增强之一是关于SpringAOP,它变得更加便于使用而且更加强大,主要是通过复杂而成熟的AspectJ语言的支持功能来实现,而同时保留纯的基于代理的Java运行时。Spring2.0的AOP提供给我们一种新的思考程序结构的方法,能够解决很多纯OOP无法解决的问题——让我们能够在
Stella981 Stella981
3年前
Spring IOC分析
前言   关于Spring,我想无需做太多的解释了。每个Java程序猿应该都使用过他。Spring的ioc和aop极大的方便了我们的开发,但是Spring又有着不好的一面,为了符合开闭原则,Spring的一个方法可以涉及到好几十个类,从设计上来说,这样的设计易于宽展,职责明确。但从开发角度而言,Spring就像一个迷宫,经常会在里面
Wesley13 Wesley13
3年前
AOP的基本术语
通知、增强(Advice)通知就是你想要的功能,在特定的连接点,AOP框架执行的动作。Spring切面可以应用5种类型的通知:前置通知(Before):在目标方法被调用之前调用通知功能;后置通知(After):在目标方法完成之后调用通知,此时不会关心方法的输出是什么;返回通知(Afterreturni
Spring源码核心剖析 | 京东云技术团队
SpringAOP作为Spring最核心的能力之一,其重要性不言而喻。然后需要知道的是AOP并不只是Spring特有的功能,而是一种思想,一种通用的功能。而SpringAOP只是在AOP的基础上将能力集成到SpringIOC中,使其作为bean的一种,从而我们能够很方便的进行使用。
美凌格栋栋酱 美凌格栋栋酱
5个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(