Spring aop 五种通知类型

spring aop 的五种通知类型

  1. 前置通知 Before advice:在连接点前面执行,前置通知不会影响连接点的执行,除非此处抛出异常
  2. 后置通知 After returning advice:在连接点正常执行完成后执行,如果连接点抛出异常,则不会执行
  3. 异常通知 After throwing advice:在连接点抛出异常后执行
  4. 最终通知 After (finally) advice:在连接点执行完成后执行,不管是正常执行完成,还是抛出异常,都会执行返回通知中的内容
  5. 环绕通知 Around advice:环绕通知围绕在连接点前后,能在方法调用前后自定义一些操作,还需要负责决定是继续处理 join point (调用 ProceedingJoinPointproceed 方法)还是中断执行

五大通知类型中,环绕通知功能最为强大,因为环绕通知,可以控制目标方法是否执行。

如果需要记录异常信息,使用异常通知。

其他通知,只能做记录工作,不能做处理,所以执行顺序其实对整个程序影响不大,没有必要太深究。

spring aop 通知类型使用

添加 Aspect 切面类

复制代码
package com.example.demo.module.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class AdviceTest {

    // 配置织入点
    @Pointcut("execution(public * com.example.demo.module.aspect.Test.*(..))")
    public void test(){

    }

    @Before("test()")
    public void doBefore(JoinPoint joinPoint){
        System.out.println(joinPoint.getSignature().getName() + "执行前置通知---");
    }

    @AfterReturning("test()")
    public void doAfterSuccess(JoinPoint joinPoint){
        System.out.println(joinPoint.getSignature().getName() + "执行返回通知---");
    }

    @AfterThrowing("test()")
    public void doAfterError(JoinPoint joinPoint){
        System.out.println(joinPoint.getSignature().getName() + "执行异常通知---");
    }

    @Around(value = "test()", argNames = "pjp")
    public Object doAround(ProceedingJoinPoint pjp) {
        Object[] args = pjp.getArgs();
        Object result;
        try {
        	// Before
            System.out.println(pjp.getSignature().getName() + "环绕前置通知---");
            result = pjp.proceed(args);
            // AfterReturning
            System.out.println(pjp.getSignature().getName() + "环绕返回通知---");
        }catch (Throwable e){
        	// AfterThrowing
            System.out.println(pjp.getSignature().getName() + "环绕异常通知---");
            throw new RuntimeException(e);
        }finally {
        	// After
            System.out.println(pjp.getSignature().getName() + "环绕最终通知---");
        }
        return result;
    }

    @After("test()")
    public void doAfter(JoinPoint joinPoint){
        System.out.println(joinPoint.getSignature().getName() + "执行最终通知---");
    }

}

添加测试方法:

复制代码
package com.example.demo.module.aspect;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RequestMapping("test")
@RestController
public class Test {

    @GetMapping("testMethod")
    public void testMethod(){
        System.out.println("方法执行---");
    }

}

运行结果:

测试异常通知,修改测试方法:

复制代码
package com.example.demo.module.aspect;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RequestMapping("test")
@RestController
public class Test {

    @GetMapping("testMethod")
    public void testMethod(){
    	int i= 1/0;
        System.out.println("方法执行---");
    }

}

运行结果:

通知执行顺序

Spring 版本不一样,通知执行顺序可能也会存在差异

@Before、@After、@AfterReturning、@AfterThrowing执行顺序

  1. Spring 4.0
    正常情况:@Before -> 目标方法 -> @After -> @AfterReturning
    异常情况:@Before -> 目标方法 -> @After -> @AfterThrowing
  2. Spring 5.28
    正常情况:@Before -> 目标方法 -> @AfterReturning -> @After
    异常情况:@Before -> 目标方法 -> @AfterThrowing -> @After

@Around的执行顺序

  1. Spring 4.0
    正常情况:环绕前置 -> 目标方法执行 -> 环绕返回 -> 环绕最终
    异常情况:环绕前置 -> 目标方法执行 -> 环绕异常 -> 环绕最终
  2. Spring 5.28
    正常情况:环绕前置 -> 目标方法执行 -> 环绕返回 -> 环绕最终
    异常情况:环绕前置 -> 目标方法执行 -> 环绕异常 -> 环绕最终

五大通知执行顺序

  1. Spring 4.0
    正常情况:环绕前置 -> @Before -> 目标方法执行 -> 环绕返回 -> 环绕最终 -> @After -> @AfterReturning
    异常情况:环绕前置 -> @Before -> 目标方法执行 -> 环绕异常 -> 环绕最终 -> @After -> @AfterThrowing
  2. Spring 5.28
    正常情况:环绕前置 -> @Before -> 目标方法执行 -> @AfterReturning -> @After -> 环绕返回 -> 环绕最终
    异常情况:环绕前置 -> @Before -> 目标方法执行 -> @AfterThrowing -> @After -> 环绕异常 -> 环绕最终
相关推荐
無名路人4 分钟前
小程序点餐页吸顶滚动
前端·微信小程序·ai编程
老马95277 分钟前
opencode7-桌面应用实战2
java·人工智能·后端
小小小前端啊8 分钟前
前端手写代码大全
前端
李白的天不白16 分钟前
大规模请求数据并发问题
java·前端·数据库
智慧物业老杨41 分钟前
智慧物业数智化转型实战:从工单响应到业主满意度的闭环构建
java·开发语言
Kiling_070444 分钟前
Java集合框架:List集合详解与应用
java·开发语言·windows
冲浪中台1 小时前
【无标题】
前端·低代码
极客先躯1 小时前
高级java每日一道面试题-2025年12月08日-实战篇[Docker]-如何为 Docker 配置代理?如何为容器配置代理?
java·docker·代理配置的双层架构·docker 守护进程配置代理·为容器配置代理·构建时环境变量·运行时注入环境变量
openKaka_1 小时前
beginWork 的第一站:HostRoot 如何把 App 接入 Fiber 树
前端·javascript·react.js
csdn2015_1 小时前
java springboot 文件导入,判断第一列的值是否有重复
java·windows·spring boot