Spring AOP深度解析:调用链与适配器模式

一、AOP核心概念回顾

先明确几个关键概念:

  • Joinpoint(连接点):程序执行过程中的特定点(如方法调用)
  • Pointcut(切点):定义哪些连接点需要被拦截
  • Advice(通知):在连接点执行的横切逻辑
  • Advisor(顾问):Pointcut和Advice的组合体
  • Interceptor(拦截器):实现横切逻辑的具体组件

二、适配器模式在AOP中的应用

适配器模式在Spring AOP中扮演着关键角色,主要体现在两个层面:

1. Advisor适配器
java 复制代码
// 适配器模式典型实现:组合Pointcut和Advice
public class DefaultPointcutAdvisor implements Advisor {
    private Pointcut pointcut;
    private Advice advice;
    
    // 构造器将两个独立组件适配为一个整体
    public DefaultPointcutAdvisor(Pointcut pointcut, Advice advice) {
        this.pointcut = pointcut;
        this.advice = advice;
    }
}

这种设计实现了:

  • 解耦:Pointcut和Advice可独立变化
  • 统一接口:所有Advisor都实现Advisor接口
  • 灵活组合:动态组合不同的切点和通知
2. Advice适配器(框架内部)

Spring内部使用适配器将不同类型的Advice统一转换为MethodInterceptor:

java 复制代码
public interface AdvisorAdapter {
    // 判断是否支持特定类型的Advice
    boolean supportsAdvice(Advice advice);
    
    // 将Advice适配为MethodInterceptor
    MethodInterceptor getInterceptor(Advisor advisor);
}

这种设计使框架能统一处理:

  • BeforeAdvice
  • AfterReturningAdvice
  • ThrowsAdvice
  • 自定义Advice类型

三、调用链执行机制深度解析

Spring AOP的核心执行流程通过责任链模式实现:

1. 代理对象创建
java 复制代码
ProxyFactory proxyFactory = new ProxyFactory(target);
proxyFactory.addAdvisor(auditAdvisor);
proxyFactory.addAdvisor(perfAdvisor);
UserService proxy = (UserService) proxyFactory.getProxy();

此时创建的代理对象包含:

  • 目标对象引用
  • 按顺序排列的Advisor列表
  • 代理配置信息
2. 调用链执行流程

当调用代理方法时,触发ReflectiveMethodInvocation执行:

java 复制代码
public class ReflectiveMethodInvocation {
    // 核心字段
    protected final Object proxy;
    protected final Object target;
    protected final Method method;
    private final Object[] arguments;
    private final List<Object> interceptorsAndDynamicMethodMatchers;
    private int currentInterceptorIndex = -1;

    // 核心方法:驱动调用链执行
    public Object proceed() throws Throwable {
        // 所有拦截器执行完毕,调用目标方法
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            return invokeJoinpoint();
        }

        // 获取下一个拦截器
        Object interceptor = 
            this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
        
        // 执行拦截器逻辑
        if (interceptor instanceof MethodInterceptor) {
            MethodInterceptor mi = (MethodInterceptor) interceptor;
            return mi.invoke(this);
        }
        // ...其他类型处理
    }
}
3. 典型调用链执行序列

createUser()方法为例:

markdown 复制代码
1. 审计拦截器前置处理
   │
2. └──> 性能拦截器前置处理
        │
3.      └──> 目标方法执行
        │
4.      ┌── 性能拦截器后置处理(计算耗时)
   │
5. └── 审计拦截器后置处理(记录结果)

这个调用栈的构建得益于责任链模式:

  • 每个拦截器持有下一个处理单元的引用
  • 通过invocation.proceed()传递控制权
  • 支持动态增减拦截器

四、Pointcut匹配机制剖析

自定义Pointcut展示了精准匹配:

java 复制代码
class UserMutationPointcut extends StaticMethodMatcherPointcut {
    @Override
    public boolean matches(Method method, Class<?> targetClass) {
        // 精确匹配方法名
        return method.getName().contains("create") 
            || method.getName().contains("delete");
    }
    
    @Override
    public ClassFilter getClassFilter() {
        // 精确匹配接口类型
        return clazz -> clazz == UserService.class;
    }
}

Spring实际执行时采用双检查策略:

  1. 类级别过滤(快速失败)
  2. 方法级别精确匹配

五、手动模拟调用链实现

手动执行流程揭示了Spring AOP的本质:

java 复制代码
void executeManually(Object target, List<Object> interceptors, 
                    String methodName, Object[] args) {
    // 1. 构建方法调用对象
    CustomMethodInvocation invocation = new CustomMethodInvocation(
        null, target, method, args, target.getClass(), interceptors);
    
    // 2. 启动调用链
    invocation.proceed();
}

这个模拟过程清晰展示了:

  • 拦截器链的封装方式
  • 当前索引的动态推进
  • 目标方法的最终调用

六、设计模式综合应用分析

在Spring AOP的实现中,多种设计模式协同工作:

设计模式 应用场景 优势
适配器模式 统一不同类型的Advice 保持接口一致性
代理模式 创建目标对象的代理 控制对象访问
责任链模式 拦截器链执行 动态处理流程
策略模式 Pointcut的不同匹配算法 灵活替换匹配策略
工厂模式 通过ProxyFactory创建代理对象 封装复杂创建逻辑

七、性能优化启示

在实际应用中需注意:

  1. 减少Pointcut复杂度:避免在matches()中执行重操作

  2. 合理排序拦截器:高频拦截器前置

  3. 慎用Around通知:避免嵌套过深

  4. 选择合适代理

    java 复制代码
    // 显式指定代理方式
    proxyFactory.setProxyTargetClass(true); // 强制CGLIB

八、总结

Spring AOP的精妙之处在于:

  1. 分层设计:Pointcut/Advice/Advisor各司其职
  2. 模式协同:适配器+责任链实现灵活扩展
  3. 开放扩展:支持自定义Pointcut和Interceptor
  4. 统一抽象:MethodInvocation封装调用上下文

流程总图

完整代码

java 复制代码
package com.dwl.call_chain;

import jakarta.annotation.Nullable;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.Advisor;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.Pointcut;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.framework.ReflectiveMethodInvocation;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.aop.support.StaticMethodMatcherPointcut;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * 业务服务接口
 */
interface UserService {
    void createUser(String username, String email);

    void deleteUser(Long userId);

    void getUserInfo(Long userId);
}

/**
 * 业务服务实现
 */
@Slf4j
class UserServiceImpl implements UserService {
    @Override
    public void createUser(String username, String email) {
        log.debug("[UserServiceImpl] 执行创建用户: {} ({})", username, email);
    }

    @Override
    public void deleteUser(Long userId) {
        log.debug("[UserServiceImpl] 执行删除用户: ID={}", userId);
    }

    @Override
    public void getUserInfo(Long userId) {
        log.debug("[UserServiceImpl] 获取用户信息: ID={}", userId);
    }
}

/**
 * 自定义切入点 - 只匹配创建和删除用户方法
 * 原理:基于AOP联盟的Pointcut实现,Spring在执行时会对每个方法进行匹配检查
 */
@Slf4j
class UserMutationPointcut extends StaticMethodMatcherPointcut {
    @Override
    public boolean matches(Method method, @Nullable Class<?> targetClass) {
        // 只匹配包含"create"或"delete"的方法名
        boolean isMatch = method.getName().contains("create") || method.getName().contains("delete");
        log.debug("[UserMutationPointcut] 方法匹配检查: {} - 结果: {}", method.getName(), isMatch);
        return isMatch;
    }

    @Override
    @NonNull
    public ClassFilter getClassFilter() {
        // 限定只对UserService接口生效
        return clazz -> {
            boolean match = clazz == UserService.class;
            log.debug("[UserMutationPointcut] 类匹配检查: {} - 结果: {}", clazz.getSimpleName(), match);
            return match;
        };
    }
}

/**
 * 自定义切入点 - 匹配所有方法
 */
@Slf4j
class AllMethodsPointcut extends StaticMethodMatcherPointcut {
    @Override
    public boolean matches(@NonNull Method method, @NonNull Class<?> targetClass) {
        log.debug("[AllMethodsPointcut] 匹配所有方法: {}", method.getName());
        return true; // 无条件匹配所有方法
    }
}

/**
 * 审计拦截器 - 用于关键业务操作
 * 实现AOP联盟的MethodInterceptor接口
 * 原理:作为Advice被织入到连接点(join point)
 */
@Slf4j
class AuditInterceptor implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        String methodName = invocation.getMethod().getName();
        Object[] args = invocation.getArguments();

        log.debug("[审计拦截器] >>> 进入审计处理, 方法: {}", methodName);
        System.out.println("=== AUDIT START: " + methodName + " ===");
        System.out.println("| User: admin@example.com");
        System.out.println("| Args: " + java.util.Arrays.toString(args));

        // 重要:调用拦截器链中的下一个处理器
        log.debug("[审计拦截器] 执行proceed(), 进入下一个拦截器或目标方法");
        Object result = invocation.proceed();

        System.out.println("| Result: " + result);
        System.out.println("=== AUDIT END ===");
        log.debug("[审计拦截器] <<< 退出审计处理, 方法: {}", methodName);
        return result;
    }
}

/**
 * 性能监控拦截器 - 用于所有方法
 * 原理:通过计算执行时间实现性能监控
 */
@Slf4j
class PerformanceInterceptor implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        long startTime = System.currentTimeMillis();
        String methodName = invocation.getMethod().getName();

        log.debug("[性能拦截器] >>> 开始执行计时, 方法: {}", methodName);

        // 重要:触发后续调用链(可能是其他拦截器或目标方法)
        Object result = invocation.proceed();

        long duration = System.currentTimeMillis() - startTime;
        log.debug("[性能拦截器] 方法执行完成, 耗时: {}ms", duration);
        System.out.println("[Perf] " + methodName + " executed in " + duration + "ms");

        log.debug("[性能拦截器] <<< 退出性能监控处理");
        return result;
    }
}

/**
 * 自定义的ReflectiveMethodInvocation子类
 * 原理:Spring AOP核心调用处理器,管理拦截器链的执行顺序
 * <p>
 * 关键机制:
 * 1. 维护拦截器列表的当前位置
 * 2. proceed()方法驱动调用链前进
 * 3. 当所有拦截器执行完毕后调用目标方法
 */
@Slf4j
class CustomMethodInvocation extends ReflectiveMethodInvocation {
    public CustomMethodInvocation(Object proxy, Object target, Method method, Object[] args,
                                  Class<?> targetClass, List<Object> interceptors) {
        super(proxy, target, method, args, targetClass, interceptors);
        log.debug("创建自定义方法调用处理器 | 目标类: {} | 方法: {} | 拦截器数量: {}",
                targetClass.getSimpleName(), method.getName(), interceptors.size());
    }
}

/**
 * 核心流程:
 * 1. 创建目标对象(被代理对象)
 * 2. 创建切点(Pointcut)和通知(Advice)
 * 3. 通过Advisor将切点和通知关联
 * 4. 使用ProxyFactory创建代理对象:
 * - 默认使用JDK动态代理(针对接口)
 * - 无接口时使用CGLIB代理
 * 5. 拦截器链执行机制:
 * - 创建MethodInvocation对象
 * - 按顺序执行拦截器
 * - 最后执行目标方法
 *
 * @ClassName SpringAopWithAdvisorDemo
 * @Description
 * @Version 1.0.0
 * @Date 2025
 * @Author By Dwl
 */
@Slf4j
public class SpringAopWithAdvisorDemo {
    public static void main(String[] args) throws Throwable {
        log.debug("===== Spring AOP 底层原理演示 =====");

        // 创建目标对象(实际业务实现)
        UserService target = new UserServiceImpl();
        log.debug("创建目标对象: {}", target.getClass().getName());

        // ============= 创建Advisor =============
        // Advisor 1: 审计顾问 (仅作用于变更操作)
        Pointcut mutationPointcut = new UserMutationPointcut();
        Advice auditAdvice = new AuditInterceptor();
        Advisor auditAdvisor = new DefaultPointcutAdvisor(mutationPointcut, auditAdvice);
        log.debug("创建审计Advisor | 切点: {} | 通知: {}",
                mutationPointcut.getClass().getSimpleName(), auditAdvice.getClass().getSimpleName());

        // Advisor 2: 性能顾问 (作用于所有方法)
        Pointcut allMethodsPointcut = new AllMethodsPointcut();
        Advice perfAdvice = new PerformanceInterceptor();
        Advisor perfAdvisor = new DefaultPointcutAdvisor(allMethodsPointcut, perfAdvice);
        log.debug("创建性能Advisor | 切点: {} | 通知: {}",
                allMethodsPointcut.getClass().getSimpleName(), perfAdvice.getClass().getSimpleName());

        // ==================== 方式1: 标准Spring代理 ====================
        log.debug("\n========= 创建Spring代理 =========");
        ProxyFactory proxyFactory = new ProxyFactory(target);
        proxyFactory.addInterface(UserService.class);
        proxyFactory.addAdvisor(auditAdvisor);
        proxyFactory.addAdvisor(perfAdvisor);

        log.debug("代理工厂配置 | 代理接口: {} | Advisor数量: {}",
                UserService.class.getSimpleName(), proxyFactory.getAdvisors().length);

        UserService proxy = (UserService) proxyFactory.getProxy();
        log.debug("代理创建完成 | 代理类: {}", proxy.getClass().getName());
        log.debug("代理技术: {}", proxyFactory.getProxy().toString().contains("$Proxy")
                ? "JDK动态代理" : "CGLIB");

        // 通过代理对象执行方法
        log.debug("\n>>>>>> 执行 createUser <<<<<<");
        proxy.createUser("john_doe", "john@example.com");

        log.debug("\n>>>>>> 执行 deleteUser <<<<<<");
        proxy.deleteUser(123L);

        log.debug("\n>>>>>> 执行 getUserInfo <<<<<<");
        proxy.getUserInfo(456L);
        log.debug("\n");

        // ==================== 方式2: 手动创建调用链 ====================
        log.debug("========= 手动创建调用链 (模拟Spring执行过程) =========");

        // 获取所有拦截器(通过Advisor获取)
        List<Object> interceptors = new ArrayList<>();
        for (Advisor advisor : proxyFactory.getAdvisors()) {
            interceptors.add(advisor.getAdvice());
        }
        log.debug("收集到拦截器: {} 个", interceptors.size());
        interceptors.forEach(interceptor ->
                log.debug(" - 拦截器: {}", interceptor.getClass().getSimpleName()));

        // 测试方法1: createUser (会触发所有拦截器)
        log.debug("\n--- 手动执行 createUser ---");
        executeManually(target, interceptors, "createUser", new Object[]{"test_user", "test@example.com"});

        // 测试方法2: getUserInfo (只会触发性能拦截器)
        log.debug("\n--- 手动执行 getUserInfo ---");
        executeManually(target, interceptors, "getUserInfo", new Object[]{789L});
    }

    /**
     * 手动执行方法调用流程
     * 模拟Spring代理的核心执行过程:
     * 1. 创建ReflectiveMethodInvocation对象
     * 2. 调用proceed()启动拦截器链
     * 3. 调用链依次执行:
     * - 按顺序执行所有MethodInterceptor
     * - 最后执行目标方法
     */
    private static void executeManually(Object target, List<Object> interceptors,
                                        String methodName, Object[] args) throws Throwable {
        // 获取方法对象
        Class<?>[] paramTypes = getParameterTypes(args);
        log.debug("获取方法元数据 | 方法名: {} | 参数类型: {}", methodName, paramTypes);

        Method method = UserService.class.getMethod(methodName, paramTypes);

        // 创建自定义方法调用处理器(核心)
        CustomMethodInvocation invocation = new CustomMethodInvocation(
                null,                // 代理对象(手动调用不需要)
                target,              // 目标对象
                method,              // 目标方法
                args,                // 方法参数
                target.getClass(),   // 目标类
                interceptors         // 拦截器链
        );

        // 核心:启动拦截器链执行(模拟Spring代理的invoke方法)
        log.debug(">>>>>> 启动拦截器链执行");
        invocation.proceed();
        log.debug("<<<<<< 拦截器链执行完成");
    }

    private static Class<?>[] getParameterTypes(Object[] args) {
        Class<?>[] paramTypes = new Class[args.length];
        for (int i = 0; i < args.length; i++) {
            paramTypes[i] = args[i].getClass();
            log.debug("参数类型检测 | 参数[{}]: {}", i, paramTypes[i].getSimpleName());
        }
        return paramTypes;
    }
}