Spring AOP静态与动态通知的协作原理

一、核心架构分析

1. Spring AOP核心组件

classDiagram class AnnotationAwareAspectJAutoProxyCreator { + postProcessAfterInitialization() + getAdvicesAndAdvisorsForBean() } class ProxyFactory { + target : Object + advisors : List + getProxy() + getInterceptorsAndDynamicInterceptionAdvice() } class Advisor { <> + getAdvice() + isPerInstance() } class AspectJPointcutAdvisor { - advice : Advice - pointcut : Pointcut + matches() } class ReflectiveMethodInvocation { - interceptors : List - currentInterceptorIndex : int + proceed() } AnnotationAwareAspectJAutoProxyCreator --> ProxyFactory : 创建 ProxyFactory "1" --> "*" Advisor : 包含 Advisor "1" --> "1" Advice : 包含 ProxyFactory --> ReflectiveMethodInvocation : 创建 ReflectiveMethodInvocation --> Advice : 执行

二、底层运作机制详解

1. 代理创建流程

AnnotationAwareAspectJAutoProxyCreator处理流程:

java 复制代码
public Object postProcessAfterInitialization(Object bean, String beanName) {
    // 步骤1: 检查是否需要创建代理
    if (!shouldSkip(bean.getClass(), beanName)) {
        // 步骤2: 筛选匹配的Advisor
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass());
        
        // 步骤3: 创建代理
        Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, bean);
        return proxy;
    }
    return bean;
}

protected Object createProxy(Class<?> beanClass, String beanName, 
                            Object[] specificInterceptors, Object target) {
    // 步骤4: 构建ProxyFactory
    ProxyFactory proxyFactory = new ProxyFactory();
    
    // 步骤5: 添加Advisor到ProxyFactory
    Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
    proxyFactory.addAdvisors(advisors);
    
    // 步骤6: 设置代理目标
    proxyFactory.setTarget(target);
    
    // 步骤7: 创建代理对象
    return proxyFactory.getProxy();
}

2. 拦截器链构建原理

ProxyFactory内部机制:

java 复制代码
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
        Method method, @Nullable Class<?> targetClass) {
    
    // 缓存机制提升性能
    MethodCacheKey cacheKey = new MethodCacheKey(method);
    if (cache.get(cacheKey) != null) { ... }
    
    // 核心处理逻辑
    List<Object> interceptorList = new ArrayList<>();
    
    for (Advisor advisor : getAdvisors()) {
        // 1. 检查是否匹配当前方法
        if (advisor.getPointcut().getMethodMatcher().matches(method, targetClass)) {
            
            // 2. 转换Advisor为MethodInterceptor
            MethodInterceptor[] interceptors = 
                registry.getInterceptors(advisor);
            
            // 3. 静态通知处理
            if (advisor.getPointcut().isRuntime()) {
                // 4. 动态通知特殊包装
                interceptorList.add(new InterceptorAndDynamicMethodMatcher(
                    interceptors[0], advisor.getPointcut().getMethodMatcher());
            } else {
                // 5. 静态通知直接加入
                interceptorList.add(interceptors[0]);
            }
        }
    }
    
    // 返回不可变列表
    return interceptorList;
}

3. 拦截器链执行引擎

ReflectiveMethodInvocation核心流程:

java 复制代码
public Object proceed() throws Throwable {
    // 1. 检查是否到达链末端
    if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
        // 执行目标方法
        return invokeJoinpoint();
    }

    // 2. 获取当前拦截器
    Object interceptorOrInterceptionAdvice = 
        this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);

    // 3. 动态通知特殊处理
    if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
        InterceptorAndDynamicMethodMatcher dm = 
            (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
        
        // 4. 运行时匹配判断
        if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
            // 5. 执行动态通知逻辑
            return dm.interceptor.invoke(this);
        } else {
            // 6. 跳过不匹配的通知
            return proceed();
        }
    } else {
        // 7. 执行静态通知
        return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
    }
}

三、静态通知与动态通知对比

特性 静态通知 动态通知
代理创建阶段 直接转换为Interceptor 包装为InterceptorAndDynamicMethodMatcher
匹配时机 Bean创建时 每次方法调用时
参数依赖 需要方法参数
执行效率 ⚡ 高(O(1)) ⚠ 较低(每次调用需匹配)
匹配器类型 StaticMethodMatcher DynamicMethodMatcher
典型应用 @Before无参数绑定 @Before(args)或@annotation

四、性能调优建议

  1. 避免过度使用动态通知​:在频繁调用的方法上使用动态通知可能产生显著性能开销

  2. 缓存拦截器链​:Spring采用MethodCacheKey机制缓存方法拦截器链

    java 复制代码
    public List<Object> getInterceptorsAndDynamicInterceptionAdvice() {
        // 缓存KEY:方法+目标类
        MethodCacheKey cacheKey = new MethodCacheKey(method, targetClass);
        // 缓存处理逻辑
        if (cache.containsKey(cacheKey)) {
            return cache.get(cacheKey);
        }
        // ... 计算逻辑
    }
  3. 优化Pointcut表达式​:

    • 减少运行时检查(如避免args, this, target等)
    • 优先使用execution而非annotation
  4. 预过滤机制​:

    java 复制代码
    public boolean matches(Method method, Class<?> targetClass) {
        // 1. 快速检查(类级别)
        if (!isCandidateClass(targetClass)) {
            return false;
        }
        
        // 2. 方法签名匹配
        return Modifier.isPublic(method.getModifiers()) && 
               method.getName().startsWith("do");
    }

五、源码级实现差异

1. 静态通知实现类

java 复制代码
public class AspectJMethodBeforeAdvice implements MethodInterceptor {
    public Object invoke(MethodInvocation mi) throws Throwable {
        // 无匹配判断直接执行
        this.adviceMethod.invoke(this.aspectInstance);
        return mi.proceed();
    }
}

2. 动态通知实现类

java 复制代码
class AspectJAfterThrowingAdvice extends AbstractAspectJAdvice 
        implements MethodInterceptor, AfterAdvice {
        
    public Object invoke(MethodInvocation mi) throws Throwable {
        try {
            return mi.proceed();
        } catch (Throwable ex) {
            // 动态异常类型匹配
            if (shouldInvokeOnThrowing(ex)) {
                invokeAdviceMethod(ex);
            }
            throw ex;
        }
    }
}

六、核心流程示意图

sequenceDiagram participant Client participant Proxy participant Invocation participant AdviceA participant AdviceB participant Target Client ->> Proxy: foo(100) Proxy ->> Invocation: 创建Invocation(advices) Invocation ->> AdviceA: proceed() AdviceA -->> Invocation: 静态通知执行 Invocation ->> AdviceB: proceed() rect rgba(255, 220, 0, 0.1) AdviceB ->> AdviceB: 参数匹配(100) AdviceB -->> Invocation: 动态通知执行 end Invocation ->> Target: foo(100) Target -->> Invocation: 结果 Invocation -->> Proxy: 返回 Proxy -->> Client: 结果

七、高级应用场景

1. 混合通知类型执行顺序

less 复制代码
  ╭── @Around (before)
  │   ╭── @Before (静态)
  │   │   ╭── @Before (动态)
  │   │   │   ╭── 目标方法
  │   │   │   ╰── @AfterReturning/@AfterThrowing
  │   │   ╰── @After (动态)
  │   ╰── @After (静态)
  ╰── @Around (after)

2. 自定义Pointcut优化策略

java 复制代码
public class FastDynamicPointcut extends DynamicMethodMatcherPointcut {
    // 缓存匹配结果提升性能
    private Map<Method, Boolean> methodCache = new ConcurrentHashMap<>();
    
    @Override
    public boolean matches(Method method, Class<?> targetClass, Object[] args) {
        return methodCache.computeIfAbsent(method, m -> 
            computeMatch(m, targetClass, args));
    }
    
    private boolean computeMatch(Method method, Class<?> targetClass, Object[] args) {
        // 复杂的匹配逻辑
    }
}

结论

Spring AOP通过精妙的架构设计实现了静态通知与动态通知的高效协作:

  1. 编译时优化:代理创建阶段最大化处理静态信息
  2. 运行时延迟计算:对动态通知采用懒匹配机制
  3. 智能拦截器链:结合静态与动态执行路径的混合调度
  4. 性能平衡策略:通过缓存和预过滤减少动态匹配开销

理解这些底层机制对于构建高性能AOP应用、实现深度定制扩展至关重要。建议通过源码调试跟踪ReflectiveMethodInvocation.proceed()方法执行路径,可直观观察拦截器链的执行状态变化。

完整代码

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

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.framework.ReflectiveMethodInvocation;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.context.support.GenericApplicationContext;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

import static com.dwl.advisor_aspect.FindEligibleAdvisorCase.getAdvisorsFromProxyCreator;

/**
 * @ClassName DynamicNotification
 * @Description 展示Spring如何组合静态/动态通知,及AOP代理执行的全流程
 * @Version 1.0.0
 * @Date 2025
 * @Author By Dwl
 */
@Slf4j
public class DynamicNotificationCase {

    // 切面定义 - 包含静态和动态两种通知类型
    @Aspect
    @Slf4j
    public static class DynamicNotificationAspect {
        /**
         * 静态通知示例:
         * 1. 无方法参数绑定
         * 2. 通知实例在代理创建时确定
         * 3. 执行时无需运行时匹配
         */
        @Before("execution(* com.dwl.dynamic_notification.DynamicNotificationCase..foo(..))")
        public void beforeA() {
            log.debug("⟳ [静态通知执行] DynamicNotificationAspect.beforeA()");
        }

        /**
         * 动态通知示例:
         * 1. 需要参数绑定(args(x))
         * 2. 通知实例需在每次调用时动态生成
         * 3. 依赖运行时参数匹配
         */
        @Before("execution(* com.dwl.dynamic_notification.DynamicNotificationCase..foo(..)) && args(x)")
        public void beforeB(int x) {
            log.debug("⟳ [动态通知执行] DynamicNotificationAspect.beforeB({})", x);
        }
    }

    // 被代理的目标类
    public static class DynamicNotificationBean {
        public void foo(int x) {
            log.info("▨ [目标方法执行] DynamicNotificationBean.foo({})", x);
        }
    }

    // 配置类声明AOP组件
    @Configuration
    public static class DynamicNotificationConfig {
        @Bean
        public AnnotationAwareAspectJAutoProxyCreator proxyCreator() {
            // 核心AOP代理创建器:负责扫描@Aspect并创建Advisor
            log.debug("🚀 注册AnnotationAwareAspectJAutoProxyCreator - AOP核心代理构造器");
            return new AnnotationAwareAspectJAutoProxyCreator();
        }

        @Bean
        public DynamicNotificationAspect dynamicNotificationAspect() {
            log.debug("➕ 注册切面组件: DynamicNotificationAspect");
            return new DynamicNotificationAspect();
        }
    }

    /**
     * 自定义方法调用处理器:继承Spring默认实现
     * 关键作用:组织通知调用链的执行顺序
     */
    public static class MethodInvocation extends ReflectiveMethodInvocation {

        private static final Field CURRENT_INDEX_FIELD;
        private static final Field INTERCEPTORS_FIELD;

        static {
            try {
                // 一次性初始化反射字段
                CURRENT_INDEX_FIELD = ReflectiveMethodInvocation.class.getDeclaredField("currentInterceptorIndex");
                CURRENT_INDEX_FIELD.setAccessible(true);

                INTERCEPTORS_FIELD = ReflectiveMethodInvocation.class.getDeclaredField("interceptorsAndDynamicMethodMatchers");
                INTERCEPTORS_FIELD.setAccessible(true);
            } catch (NoSuchFieldException e) {
                throw new RuntimeException("反射字段初始化失败", e);
            }
        }

        public MethodInvocation(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(), args,
                    interceptors.size(), formatInterceptors(interceptors));
        }

        // 美化拦截器输出格式
        private String formatInterceptors(List<Object> interceptors) {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < interceptors.size(); i++) {
                sb.append(String.format("   %d. %-60s → %s\n",
                        i + 1,
                        interceptors.get(i).getClass().getSimpleName(),
                        extractInterceptorDetail(interceptors.get(i))));
            }
            return sb.toString();
        }

        // 解析拦截器详细信息
        private String extractInterceptorDetail(Object interceptor) {
            try {
                // 尝试解析AspectJMethodBeforeAdvice
                if (interceptor.getClass().getName().contains("AspectJMethodBeforeAdvice")) {
                    Method getAspectMethod = interceptor.getClass().getMethod("getAspectMethod");
                    Method m = (Method) getAspectMethod.invoke(interceptor);
                    return "通知方法: " + m.getName();
                }
            } catch (Exception e) { /* 忽略解析错误 */ }
            return interceptor.toString();
        }

        /**
         * 增强proceed方法日志:展示调用链执行过程
         */
        @Override
        public Object proceed() throws Throwable {
            try {
                int currentIndex = (int) CURRENT_INDEX_FIELD.get(this);
                @SuppressWarnings("unchecked")
                List<Object> interceptors = (List<Object>) INTERCEPTORS_FIELD.get(this);

                if (currentIndex < interceptors.size() - 1) {
                    Object currentInterceptor = interceptors.get(currentIndex + 1);
                    log.debug("🔹 执行拦截器 [{}/{}]: {}",
                            currentIndex + 1,
                            interceptors.size(),
                            currentInterceptor.getClass().getSimpleName());
                } else if (currentIndex == interceptors.size() - 1) {
                    assert getThis() != null;
                    log.debug("🎯 调用目标方法: {}.{}({})",
                            getThis().getClass().getSimpleName(),
                            getMethod().getName(),
                            Arrays.stream(getArguments())
                                    .map(String::valueOf)
                                    .collect(Collectors.joining(", ")));
                }
            } catch (IllegalAccessException e) {
                log.error("访问执行状态失败", e);
            }
            return super.proceed();
        }
    }

    public static void main(String[] args) throws Throwable {
        log.info("""
                ==========================================================================
                🔍 启动动态通知深度解析流程
                ==========================================================================""");

        // 1. 创建并初始化Spring容器
        log.info("⛱ 创建Spring应用上下文");
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean(ConfigurationClassPostProcessor.class); // 配置类处理器
        context.registerBean(DynamicNotificationConfig.class);       // AOP配置
        log.info("🔄 刷新容器 - 触发Bean初始化及AOP配置加载");
        context.refresh();

        // 2. 获取AOP核心组件
        log.info("\n🔍 获取AnnotationAwareAspectJAutoProxyCreator实例");
        AnnotationAwareAspectJAutoProxyCreator proxyCreator = context.getBean(AnnotationAwareAspectJAutoProxyCreator.class);

        // 3. 获取适用当前Bean的Advisor列表
        log.info("\n🕵️‍ 查找适用于DynamicNotificationBean的Advisor");
        List<Advisor> advisorList = getAdvisorsFromProxyCreator(
                proxyCreator,
                DynamicNotificationBean.class,
                "dynamicNotificationBean"
        );
        log.info("✅ 找到{}个Advisor", advisorList.size());

        // 4. 手动创建代理工厂
        log.info("\n🏭 构建代理工厂 (ProxyFactory)");
        DynamicNotificationBean bean = new DynamicNotificationBean();
        ProxyFactory factory = new ProxyFactory();
        factory.setTarget(bean);
        factory.addAdvisors(advisorList); // 添加切面逻辑

        // 5. 生成代理对象
        log.info("\n✨ 创建代理对象");
        Object proxy = factory.getProxy();
        log.info("代理对象类型: {}", proxy.getClass().getName());

        // 6. 获取方法拦截器链
        log.info("\n🔗 获取方法拦截器链");
        Method fooMethod = DynamicNotificationBean.class.getMethod("foo", int.class);
        List<Object> interceptionAdvices = factory.getInterceptorsAndDynamicInterceptionAdvice(
                fooMethod,
                DynamicNotificationBean.class
        );
        log.info("📌 拦截器链包含 {} 个元素", interceptionAdvices.size());

        // 7. 分析拦截器链构成
        log.info("\n🔬 解析拦截器链结构");
        interceptionAdvices.forEach(advice -> {
            try {
                analyzeAdviceStructure(advice);
            } catch (Exception e) {
                log.error("解析拦截器失败", e);
            }
        });

        // 8. 执行代理方法调用
        log.info("\n⚡ 通过自定义调用链执行方法调用");
        MethodInvocation invocation = new MethodInvocation(
                proxy,                      // 代理对象
                bean,                       // 目标对象
                fooMethod,                  // 目标方法
                new Object[]{100},          // 方法参数
                DynamicNotificationBean.class,
                interceptionAdvices         // 拦截器链
        );

        log.info("\n🚦 开始执行拦截器链");
        invocation.proceed();
        log.info("\n✅ 调用链执行完成");

        log.info("""
                ==========================================================================
                🏁 动态通知解析流程结束
                ==========================================================================""");
    }

    /**
     * 深度分析通知对象结构:
     * 区分静态通知和动态通知(含有MethodMatcher)
     */
    private static void analyzeAdviceStructure(Object advice) throws Exception {
        Class<?> interceptorAndMatcherClass = Class.forName(
                "org.springframework.aop.framework.InterceptorAndDynamicMethodMatcher");

        if (interceptorAndMatcherClass.isInstance(advice)) {
            // 动态通知解析
            Field matcherField = interceptorAndMatcherClass.getDeclaredField("matcher");
            matcherField.setAccessible(true);
            Object matcher = matcherField.get(advice);

            Field interceptorField = interceptorAndMatcherClass.getDeclaredField("interceptor");
            interceptorField.setAccessible(true);
            Object interceptor = interceptorField.get(advice);

            log.info("""
                            ⧉ 动态通知结构 (InterceptorAndDynamicMethodMatcher)
                            ├─ 类型: 动态通知 (需运行时匹配)
                            ├─ 匹配器: {}
                            └─ 通知器: {}""",
                    matcher.getClass().getName(),
                    interceptor);
        } else {
            // 静态通知解析
            log.info("""
                            ⧉ 静态通知结构
                            ├─ 类型: 静态通知 (代理创建时确定)
                            └─ 通知器: {}""",
                    advice.getClass().getName());
        }
    }
}
相关推荐
哈基咩4 分钟前
Go 语言模糊测试 (Fuzz Testing) 深度解析与实践
开发语言·后端·golang
mCell4 分钟前
告别轮询!深度剖析 WebSocket:全双工实时通信原理与实战
后端·websocket·http
毛小茛37 分钟前
认识微服务
微服务·云原生·架构
ClouGence39 分钟前
从达梦到 StarRocks:国产数据库实时入仓实践
数据库·后端
洛卡卡了1 小时前
“改个配置还要发版?”搞个配置后台不好吗
前端·后端·架构
用户75389755281751 小时前
《手写解释器》第4章 扫描
后端
kakaZhou7192 小时前
日志系统之Grafana Loki
后端·开源
菜菜的后端私房菜2 小时前
Protocol Buffers!高效数据通信协议
java·后端·protobuf
树獭叔叔2 小时前
Python 锁机制详解:从原理到实践
后端·python
WindrunnerMax2 小时前
浅谈 RAG 并基于 NodeJS 实现基础向量检索服务
架构·node.js·aigc