当前位置: 首页 > backend >正文

浅析Spring AOP 代理的生成机制

浅析Spring AOP 代理的生成机制

  • 一、生成的核心时机:初始化后置处理
  • 二、源码解析:关键类与流程
  • 三、时序图:代理生成在容器初始化中的位置
  • 四、总结:核心要点

在这里插入图片描述

一、生成的核心时机:初始化后置处理

AOP 代理的生成主要发生在以下两个阶段:

  1. 初始化前的提前代理(可选):通过 resolveBeforeInstantiation 方法尝试在 Bean 实例化前生成代理对象
  2. 初始化后的代理生成(主要):通过 postProcessAfterInitialization 方法在 Bean 初始化完成后生成代理对象

AOP 代理对象的生成时机主要集中在 Bean 初始化的后置处理阶段,具体通过 BeanPostProcessor 的扩展机制实现。

如果对BeanPostProcessor 感到陌生,可参考这篇文章:【Spring BeanPostProcessor:机制解读与代码实践】

二、源码解析:关键类与流程

核心后置处理器:AbstractAutoProxyCreator
该类实现了 BeanPostProcessor 接口,核心方法为 postProcessAfterInitialization,用于在 Bean 初始化后生成代理。

源码如下:

public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {if (bean != null) {// 生成用于缓存的键,基于 bean 类型和名称Object cacheKey = getCacheKey(bean.getClass(), beanName);// 检查是否已经在早期代理引用中处理过此 bean,避免重复创建代理或循环依赖问题if (!this.earlyProxyReferences.contains(cacheKey)) {// 【核心方法】:具体生成代理对象的逻辑return wrapIfNecessary(bean, beanName, cacheKey);}}return bean;
}

其中 wrapIfNecessary 方法负责决定是否为给定的 bean 创建代理对象。下面是对该方法的详细分析:

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {if (beanName != null && this.targetSourcedBeans.contains(beanName)) {return bean;}if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {return bean;}// 检查 bean 是否为基础设施类(如 Advisor、Pointcut 等) 或者是否应该跳过代理创建(通过 shouldSkip 方法判断)if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {this.advisedBeans.put(cacheKey, Boolean.FALSE);return bean;}// 获取适用于该 bean 的通知和切面Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);// 如果找到适用于该 bean 的通知或切面,则创建代理if (specificInterceptors != DO_NOT_PROXY) {this.advisedBeans.put(cacheKey, Boolean.TRUE);// 【核心方法】创建代理对象。使用 SingletonTargetSource 封装原始 bean,作为代理的目标对象Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));this.proxyTypes.put(cacheKey, proxy.getClass());return proxy;}this.advisedBeans.put(cacheKey, Boolean.FALSE);// 返回原始 beanreturn bean;
}

其中createProxy是真正创建代理对象的方法,下面是对该方法的详细分析:

protected Object createProxy(Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {if (this.beanFactory instanceof ConfigurableListableBeanFactory) {AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);}// 创建代理工厂实例并复制当前配置ProxyFactory proxyFactory = new ProxyFactory();proxyFactory.copyFrom(this);// 确定代理策略:JDK 动态代理(基于接口)或 CGLIB 代理(基于类)if (!proxyFactory.isProxyTargetClass()) {// 检查是否应该强制使用 CGLIB 代理if (shouldProxyTargetClass(beanClass, beanName)) {proxyFactory.setProxyTargetClass(true);}else {// 评估 bean 实现的接口,决定是否使用 JDK 动态代理evaluateProxyInterfaces(beanClass, proxyFactory);}}Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);for (Advisor advisor : advisors) {proxyFactory.addAdvisor(advisor);}proxyFactory.setTargetSource(targetSource);customizeProxyFactory(proxyFactory);proxyFactory.setFrozen(this.freezeProxy);if (advisorsPreFiltered()) {proxyFactory.setPreFiltered(true);}// 【核心方法】使用指定的类加载器创建并返回代理对象return proxyFactory.getProxy(getProxyClassLoader());
}
public Object getProxy(ClassLoader classLoader) {return createAopProxy()	// 【核心方法】生成代理工厂(内部有判断应该生成 “JDK动态代理” or “CGLIB代理” 的逻辑).getProxy(classLoader);
}

createAopProxy() 方法是 Spring AOP 框架中创建代理对象的核心工厂方法。它负责初始化代理创建环境并委派给实际的 AOP 代理工厂来生成代理实例。下面是对该方法的详细分析:

protected final synchronized AopProxy createAopProxy() {if (!this.active) {activate();}// 获取 AopProxyFactory 并使用它创建 AopProxy 实例// 传入当前的 ProxyConfig 对象,包含了所有代理配置信息return getAopProxyFactory().createAopProxy(this);
}

这个 createAopProxy 方法是 Spring AOP 框架中 DefaultAopProxyFactory 类的核心实现,负责根据配置决定使用 JDK 动态代理还是 CGLIB 代理。下面是对该方法的详细分析:

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {// 判断是否应该使用 CGLIB 代理的条件:// 1. optimize=true:是否需要优化代理创建过程// 2. proxyTargetClass=true:是否强制使用 CGLIB 代理// 3. hasNoUserSuppliedProxyInterfaces():目标类是否未实现任何接口if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {Class<?> targetClass = config.getTargetClass();if (targetClass == null) {throw new AopConfigException("TargetSource cannot determine target class: " +"Either an interface or a target is required for proxy creation.");}// 如果目标类是接口或已经是代理类,则使用 JDK 动态代理if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {return new JdkDynamicAopProxy(config);}// 其他情况(普通类且需要 CGLIB 代理),使用 ObjenesisCglibAopProxyreturn new ObjenesisCglibAopProxy(config);}else {// 如果不需要强制使用 CGLIB 代理且目标类实现了接口,则使用 JDK 动态代理return new JdkDynamicAopProxy(config);}
}

三、时序图:代理生成在容器初始化中的位置

在这里插入图片描述

四、总结:核心要点

  • 时机主要在 Bean 的 postProcessAfterInitialization 阶段生成代理,确保 Bean 完全初始化(如果存在循环引用/依赖,则会在实例化阶段提前处理AOP)
  • 代理类型根据目标类是否为接口自动选择 JDK 动态代理CGLIB 代理
  • 源码核心类AbstractAutoProxyCreator(代理创建逻辑)、DefaultAopProxyFactory(代理类型选择)。

通过上述流程,Spring 实现了对目标 Bean 的动态增强,完成 AOP 代理的创建与注入。

http://www.xdnf.cn/news/8623.html

相关文章:

  • 为什么要使用线程池
  • 【概率论基本概念01】点估计
  • 《P3435 [POI 2006] OKR-Periods of Words》
  • 【Linux网络篇】:Socket网络套接字以及简单的UDP网络程序编写
  • 【Node.js】高级主题
  • 【Linux 学习计划】-- git 在Linux远端服务器上的部署与简单使用
  • LABVIEW 通过节点属性动态改变数值显示控件的方法
  • TypeScript入门到精通
  • 【Leetcode 每日一题】2942. 查找包含给定字符的单词
  • 机器学习算法-sklearn源起
  • 语音合成之十六 语音合成(TTS)跳跃与重复问题的解析:成因、机制及解决方案
  • Mac的显卡架构种类
  • 进程间通信I·匿名管道
  • 软考中级软件设计师全真题
  • Android中获取控件尺寸进阶方案
  • 【MySQL】06.内置函数
  • 机器学习第二十六讲:官方示例 → 跟着菜谱学做经典菜肴
  • spring boot 2.7集成旧的springfox-boot-starter swagger oas 3.0
  • 论文阅读笔记——Emerging Properties in Unified Multimodal Pretraining
  • 超全GPT-4o 风格提示词案例,持续更新中,附使用方式
  • 行为型:迭代器模式
  • java面试题
  • 物联网代理暴利逻辑拆解:格行随身WiFi三网切换技术实战分析
  • 机器学习中的多GPU训练模式
  • 向量数据库Milvus03-高级功能与性能调优
  • 7:QT加载保存参数(读写日志)
  • JS逆向 - 狗dong参数Log及joyytokem(补环境)
  • Groovy:Java 的简洁版
  • python web 开发-Flask-Login使用详解
  • 构建安全AI风险识别大模型:CoT、训练集与Agent vs. Fine-Tuning对比