Aop的优先级

Spring AOP使用AspectJ的优先级规则来确定通知执行顺序。

    总共有两种情况:同一切面中通知执行顺序、不同切面中的通知执行顺序。

    同一切面中通知执行顺序:

    1. 前置通知/环绕通知proceed方法之前部分    --执行顺序根据配置顺序决定

    2. 被通知方法

    3. 后置方法/环绕通知proceed方法之后部分    --执行顺序根据配置顺序决定

前置通知与环绕通知proceed之前的顺序是根据配置顺序决定的,比如:


?
1
2
3
4
5
6
7
< aop:aspect ref = "aspect" >
     < aop:around method = "around" pointcut-ref = "pointcut" />
     < aop:before method = "before" pointcut-ref = "pointcut" />
     < aop:after-returning method = "afterReturning" pointcut-ref = "pointcut" returning = "retVal" />
     < aop:after method = "afterAdvice" pointcut-ref = "pointcut" />
     < aop:after-throwing method = "afterThrowing" arg-names = "ex" throwing = "ex" pointcut-ref = "pointcut" />
</ aop:aspect >
环绕通知在前置通知之前,则会先执行环绕通知proceed之前的部分。


同样环绕通知与后置通知、后置返回通知的顺序也是根据配置顺序决定的。因此在环绕通知中修改了返回值,根据配置的顺序结果会不一样。


不同切面中的通知执行顺序:当定义在不同切面的相同类型的通知需要在同一个连接点执行,如果没指定切面的执行顺序,这两个通知的执行顺序将是未知的。

如果需要他们顺序执行,可以通过指定切面的优先级来控制通知的执行顺序。Spring中可以通过在切面实现类上实现org.springframework.core.Ordered接口或使用Order注解来指定切面优先级。在多个切面中,Ordered.getValue()方法返回值(或者注解值)较小值的那个切面拥有较高优先级:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public class XmlLogAspect implements Ordered {
 
     private int order = 1 ;
     private static final Logger LOGGER = LoggerFactory.getLogger(XmlLogAspect. class );
 
     public void publicPointcut(){}
 
     public void before() {
         LOGGER.info( "支付前打印一点字........." );
     }
 
     public void afterAdvice() {
         LOGGER.info( "后置通知,支付完成了呵呵............" );
     }
 
     // 注意,此处returning后的值必须与方法参数名的值一致
     public void afterReturning(String retVal) {
         LOGGER.info( "支付结果如何,hoho检查检查:" + retVal);
     }
 
     public void afterThrowing(Exception ex) {
         LOGGER.info(ex.getMessage());
     }
 
     // 此方法必须有返回值,否则会使得被代理的方法的返回值变为null
     public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
         LOGGER.info( "支付方法中,先来一下........" );
         Object result = joinPoint.proceed();
         LOGGER.info( "支付方法结束了,走你........." );
         return result + "add" ;
     }
 
 
     @Override
     public int getOrder() {
         return this .order;
     }
 
     public void setOrder( int order) {
         this .order = order;
     }
}

使用@Order注解更加简单:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Order ( 2 )
public class XmlLogAspect {
private static final Logger LOGGER = LoggerFactory.getLogger(XmlLogAspect. class );
 
     public void publicPointcut(){}
 
     public void before() {
         LOGGER.info( "支付前打印一点字........." );
     }
 
     public void afterAdvice() {
         LOGGER.info( "后置通知,支付完成了呵呵............" );
     }
 
     // 注意,此处returning后的值必须与方法参数名的值一致
     public void afterReturning(String retVal) {
         LOGGER.info( "支付结果如何,hoho检查检查:" + retVal);
     }
}
或者在xml中配置:
?
1
2
3
< aop:aspect ref = "aspect1" order = "1" >
……
</ aop:aspect >
### Spring AOP 通知类型及其执行顺序与优先级 Spring AOP 的核心在于通过不同的通知类型(Advice Types)来增强目标方法的功能。以下是关于不同类型通知的执行顺序以及其优先级的相关说明。 #### 不同通知类型的定义 Spring 支持五种主要的通知类型,每种类型都有特定的作用范围和触发时机: - **前置通知(Before Advice)**: 在目标方法调用前执行[^4]。 - **后置通知(After Advice)**: 在目标方法完成后执行,无论是否有异常发生。 - **返回通知(After Returning Advice)**: 当目标方法成功执行并返回结果时触发。 - **异常通知(After Throwing Advice)**: 只有当目标方法抛出指定异常时才会触发。 - **环绕通知(Around Advice)**: 是最强大的一种通知形式,它可以在目标方法前后都执行逻辑,并能够控制是否继续执行目标方法。 #### 执行顺序分析 在实际运行过程中,如果一个切入点被多个切面拦截,则这些切面会被按一定规则排序形成一条调用链。具体来说: 1. 进入切入点时,具有较高优先级的切面中的前置通知会率先被执行; 2. 如果存在环绕通知,它的 `proceed()` 方法决定了何时真正调用目标方法或者后续其他低优先级的通知; 3. 离开切入点时,高优先级的后置/返回/异常通知则会在较低优先级之后才得以处理[^1]。 #### 切面优先级机制 为了决定各个切面之间的相对位置关系,Spring 提供了一套完善的优先级判定体系。通常情况下,默认不设置任何特殊属性的话,各切面之间视为平等对待;然而可以通过实现 Ordered 接口或利用 @Order 注解显式声明各自的次序级别[^2]。数值越小代表优先度越高,意味着更早介入到整个事务链条当中去。 #### 示例代码展示 下面给出一段简单的 Java 配置类用于演示如何配置多种类型的通知: ```java @Aspect @Component public class LoggingAspect { @Before("execution(* com.example.service.*.*(..))") public void logBefore(JoinPoint joinPoint){ System.out.println("Logging before method: "+joinPoint.getSignature().getName()); } @AfterReturning(pointcut="execution(* com.example.service.*.*(..))", returning="result") public void logAfterReturn(Object result){ System.out.println("Method returned value :"+result); } @AfterThrowing(pointcut="execution(* com.example.service.*.*(..))", throwing="error") public void logAfterError(Exception error){ System.out.println("Exception caught:"+error.getMessage()); } } ``` 上述例子展示了基本的日志记录方面,其中包含了 Before 和 After 类型的通知实例化过程[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值