SpringBoot AOP切面编程精讲:实现方式、Spring区别及与自定义注解生产实战

文章目录

一、AOP核心简介

AOP(面向切面编程)是Spring两大核心之一,核心作用就是不改动业务代码,就能对方法做统一增强,实现业务逻辑与公共逻辑解耦。常用于统一日志、接口耗时统计、权限校验、事务管理、操作记录等场景。

核心四要素:切点 (要拦截哪些方法)、切面 (增强处理类)、通知 (前后/环绕/异常等增强逻辑)、连接点(被拦截的目标方法)。

二、SpringBoot快速实现AOP(注解版)

1. 引入核心依赖

SpringBoot无需繁琐配置,仅需引入AOP启动器,自动完成装配。

xml 复制代码
<!-- SpringBoot AOP核心依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

2. 编写切面类(五种通知完整示例)

@Aspect标记切面类,@Component交给容器管理,通过切点匹配目标方法,配置不同通知完成增强。

java 复制代码
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LogAndTimeAspect {
    // 切点:拦截controller包下所有方法
    @Pointcut("execution(* com.example.demo.controller.*.*(..))")
    public void controllerPointCut(){}

    // 前置通知:方法执行前
    @Before("controllerPointCut()")
    public void beforeAdvice(){
        System.out.println("【前置通知】方法开始执行");
    }

    // 后置通知:无论是否异常,执行完毕都执行
    @After("controllerPointCut()")
    public void afterAdvice(){
        System.out.println("【后置通知】方法执行结束");
    }

    // 返回通知:方法正常返回后执行
    @AfterReturning(pointcut = "controllerPointCut()",returning = "result")
    public void afterReturningAdvice(Object result){
        System.out.println("【返回通知】返回值:" + result);
    }

    // 异常通知:方法报错时执行
    @AfterThrowing(pointcut = "controllerPointCut()",throwing = "e")
    public void afterThrowingAdvice(Exception e){
        System.out.println("【异常通知】异常信息:" + e.getMessage());
    }

    // 环绕通知:功能最强,手动控制方法执行前后逻辑
    @Around("controllerPointCut()")
    public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        // 执行目标方法
        Object result = joinPoint.proceed();
        long endTime = System.currentTimeMillis();
        System.out.println("【环绕通知】方法耗时:" + (endTime - startTime) + "ms");
        return result;
    }
}

3. 测试接口

java 复制代码
@RestController
public class AopTestController {
    @GetMapping("/aop/test")
    public String aopTest(){
        System.out.println("业务方法执行中");
        return "AOP执行成功";
    }
}

4. 通知执行顺序

正常执行:环绕前置 → 前置通知 → 目标方法 → 返回通知 → 后置通知 → 环绕后置

异常执行:环绕前置 → 前置通知 → 方法报错 → 异常通知 → 后置通知

三、传统Spring AOP vs SpringBoot AOP核心区别

两者底层原理、切点规则、通知逻辑完全一样,核心区别仅在配置和使用方式。

1. 核心差异汇总

  • 配置方式:Spring AOP必须写XML配置,繁琐冗余;SpringBoot AOP零XML,纯注解开箱即用。

  • 依赖管理:Spring需手动导入多个Jar、处理版本冲突;SpringBoot只需一个启动器,自动管控版本。

  • 代理开启:Spring需手动配置AOP自动代理标签;SpringBoot默认自动开启,无需手动配置。

  • 适用场景:Spring AOP仅用于老旧SSM项目维护;SpringBoot AOP是新项目、微服务标配。

四、SpringBoot AOP切面 vs 自定义注解(生产重点)

1. 核心关系

AOP切面 :干活的拦截器,负责方法增强逻辑;自定义注解:标记开关,只负责筛选哪些方法需要拦截。

两者不是二选一,生产标配:AOP切面 + 自定义注解组合使用

2. 两种方式对比

对比维度 纯AOP按包名拦截(execution) AOP+自定义注解(精准拦截)
拦截范围 全局批量拦截,范围大 只拦截加注解的方法,精准可控
误拦截风险 高,容易拦截无关方法 无,不加注解不生效
适用场景 全局耗时、基础统一日志 操作日志、权限、限流、数据脱敏
生产推荐 少用、不推荐 首选、企业标准

五、实战1:纯AOP全局拦截(仅演示,不推荐生产)

按包名一刀切,所有接口都拦截,无法单独控制,容易产生垃圾日志。

java 复制代码
@Aspect
@Component
public class AllApiLogAspect {
    @Pointcut("execution(* com.example.demo.controller.*.*(..))")
    public void pointcut(){}

    @Around("pointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("接口入参:" + Arrays.toString(joinPoint.getArgs()));
        Object result = joinPoint.proceed();
        System.out.println("接口出参:" + result);
        return result;
    }
}

六、实战2:AOP+自定义注解(生产标准写法)

1. 创建自定义标记注解

java 复制代码
import java.lang.annotation.*;

// 仅标记方法、运行时生效
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface OperateLog {
    String value() default ""; // 记录操作描述
}

2. 切面拦截该注解

java 复制代码
@Aspect
@Component
public class OperateLogAspect {
    // 只拦截加了@OperateLog注解的方法
    @Pointcut("@annotation(com.example.demo.annotation.OperateLog)")
    public void operateLogPointcut(){}

    @Around("operateLogPointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("===== 记录重要操作日志 =====");
        System.out.println("操作方法:" + joinPoint.getSignature().getName());
        System.out.println("请求参数:" + Arrays.toString(joinPoint.getArgs()));
        Object result = joinPoint.proceed();
        System.out.println("操作返回结果:" + result);
        return result;
    }
}

3. 业务接口按需使用

java 复制代码
@RestController
public class UserController {
    // 普通查询:不加注解 → 不记录日志
    @GetMapping("/user/get")
    public String getUser(){
        return "查询用户";
    }

    // 重要操作:加注解 → AOP自动记录日志
    @OperateLog("删除用户操作")
    @GetMapping("/user/delete")
    public String deleteUser(){
        return "删除成功";
    }
}

七、最终生产总结

  1. 简单全局通用功能,可少量使用纯AOP包名拦截;

  2. 业务特殊增强功能,一律使用AOP+自定义注解,精准可控、好维护;

  3. SpringBoot新项目只用注解AOP,传统Spring XML配置仅作老旧项目维护使用。

相关推荐
写代码写到手抽筋3 小时前
5G上行DCI字段判定:端口 流数 PMI选择详解
java·算法·5g
wang09073 小时前
自己动手写一个spring之系列
spring
xieliyu.3 小时前
Java算法精讲:双指针(二)
java·开发语言·算法
jeffer_liu4 小时前
Spring AI 生产级实战:裁判员
java·人工智能·后端·spring·大模型
小bo波5 小时前
枚举实战
java·设计模式·枚举·后端开发·代码重构
夜微凉45 小时前
三、Spring
java·后端·spring
橘右今5 小时前
2026 Java后端高频面试宝典
java·开发语言·面试
xyzzklk6 小时前
解决Salesforce无法向外发送邮件
android·java·开发语言·网络·crm·salesforce·客户关系管理
biubiubiu07066 小时前
SpringBoot关于外部化配置
java·spring boot·spring
Full Stack Developme7 小时前
Spring Bean 依赖注入
python·spring·log4j