Spring AOP 源码-通知链的执行与责任链模式

在说这节的重点前,我们回顾一下几个重要概念:

  • 切面:封装了横切关注点的模块,包含通知和切点
  • 通知:定义增强逻辑的代码,前置、后置、环绕等
  • 切点:定义哪些方法需要被增强的匹配规则

那自然引出我们这节的重点,通知链,通知链指的是当一个方法匹配多个通知的情况下,AOP将这些串成一个链来依次执行。那我们上文说的代理对象就是拦截目标方法然后来执行通知链。

Spring AOP的通知链执行逻辑高度依赖责任链模式,通过链式调用协调多个通知的执行顺序,确保灵活性和扩展性,那下面我们具体来看下是如何实现的。另外,责任链模式是一种设计模式,而通知链是具体的应用,大家别搞混了。

1. 责任链模式特点

责任链模式是一种设计模式,也就是允许多个处理者依次处理请求,处理者决定是否处理还是给下一位,这个名字就很贴切,很符合链条式,比较核心的优点是:

  • 能够解耦请求与处理:请求发送者无需知道处理者
  • 动态组合:链上的处理者可以动态修改
  • 顺序执行

那在AOP的通知链就完美契合责任链模式,每个通知 就是一个处理者目标方法的调用请求,Spring通过代理对象将方法调用分发到通知链,通知按顺序执行。

2. Spring AOP通知链的执行流程

整个流程的调用链如下:

客户端调用->代理对象->通知链(Advice1->Advice2->Advice3......->目标方法)->返回结果

3. 通知链的构建与执行

SpringAOP的通知链实现在下面几个核心源码类里:

  • ReflectiveMethodInvocation:管理通知链的执行,维护通知列表和调用状态
  • CglibAopProxy和JdkDynamicAopProxy:实现代理逻辑,触发通知链
  • DefaultAdvisorChainFactory:构建通知链

下面我们从这三个类入手来看一下这一块的内容:

3.1 通知链的构建

DefaultAdvisorChainFactory 的核心方法是getInterceptorsAndDynamicInterceptors

scss 复制代码
public class DefaultAdvisorChainFactory implements AdvisorChainFactory {
    @Override
    public List<Object> getInterceptorsAndDynamicInterceptors(
            AdvisedSupport config, Method method, Class<?> targetClass) {
        List<Object> interceptorList = new ArrayList<>(config.getAdvisors().length);
        Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
        Advisor[] advisors = config.getAdvisors();

        // 遍历所有 Advisor
        for (Advisor advisor : advisors) {
            if (advisor instanceof PointcutAdvisor) {
                PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
                // 检查切点是否匹配
                if (pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass) &&
                        pointcutAdvisor.getPointcut().getMethodMatcher().matches(method, actualClass)) {
                    // 获取通知并转换为拦截器
                    MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
                    interceptorList.addAll(Arrays.asList(interceptors));
                }
            }
        }
        return interceptorList;
    }
}

这里的关键是:首先通过AdvisedSupportAdvisor 遍历,然后通过PointcutAdvisor的ClassFilterMethodMatcher判断方法是否需要增强,然后就是拦截器转换最后就是按优先级排序。

3.2 通知链的执行

ReflectiveMethodInvocation 的核心方法为proceed

kotlin 复制代码
public class ReflectiveMethodInvocation implements MethodInvocation {
    protected final Object proxy;
    protected final Object target;
    protected final Method method;
    protected Object[] arguments;
    private final List<?> interceptorsAndDynamicMethodMatchers;
    private int currentInterceptorIndex = -1;

    public ReflectiveMethodInvocation(
            Object proxy, Object target, Method method, Object[] arguments,
            Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) {
        this.proxy = proxy;
        this.target = target;
        this.method = method;
        this.arguments = arguments;
        this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;
    }

    @Override
    public Object proceed() throws Throwable {
        // 如果所有拦截器执行完毕,调用目标方法
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            return invokeJoinpoint();
        }

        // 获取下一个拦截器
        Object interceptorOrInterceptionAdvice =
                this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
        if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
            InterceptorAndDynamicMethodMatcher dm =
                    (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
            if (dm.methodMatcher.matches(this.method, this.target.getClass(), this.arguments)) {
                return dm.interceptor.invoke(this);
            } else {
                return proceed(); // 跳过不匹配的拦截器
            }
        } else {
            // 执行拦截器逻辑
            return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
        }
    }

    protected Object invokeJoinpoint() throws Throwable {
        return AopUtils.invokeJoinpointUsingReflection(this.target, this.method, this.arguments);
    }
}

关键点是:

  • 链式调用:proceed方法通过currentInterceptorIndex维护当前执行的拦截器的位置,递归调用形成链式执行
  • 拦截器执行:每个拦截器(MethodInterceptor)通过invoke方法执行逻辑,并决定是否调用proceed继续链的执行
  • 目标方法调用:当所有拦截器执行完毕,invokeJoinpoint通过反射调用目标方法
  • 动态匹配:支持动态切点匹配,在运行时检查方法是否匹配

3.3 代理对象的拦截逻辑

这个我们在上篇文章说过,核心方法就是intercept:

typescript 复制代码
private static class DynamicAdvisedInterceptor implements MethodInterceptor {
    private final AdvisedSupport advised;

    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        // 获取通知链
        List<Object> chain = advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
        Object retVal;
        if (chain.isEmpty()) {
            // 无通知,直接调用目标方法
            retVal = methodProxy.invoke(target, args);
        } else {
            // 创建 MethodInvocation,触发通知链
            MethodInvocation invocation = new ReflectiveMethodInvocation(
                    proxy, target, method, args, targetClass, chain);
            retVal = invocation.proceed();
        }
        return retVal;
    }
}

关键点是:

  • 通知链获取:通过AdvisedSupport获取适用于当前方法的通知链
  • MethodInvocation创建:封装代理对象、目标对象、方法、参数和通知链
  • 链式调用:调用ReflectiveMethodInvocation.proceed触发通知链的执行

另外,Spring AOP默认按以下顺序来执行通知的:

@Around(前置)→ @Before → 目标方法 → @After → @Around(后置)

4. 总结

在整个源码中,有一些关键的优化,例如使用缓存、反射、拦截器统一拦截。那这篇文章主要有两个关键点,一个是通知链的构建还有一个链式执行

相关推荐
MaCa .BaKa1 分钟前
33-公交车司机管理系统
java·vue.js·spring boot·maven
洛小豆27 分钟前
一个场景搞明白Reachability Fence,它就像一道“结账前别走”的红外感应门
java·后端·面试
500佰29 分钟前
AI提示词(Prompt)设计优化方案 | 高效使用 AI 工具
java·人工智能·prompt·ai编程
摘星编程31 分钟前
并发设计模式实战系列(4):线程池
java·设计模式·并发编程
PGCCC44 分钟前
【PGCCC】Postgres MVCC 内部:更新与插入的隐性成本
java·开发语言·数据库
诺亚凹凸曼1 小时前
Java基础系列-LinkedList源码解析
java·开发语言
爱上大树的小猪1 小时前
【前端样式】用 aspect-ratio 实现等比容器:视频封面与图片占位的终极解决方案
前端·css·面试
Maỿbe1 小时前
手动实现LinkedList
java·开发语言
江城开朗的豌豆1 小时前
CSS篇:HTML与XHTML:关键区别与实际应用解析
前端·css·面试
爱喝一杯白开水1 小时前
java基础从入门到上手(九):Java - List、Set、Map
java·list·set·map