首页  

多个AOP切面注解 执行顺序说明     所属分类 spring 浏览量 23
在 Spring AOP 中,同一个方法上多个 AOP 注解的执行顺序取决于注解类型、切面类的定义以及是否显式指定优先级 

1. 同一类型注解的执行顺序
场景:多个相同类型的 AOP 注解(如多个 @Before)  
默认顺序:按切面类的 声明顺序 执行(Spring 默认按字母顺序排序类名)  
显式控制顺序:使用 @Order 注解指定优先级(值越小越先执行) 
 
@Aspect
@Order(1)
@Component
public class Aspect1 {
    @Before("execution(* com.example.MyService.myMethod(..))")
    public void before1() {
        System.out.println("Aspect1 Before");
    }
}

@Aspect
@Order(2)
@Component
public class Aspect2 {
    @Before("execution(* com.example.MyService.myMethod(..))")
    public void before2() {
        System.out.println("Aspect2 Before");
    }
}
输出顺序:

Aspect1 Before
Aspect2 Before



2. 不同类型注解的执行顺序
常见注解类型及其执行顺序:
@Around:环绕通知,最先执行,包裹整个方法调用  
@Before:在目标方法执行前执行  

目标方法:实际业务逻辑  
@After:目标方法执行后执行(无论是否异常)  
@AfterReturning:目标方法成功返回后执行  
@AfterThrowing:目标方法抛出异常后执行  


示例:

@Aspect
@Component
public class MyAspect {
    @Around("execution(* com.example.MyService.myMethod(..))")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("Around Before");
        Object result = joinPoint.proceed();
        System.out.println("Around After");
        return result;
    }

    @Before("execution(* com.example.MyService.myMethod(..))")
    public void before() {
        System.out.println("Before");
    }

    @After("execution(* com.example.MyService.myMethod(..))")
    public void after() {
        System.out.println("After");
    }
}
执行顺序:

Around Before
Before

目标方法
After
Around After

3. 多个切面类的执行顺序
场景:多个切面类对同一方法定义了相同类型的注解  
默认顺序:按 Spring Bean 的 加载顺序 执行(通常按类名字母顺序)  
显式控制顺序:在切面类上使用 @Order 注解  

示例:
@Aspect
@Order(1)
@Component
public class Aspect1 {
    @Before("execution(* com.example.MyService.myMethod(..))")
    public void before1() {
        System.out.println("Aspect1 Before");
    }
}

@Aspect
@Order(2)
@Component
public class Aspect2 {
    @Before("execution(* com.example.MyService.myMethod(..))")
    public void before2() {
        System.out.println("Aspect2 Before");
    }
}
输出顺序:

Aspect1 Before
Aspect2 Before


4. 特殊情况:@Around 与其他注解的交互

@Around 的优先级:@Around 会包裹整个方法调用流程,因此它的执行顺序会影响其他注解的触发时机  
示例:如果 @Around 决定不调用 joinPoint.proceed(),则后续的 @Before、目标方法等都不会执行  


@Aspect
@Component
public class AroundAspect {
    @Around("execution(* com.example.MyService.myMethod(..))")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("Around Before");
        // 如果注释掉下一行,目标方法及后续注解都不会执行
        Object result = joinPoint.proceed(); 
        System.out.println("Around After");
        return result;
    }
}


5. 总结:执行顺序规则
注解类型	执行阶段	说明
@Around	最先执行,包裹整个流程	控制是否调用 proceed()
@Before	在目标方法执行前	所有 @Before 按 @Order 或声明顺序执行
目标方法	实际业务逻辑	
@After	目标方法执行后(无论是否异常)	
@AfterReturning	目标方法成功返回后	
@AfterThrowing	目标方法抛出异常后	


6. 实际应用建议
显式指定顺序:对关键切面(如权限校验、日志记录)使用 @Order 避免依赖默认排序  
避免过度依赖顺序:尽量将职责单一的切面解耦,减少顺序依赖  
测试验证:通过单元测试或日志输出确认实际执行顺序  
通过合理使用 @Order 和理解注解类型的作用阶段,可以灵活控制 AOP 的执行顺序,确保切面逻辑按预期工作

上一篇    
spring事务的一些知识点

MyBatis Plus 动态数据源注解 @DS 注解

MyBatis Plus @DS注解原理