Spring Boot AOP(一) 入门与核心概念

5 阅读4分钟

Spring Boot AOP(一) 入门与核心概念

1. AOP 基础概念

AOP(Aspect-Oriented Programming,[面向切面编程])是一种用于处理 横切关注点(Cross-Cutting Concerns)的[编程技术]。在企业级项目中,日志记录、性能监控、事务管理、权限校验等通常会重复出现在多个模块,如果将这些逻辑直接写入业务方法,会导致代码耦合高、难维护。AOP 通过 切面(Aspect)  将这些横切逻辑模块化,从而解耦业务逻辑。

核心概念

概念说明示例
切面 Aspect横切关注点模块化封装日志切面、事务切面
通知 Advice切面中具体执行操作@Before、@After、@Around
连接点 JoinPoint可以被切面切入的位置方法调用、异常抛出
切入点 Pointcut匹配连接点的表达式execution(* com.example.service… . (…))
织入 Weaving将切面应用到目标对象的过程Spring AOP 在运行时生成代理

Spring AOP 默认使用 运行时动态代理,只对 Spring 管理的 Bean 生效,无法处理普通对象的直接方法调用。


2. 连接点与切入点表达式

2.1 JoinPoint 常用方法

@Around("execution(* com.example.service..*.*(..))")
public Object logAround(ProceedingJoinPoint pjp) throws Throwable {
    System.out.println("目标对象: " + pjp.getTarget());
    System.out.println("方法签名: " + pjp.getSignature());
    System.out.println("方法参数: " + Arrays.toString(pjp.getArgs()));
    return pjp.proceed();
}

AI写代码java
运行
1234567
方法说明
getTarget()目标对象
getThis()当前代理对象
getArgs()方法参数
getSignature()方法签名
proceed()执行目标方法(环绕通知专用)

2.2 切入点表达式常用类型

表达式含义示例
execution()匹配方法执行execution(* com.example.service… . (…))
within()匹配类或包within(com.example.service…*)
this()匹配代理对象类型this(com.example.service.MyService)
target()匹配目标对象类型target(com.example.service.MyService)
args()匹配参数类型args(String, …)

2.3 切入点示意图

匹配

不匹配

Service 层方法

匹配切入点?

执行切面通知

直接执行目标方法


3. Spring AOP 通知类型

类型执行时机注解适用场景
前置通知方法执行前@Before权限校验、日志记录
后置通知方法执行后@After日志记录、资源清理
返回通知方法成功返回后@AfterReturning日志记录、返回值处理
异常通知方法抛出异常后@AfterThrowing异常记录、告警
环绕通知方法执行前后@Around性能统计、异常统一处理

通知执行顺序示意

AI写代码mermaid
12345678

4. 简单切面示例

@Aspect
@Component
public class LogAspect {

    @Before("execution(* com.example.service..*.*(..))")
    public void logBefore(JoinPoint joinPoint) {
        System.out.println("前置通知: 调用方法 " + joinPoint.getSignature().getName());
    }

    @AfterReturning(pointcut = "execution(* com.example.service..*.*(..))", returning = "result")
    public void logAfterReturning(JoinPoint joinPoint, Object result) {
        System.out.println("返回通知: 方法返回值 " + result);
    }

    @Around("execution(* com.example.service..*.*(..))")
    public Object logAround(ProceedingJoinPoint pjp) throws Throwable {
        long start = System.currentTimeMillis();
        System.out.println("环绕通知: 方法执行前");
        Object result = pjp.proceed();
        System.out.println("环绕通知: 方法执行后, 耗时 " + (System.currentTimeMillis() - start) + "ms");
        return result;
    }
}

AI写代码java
运行
1234567891011121314151617181920212223

5. 方法调用流程示意

ClientProxyTarget调用方法执行 @Before调用目标方法返回结果执行 @AfterReturning 或 @AfterThrowing返回最终结果ClientProxyTarget


6. 环绕通知深入解析

环绕通知 (@Around) 可以完全控制目标方法的执行:

  • 可以修改参数
  • 可以捕获异常
  • 可以修改返回值
  • 可以决定是否执行目标方法
@Around("execution(* com.example.service..*.*(..))")
public Object secureAround(ProceedingJoinPoint pjp) throws Throwable {
    Object[] args = pjp.getArgs();
    // 修改参数
    args[0] = "modified";
    try {
        Object result = pjp.proceed(args);
        return result;
    } catch (Throwable ex) {
        System.out.println("捕获异常: " + ex.getMessage());
        throw ex;
    }
}

AI写代码java
运行
12345678910111213

流程图:环绕通知控制流程

AI写代码mermaid
12345678

7. AOP 与 Bean 生命周期交互

Spring AOP 使用 BeanPostProcessor 在 Bean 初始化后生成代理:

BeanDefinition 注册

Bean 实例化

依赖注入

postProcessBeforeInitialization

初始化方法

postProcessAfterInitialization

需要代理?

创建代理对象

直接返回 Bean

代理对象注入到容器

核心类:

  • AnnotationAwareAspectJAutoProxyCreator
  • ProxyFactory / Enhancer
  • Advisor / Advice / Pointcut

8. 实战案例:日志 + 性能切面

@Aspect
@Component
public class PerformanceAspect {

    @Around("execution(* com.example.service..*.*(..))")
    public Object measureTime(ProceedingJoinPoint pjp) throws Throwable {
        long start = System.currentTimeMillis();
        Object result = pjp.proceed();
        long duration = System.currentTimeMillis() - start;
        System.out.println(pjp.getSignature() + " 耗时: " + duration + "ms");
        return result;
    }
}

@Aspect
@Component
public class LoggingAspect {

    @Before("execution(* com.example.service..*.*(..))")
    public void logBefore(JoinPoint joinPoint) {
        System.out.println("调用方法: " + joinPoint.getSignature().getName());
    }

    @AfterReturning(pointcut = "execution(* com.example.service..*.*(..))", returning = "result")
    public void logAfterReturning(JoinPoint joinPoint, Object result) {
        System.out.println("方法返回值: " + result);
    }
}

AI写代码java
运行
12345678910111213141516171819202122232425262728

多切面调用顺序示意

AI写代码mermaid
1234567

9. 本文小结

  • AOP 是处理横切关注点的强大机制
  • 切面 + 通知 + 切入点构成核心
  • 环绕通知最灵活,可控制方法执行前后
  • 多切面、Bean 生命周期、通知组合都需要清楚理解
  • Mermaid 图帮助理解调用顺序和执行流程