SpringAop新链实现任意无参方法调用
字数 2111 2025-08-29 22:41:01

Spring AOP 新链实现任意无参方法调用技术分析

1. AOP核心概念

1.1 基本术语

  • 切面(Aspect): 公共功能的实现模块,如日志、权限、验签等。使用@Aspect注解修饰的Java类
  • 通知(Advice): 切面的具体实现方法,分为:
    • 前置通知(Before)
    • 后置通知(AfterReturning)
    • 异常通知(AfterThrowing)
    • 最终通知(After)
    • 环绕通知(Around)
  • 连接点(JoinPoint): 程序运行中可插入切面的位置,Spring仅支持方法级连接点
  • 切点(PointCut): 定义通知应应用到哪些连接点的规则
  • 引入(Introduction): 动态为类添加新接口实现

1.2 依赖关系

spring-boot-starter-aop包含:

  • spring-aop
  • aspectjweaver

2. AOP实现机制

2.1 动态代理与拦截

JdkDynamicAopProxy类:

  • JDK动态代理的调用处理器
  • 代理对象方法调用时跳转到invoke方法处理
  • 调用目标方法前检查是否配置拦截链

两种处理路径:

  1. 拦截链为空(chain.isEmpty()): 直接反射调用目标方法
  2. 配置拦截链: 通过拦截链层层处理后再调用目标方法

2.2 拦截链构建

AdvisedSupport类处理代理配置:

  • readObject初始化空的methodCache Map
  • 首次获取拦截链返回null
  • 通过getInterceptorsAndDynamicInterceptionAdvice构建拦截链

拦截链构建过程:

  1. 从配置获取Advisor(包含advice和匹配过滤器)
  2. 判断advice类型(PointCut或Introduction)
  3. 通过DefaultAdvisorAdapterRegistry.getInterceptors获取Interceptor
  4. 合并到interceptorList

MethodInterceptor接口:

  • 用于拦截目标方法调用
  • 通过invoke方法添加拦截逻辑

2.3 拦截链执行

ReflectiveMethodInvocation类:

  • currentInterceptorIndex跟踪当前拦截器位置
  • 执行完所有拦截器后调用目标方法(invokeJoinpoint)
  • 动态匹配方法时先检查方法是否匹配

3. 切面方法调用机制

3.1 Advice调用流程

AbstractAspectJAdvice抽象类:

  • 包含各种通知类型的子类(Before, After等)
  • invokeAdviceMethod最终调用切面方法
  • aspectJAdviceMethod: advice对应的方法(如logBefore)

方法恢复:

  • Method未实现Serializable
  • aspectJAdviceMethodtransient修饰
  • readObject时通过反射恢复

3.2 实例工厂

AspectInstanceFactory实现类:

  1. SimpleAspectInstanceFactory: 反射调用无参构造器(不可序列化)
  2. SingletonAspectInstanceFactory: 单例工厂(可序列化)
  3. SimpleBeanFactoryAwareAspectInstanceFactory: 由Bean工厂创建
  4. SimpleJndiBeanFactory: JNDI工厂(不可序列化)

3.3 参数绑定

AbstractAspectJAdvice#argBinding:

  • jpMatch来自getJoinPointMatch
  • 需要ProxyMethodInvocation#setUserAttribute设置属性
  • 当前仅支持无参方法调用

4. 任意无参方法调用实现

4.1 关键问题

直接构造会报错缺少MethodInvocation:

  • ExposeInvocationInterceptor拦截器负责设置MethodInvocation
  • 需要先注册此interceptor再注册advice

4.2 实现步骤

  1. 创建SingletonAspectInstanceFactory实例
  2. 设置目标方法(如TemplatesImpl#newTransformer)
  3. 构建拦截链:
    • 先添加ExposeInvocationInterceptor
    • 再添加自定义advice
  4. 通过JdkDynamicAopProxy执行调用链

4.3 示例代码结构

// 1. 创建单例工厂
SingletonAspectInstanceFactory factory = new SingletonAspectInstanceFactory(targetObject);

// 2. 设置目标方法
Method method = TemplatesImpl.class.getMethod("newTransformer");

// 3. 构建拦截链
List<Object> interceptors = new ArrayList<>();
interceptors.add(new ExposeInvocationInterceptor());
interceptors.add(new MyAdvice(factory, method));

// 4. 创建代理调用
JdkDynamicAopProxy proxy = new JdkDynamicAopProxy(config);
proxy.invoke(proxy, method, new Object[]{});

5. 限制与注意事项

  1. 仅支持无参方法调用
  2. 依赖SingletonAspectInstanceFactory可序列化
  3. 拦截链顺序必须正确(ExposeInvocationInterceptor优先)
  4. 目标类必须可访问
  5. 安全限制可能阻止某些方法调用

6. 防御建议

  1. 限制反序列化源
  2. 监控可疑的AOP配置
  3. 更新Spring框架版本
  4. 实施最小权限原则
  5. 对输入进行严格验证
Spring AOP 新链实现任意无参方法调用技术分析 1. AOP核心概念 1.1 基本术语 切面(Aspect) : 公共功能的实现模块,如日志、权限、验签等。使用 @Aspect 注解修饰的Java类 通知(Advice) : 切面的具体实现方法,分为: 前置通知(Before) 后置通知(AfterReturning) 异常通知(AfterThrowing) 最终通知(After) 环绕通知(Around) 连接点(JoinPoint) : 程序运行中可插入切面的位置,Spring仅支持方法级连接点 切点(PointCut) : 定义通知应应用到哪些连接点的规则 引入(Introduction) : 动态为类添加新接口实现 1.2 依赖关系 spring-boot-starter-aop 包含: spring-aop aspectjweaver 2. AOP实现机制 2.1 动态代理与拦截 JdkDynamicAopProxy 类: JDK动态代理的调用处理器 代理对象方法调用时跳转到 invoke 方法处理 调用目标方法前检查是否配置拦截链 两种处理路径: 拦截链为空( chain.isEmpty() ): 直接反射调用目标方法 配置拦截链: 通过拦截链层层处理后再调用目标方法 2.2 拦截链构建 AdvisedSupport 类处理代理配置: readObject 初始化空的 methodCache Map 首次获取拦截链返回null 通过 getInterceptorsAndDynamicInterceptionAdvice 构建拦截链 拦截链构建过程: 从配置获取 Advisor (包含advice和匹配过滤器) 判断advice类型(PointCut或Introduction) 通过 DefaultAdvisorAdapterRegistry.getInterceptors 获取Interceptor 合并到 interceptorList MethodInterceptor 接口: 用于拦截目标方法调用 通过 invoke 方法添加拦截逻辑 2.3 拦截链执行 ReflectiveMethodInvocation 类: currentInterceptorIndex 跟踪当前拦截器位置 执行完所有拦截器后调用目标方法( invokeJoinpoint ) 动态匹配方法时先检查方法是否匹配 3. 切面方法调用机制 3.1 Advice调用流程 AbstractAspectJAdvice 抽象类: 包含各种通知类型的子类(Before, After等) invokeAdviceMethod 最终调用切面方法 aspectJAdviceMethod : advice对应的方法(如 logBefore ) 方法恢复: Method 未实现 Serializable aspectJAdviceMethod 由 transient 修饰 readObject 时通过反射恢复 3.2 实例工厂 AspectInstanceFactory 实现类: SimpleAspectInstanceFactory : 反射调用无参构造器(不可序列化) SingletonAspectInstanceFactory : 单例工厂(可序列化) SimpleBeanFactoryAwareAspectInstanceFactory : 由Bean工厂创建 SimpleJndiBeanFactory : JNDI工厂(不可序列化) 3.3 参数绑定 AbstractAspectJAdvice#argBinding : jpMatch 来自 getJoinPointMatch 需要 ProxyMethodInvocation#setUserAttribute 设置属性 当前仅支持无参方法调用 4. 任意无参方法调用实现 4.1 关键问题 直接构造会报错缺少 MethodInvocation : ExposeInvocationInterceptor 拦截器负责设置 MethodInvocation 需要先注册此interceptor再注册advice 4.2 实现步骤 创建 SingletonAspectInstanceFactory 实例 设置目标方法(如 TemplatesImpl#newTransformer ) 构建拦截链: 先添加 ExposeInvocationInterceptor 再添加自定义advice 通过 JdkDynamicAopProxy 执行调用链 4.3 示例代码结构 5. 限制与注意事项 仅支持无参方法调用 依赖 SingletonAspectInstanceFactory 可序列化 拦截链顺序必须正确(ExposeInvocationInterceptor优先) 目标类必须可访问 安全限制可能阻止某些方法调用 6. 防御建议 限制反序列化源 监控可疑的AOP配置 更新Spring框架版本 实施最小权限原则 对输入进行严格验证