Spring AOP 底层原理

我们来深入分析 @Around 通知的执行逻辑,包括:

  1. @Around 背后的动态代理逻辑
  2. ProceedingJoinPoint 是如何封装目标方法的
  3. 执行链(advice chain)是怎么组织的

🔧 1. Spring AOP 背后的代理实现

Spring AOP 默认使用 JDK 动态代理(接口)CGLIB 代理(子类)

目标类类型代理方式
实现了接口JDK 动态代理
没有接口实现CGLIB 子类代理

你举的 UserServiceAopProxy extends UserService 就类似 CGLIB 的方式。


📍 2. @Around 是如何工作的

Spring AOP 的 @Around 是基于 责任链模式,核心逻辑是通过 MethodInterceptor 接口实现的。

例子:定义一个 @Around 方法

@Aspect
@Component
public class LoggingAspect {

    @Around("execution(* com.example.service.UserService.*(..))")
    public Object doLog(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("Before method: " + pjp.getSignature());
        Object result = pjp.proceed(); // 目标方法执行
        System.out.println("After method: " + pjp.getSignature());
        return result;
    }
}

🧵 3. 动态代理执行流程细节

以 CGLIB 为例,Spring 会在运行时为你的目标类生成一个子类(即代理类),代理类会拦截所有 public 方法,并执行拦截器链:

public class UserService$$EnhancerBySpringCGLIB extends UserService {
    // 拦截所有方法
    public User login(String email, String password) {
        Method method = ... // 反射获取login方法
        MethodInterceptor interceptor = ... // 从缓存中获取Advice链
        return (User) interceptor.invoke(new CglibMethodInvocation(this, method, args));
    }
}

🔁 4. ProceedingJoinPoint 是如何工作的?

核心类:ReflectiveMethodInvocation(JDK 代理)或 CglibMethodInvocation(CGLIB)

这两个类实现了 ProceedingJoinPoint 接口,其职责是:

  • 封装目标方法调用所需的信息(目标对象、方法、参数、注解等)
  • 提供 proceed() 方法来按顺序执行通知链

内部结构简化如下:

public class ReflectiveMethodInvocation implements ProceedingJoinPoint {
    private Object target;           // 目标对象
    private Method method;           // 调用的方法
    private Object[] arguments;      // 方法参数
    private List<MethodInterceptor> interceptors;
    private int currentInterceptorIndex = -1;

    public Object proceed() throws Throwable {
        if (++currentInterceptorIndex == interceptors.size()) {
            // 所有Advice执行完,调用目标方法
            return method.invoke(target, arguments);
        }

        // 执行下一个Advice
        MethodInterceptor nextInterceptor = interceptors.get(currentInterceptorIndex);
        return nextInterceptor.invoke(this); // 递归调用
    }
}

你可以理解为:

@Around1 -> @Around2 -> @Before -> method -> @AfterReturning

每个 interceptor 都包裹住下一层,最终最内层调用的是目标方法。


✨ 举例说明

设想你有两个 @Around 通知:

@Around("...")  // First
public Object advice1(ProceedingJoinPoint pjp) {
    System.out.println("Advice 1 before");
    Object result = pjp.proceed();  // 调用下一个拦截器或目标方法
    System.out.println("Advice 1 after");
    return result;
}

@Around("...")  // Second
public Object advice2(ProceedingJoinPoint pjp) {
    System.out.println("Advice 2 before");
    Object result = pjp.proceed();
    System.out.println("Advice 2 after");
    return result;
}

执行顺序是:

Advice 1 before
Advice 2 before
--- 调用目标方法 ---
Advice 2 after
Advice 1 after

✅ 小结:Spring AOP 中 @Around 执行流程

  1. Spring 使用动态代理或 CGLIB 生成代理类
  2. 拦截所有目标方法,通过 MethodInterceptor 组成一个拦截链
  3. @Around 被包装成 MethodInterceptor,按顺序组成调用链
  4. ProceedingJoinPoint 实际由 MethodInvocation 对象实现
  5. proceed() 会继续调用下一个拦截器,最后执行目标方法
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值