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

浅析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 代理的创建与注入。

相关文章:

  • 实现Web网站冷启动的全面指南
  • [软件测试_4] 沟通技巧 | 测试用例 | 设计方法
  • 基于cornerstone3D的dicom影像浏览器 第二十二章 mpr + vr
  • 基于AI生成测试用例的处理过程
  • TestHubo V1.0.8版本发布,支持按模块树筛选用例,让查询更便捷
  • A-Teacher: Asymmetric Network for 3D Semi-Supervised Object Detection
  • c/c++的opencv像素级操作二值化
  • 【RAG文档切割】从基础拆分到语义分块实战指南
  • 【动态规划】P12223 [蓝桥杯 2023 国 Java B] 非对称二叉树|普及+
  • 使用ps为图片添加水印
  • Gitlab-Runner安装
  • 【人工智能】AI的炼金术:大模型训练的秘密配方
  • curl常用指令
  • RK3588 buildroot QT 悬浮显示(OSD)
  • 黑马k8s(十四)
  • (9)-java+ selenium->元素定位之By name
  • 用go从零构建写一个RPC(3)--异步调用+多路复用实现
  • 云计算,大数据,人工智能
  • C语言 — 内存函数和数据的存储
  • 【C】函数未定义或者函数找不到原型实现
  • 打开山东城市建设职业学院网站/优化网站关键词的技巧
  • 灰色词秒收录代发/百度seo收费
  • 做网站步骤/点击器 百度网盘
  • 郑州网站建设网络公司/网络营销案例题
  • 中国城乡住房和城乡建设部网站首页/重庆网站seo外包
  • 揭阳网站制作软件/百度的企业网站