spring aop 执行顺序(@Before @Around @After @AfterReturning @AfterThrowing)

spring aop 执行顺序(@Before @Around @After @AfterReturning @AfterThrowing)

思路

通过单元测试,调用指定方法,验证切面方法执行顺序

代码

1.引入切面aop

<!-- 切面 spring-boot-starter-aop -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
            <version>2.6.2</version>
        </dependency>

	<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.0</version>
<!--        <version>2.1.0.RELEASE</version>-->
<!--        <version>2.0.0.RELEASE</version>-->
<!--        <version>2.2.0.RELEASE</version>-->
<!--        <version>2.3.0.RELEASE</version>-->
<!--        <version>2.3.1.RELEASE</version>-->
<!--        <version>2.3.2.RELEASE</version>-->
<!--        <version>2.3.3.RELEASE</version>-->
<!--        <version>1.5.22.RELEASE</version>-->
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

2.目标方法
2.1目标方法A

package com.example.temp.aopOrder;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * @Author:
 * @Date:
 * @Version:1.0.0
 **/
@Component
@Slf4j
public class AopOrderServiceA {

    @Resource
    AopOrderServiceB serviceB;

    public void aopOrderA() {
        log.info("aopOrderA-进入方法。。。");
        int x = 0/0;
        serviceB.aopOrderB();
        log.info("aopOrderA-方法执行完毕!");
    }

}

2.2目标方法B

package com.example.temp.aopOrder;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

/**
 * @Author:
 * @Date:
 * @Version:1.0.0
 **/
@Component
@Slf4j
public class AopOrderServiceB {

    public void aopOrderB() {
        log.info("aopOrderB-进入方法。。。");
//        int x = 0/0;
        log.info("aopOrderB-方法执行完毕!");
    }
}

3.切面方法

package com.example.temp.aopOrder;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 * @Author:
 * @Date:
 * @Version:1.0.0
 **/
@Aspect// 这是一个切面
@Component// 这是一个需要被装配的spring bean
@Slf4j
public class AopOrderAspecct {

    @Pointcut("execution(public void com.example.temp.aopOrder.*.*())")
    public void point() {
    }

    @Before("point()")
    public void before(JoinPoint joinPoint) {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        String methodName = methodSignature.getName();
        log.info("{}-执行before。。。", methodName);
    }

    @Around("point()")
    public void around(ProceedingJoinPoint joinPoint) {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        String methodName = methodSignature.getName();
        log.info("{}-进入around。。。", methodName);
        try {
            joinPoint.proceed();
        } catch (Throwable throwable) {
            log.error("{}-around内部方法执行失败:{}", methodName, throwable.getMessage());
        }
        log.info("{}-around执行完毕!", methodName);
    }

    @After("point()")
    public void after(JoinPoint joinPoint) {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        String methodName = methodSignature.getName();
        log.info("{}-执行after。。。", methodName);
    }

    @AfterReturning("point()")
    public void afterReturning(JoinPoint joinPoint) {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        String methodName = methodSignature.getName();
        log.info("{}-执行afterReturning。。。", methodName);
    }

    @AfterThrowing("point()")
    public void afterThrowing(JoinPoint joinPoint) {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        String methodName = methodSignature.getName();
        log.info("{}-执行afterThrowing。。。", methodName);
    }
}

4.单元测试

package com.example.temp.aopOrder;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;

/**
 * @Author:
 * @Date:
 * @Version:1.0.0
 **/
@SpringBootTest
@RunWith(SpringRunner.class)
public class OrderServiceTest {
    @Resource
    AopOrderService aopOrderService;

    @Test
    public void testOrder() {
    	String springVersion = SpringVersion.getVersion();
        String bootVersion = SpringBootVersion.getVersion();
        log.info("spring:{},springBoot:{}", springVersion, bootVersion);
        aopOrderService.aopOrder();
    }
}

5.测试结果(执行环境springboot版本为2.7.0)
当目标方法无异常时

spring:5.3.20,springBoot:2.7.0
aopOrderA-进入around。。。
aopOrderA-执行before。。。
aopOrderA-进入方法。。。
aopOrderA-方法执行完毕!
aopOrderA-执行afterReturning。。。// 注意,这里不同
aopOrderA-执行after。。。
aopOrderA-around执行完毕!

当目标方法执行抛出异常时

spring:5.3.20,springBoot:2.7.0
aopOrderA-进入around。。。
aopOrderA-执行before。。。
aopOrderA-进入方法。。。
aopOrderA-执行afterThrowing。。。// 注意,这里不同
aopOrderA-执行after。。。
aopOrderA-around内部方法执行失败:/ by zero
aopOrderA-around执行完毕!

当目标方法切面嵌套时

spring:5.3.20,springBoot:2.7.0
aopOrderA-进入around。。。
aopOrderA-执行before。。。
aopOrderA-进入方法。。。
aopOrderB-进入around。。。
aopOrderB-执行before。。。
aopOrderB-进入方法。。。
aopOrderB-方法执行完毕!
aopOrderB-执行afterReturning。。。
aopOrderB-执行after。。。
aopOrderB-around执行完毕!
aopOrderA-方法执行完毕!
aopOrderA-执行afterReturning。。。
aopOrderA-执行after。。。
aopOrderA-around执行完毕!
aopOrderA-方法执行完毕!
aopOrderA-执行afterReturning。。。
aopOrderA-执行after。。。
aopOrderA-around执行完毕!

6.不同版本的差异

springboot版本 2.3.1.RELEASE 之前,after在around之后执行, 2.3.1.RELEASE 及之后,around包裹整个切面执行周期

spring boot 版本为 2.0.0.RELEASE

spring:5.0.4.RELEASE,springBoot:2.0.0.RELEASE
aopOrderA-进入around。。。
aopOrderA-执行before。。。
aopOrderA-进入方法。。。
aopOrderA-方法执行完毕!
aopOrderA-around执行完毕!
aopOrderA-执行after。。。
aopOrderA-执行afterReturning。。。

spring boot 版本为 2.1.0.RELEASE

spring:5.1.2.RELEASE,springBoot:2.1.0.RELEASE
aopOrderA-进入around。。。
aopOrderA-执行before。。。
aopOrderA-进入方法。。。
aopOrderA-方法执行完毕!
aopOrderA-around执行完毕!
aopOrderA-执行after。。。
aopOrderA-执行afterReturning。。。

spring boot 版本为 2.2.0.RELEASE

spring:5.2.0.RELEASE,springBoot:2.2.0.RELEASE
aopOrderA-进入around。。。
aopOrderA-执行before。。。
aopOrderA-进入方法。。。
aopOrderA-方法执行完毕!
aopOrderA-around执行完毕!
aopOrderA-执行after。。。
aopOrderA-执行afterReturning。。。

spring boot 版本为 2.3.0.RELEASE

spring:5.2.6.RELEASE,springBoot:2.3.0.RELEASE
aopOrderA-进入around。。。
aopOrderA-执行before。。。
aopOrderA-进入方法。。。
aopOrderA-方法执行完毕!
aopOrderA-around执行完毕!
aopOrderA-执行after。。。
aopOrderA-执行afterReturning。。。

spring boot 版本为 2.3.1.RELEASE

spring:5.2.7.RELEASE,springBoot:2.3.1.RELEASE
aopOrderA-进入around。。。
aopOrderA-执行before。。。
aopOrderA-进入方法。。。
aopOrderA-方法执行完毕!
aopOrderA-执行afterReturning。。。
aopOrderA-执行after。。。
aopOrderA-around执行完毕!// 注意,这里不同
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值