【Spring源码】AOP的开端:核心对象创建的准备工作
AOP的核心成员是如何被被加载的?
本篇我们主要分析使用xml的逻辑,如果使用注解,增加注解处理类即可(ConfigurationClassPostProcessor)
拿之前分析循环的时候举的例子🌰,它的日志切面就是通过xml进行配置的(配置文件📃内容如下,完整测试代码可参考【实践向】当移除了三级缓存…… 中的示例代码)

通过ApplicationContext applicationContext = new ClassPathXmlApplicationContext("circulate.xml");启动容器

进入refresh()方法后,先调用prepareRefresh()方法进行的是容器刷新前的准备工作,这里的准备工作大致包括5个内容:
设置容器的启动时间
设置活跃状态为true
设置关闭状态为false
获取Environment对象,并加载当前系统的属性值到Environment对象中
准备监听器和事件的集合对象(默认为空)
在准备工作完成后,开始了下面的创建容器的流程
创建容器
进入方法obtainFreshBeanFactory(),开始Spring容器的创建

可以看到此时创建的是上下文对象是ClassPathXmlApplicationContext

接着进入方法refreshBeanFactory()中,开始BeanFactory的初始化以及XML配置文件的读取和解析

读取并解析XML配置文件📃

进入loadBeanDefinitions()




终于看到了咱们的doLoadBeanDefinitions() ,正式开始读取+解析标签🏷️的逻辑

registerBeanDefinitions()


进入doRegisterBeanDefinition()(没错、do-开头的方法都是干实事的~)

开始重头戏(。・ω・。)ノ

进入parseBeanDefinitions(),方法中对于 Element 的处理主要分为两种类型:
parseDefaultElement
parseCustomElement
找到对应的handler
<aop:config>就属于自定义元素类型,所以我们进入parseCustomElement()方法中

进入parseCustomElement()

我们可以看到,此时的处理器handler为AopNamespaceHandler

按照案例代码,我们进入了NamespaceHandlerSupport接口中,重写了parse

进入其一个实现类NamepaceHandlerSupport中

由于parser != null为true,再次进入名为parse()的方法中

这里主要进行了两个步骤的处理:
注册自动代理模式创建器
解析<aop:config>下的子节点
POINTCUT
ADVICE
ASPECT
我们依次来看看
第一个步骤:【注册自动代理模式创建器】configureAutoProxyCreator()

进入方法configureAutoProxyCreator()

此时集合containingComponents中只有一个元素:"aop:config"
进入registerAspectJAutoProxyCreatorIfNecessary()

registerOrEscalateApcAsRequired()

进入registerOrEscalateApcAsRequired()

如果已经存在了自动代理创建器,且存在的自动代理创建器与当前不一致,那么需要根据优先级来判断下到底需要使用哪个;如果已经存在了自动代理创建器,且存在的自动代理创建器与当前一致,则无需再次创建,返回null即可

下面的变量表中可以看到,这里注册的Bean名为org.springframework.aop.config.internalAutoProxyCreator的beanDefinition;并且其中的BeanDefinition的具体Class类为AspectJAwareAdvisorAutoProxyCreator
方法registerOrEscalateApcAsRequired()执行到最后的registerBeanDefinition()时,当前的BeanDefinition(也就是AspectJAwareAdvisorAutoProxyCreator的BeanDefinition)就已经注册成功了
由下图的静态代码块中也同样添加了InfrastructureAdvisorAutoProxyCreator和AnnotationAwareAspectJAutoProxyCreator这两个类,因此可以推断出他俩的注册流程与AspectJAwareAdvisorAutoProxyCreator类似

那么问题来了:AspectJAwareAdvisorAutoProxyCreator跟我们熟悉的那些BeanPostProcessor、Aware等等有什么关系么?
(*≧ω≦)我们看下类关系图(下图中右下角的就是AspectJAwareAdvisorAutoProxyCreator)

useClassProxyingIfNecessary()

方法中主要是对proxy-target-class和expose-proxy这两个属性进行处理

如果被代理的目标对象实现了至少一个接口,就会使用JDK动态代理,该目标类型实现的接口都会被代理;如果没有实现任何接口,则创建一个Cglib代理对象
registerComponentIfNecessary()

最后调用方法registerComponentIfNecessary()注册对应的组件

接着回到parse()方法中,可以看到此时<aop:config>还是null

第二个步骤:解析<aop:config>下的子节点
继续解析<aop:config>子节点下的
<aop:pointcut>
<aop:advice>
<aop:aspect>

在这里会根据获取到的localName进入不同的if条件语句,进而执行不同的解析方法
parsePointcut()
parseAdvisor()
parseAspect()
下面我们按照我们的测试代码中的XML配置(如下图)捋一遍流程(。・ω・。)ノ

由于获取到的localName为"aspect",满足ASPECT.equals(localName)为true的条件,所以进入parseAspect()方法中

parseAspect()

先获取<aop:aspect>的两个属性:
id属性
ref属性(代表切面,必须配置)

接着解析<aop:aspect>下的declare-parents节点,通过DeclareParentsAdvisor作为beanClass加载,然后继续解析其他节点

在获取到节点后,遍历循环,解析其下的Advice类型的节点,通过调用isAdviceNode()判断遍历到的当前节点是否为Advice类型的节点
isAdviceNode()
判断是否为Advice节点

如上图中方法上面的注释,Advice类型的节点有5个:
{@code before}
{@code after}
{@code after-returning}
{@code after-throwing}
{@code around}
与上面任何一个类型形同返回值即为true
解析成功则继续向下执行

parseAdvisor()

方法parseAdvisor()先生成了methodDefinition(解析advice中的"method"属性,并包装为MethodLocatingFactoryBean对象 )、aspectFactoryDef(关联aspectName,包装为SimpleBeanFactoryAwareAspectInstanceFactory对象)这两个RootBeanDefinition对象,并依次为他俩赋值

随后解析pointcut属性,将上面👆两个对象传入了方法createAdviceDefinition()中,包装为AspectJMethodBeforeAdvice对象返回并赋值给名为adviceDef的AbstractBeanDefinition对象

最后将这个对象包装为名为advisorDefinition的RootBeanDefinition对象并为相关的属性赋值

最后完成注册,就可以在parseContext对象的readerContext -> reader -> registry -> beanDefinitionMap属性中看到这个AspectJPointcutAdvisor对象叻(AspectJPointcutAdvisor#0)

那么问题来了:这些生成的RootBeanDefinition对象有什么区别吗,他们具体都是哪些类呢?
我们先来详细介绍下createAdviceDefinition()这个方法
createAdviceDefinition()
进入方法createAdviceDefinition()

首先根据adviceElement节点通过调用getAdviceClass()方法分析出是什么类型的Advice,获取到一个adviceDefinition对象
getAdviceClass()
这个方法其实与刚刚介绍过的isAdviceNode()判断的类型是完全一致的

继续给刚刚获取到的adviceDefinition对象设置属性值
设置aspectName属性和declarationOrder属性
设置returning、throwing、arg-name这3个属性(先判断,有则设置)
设置构造函数的入参变量
Method
AspectJExpressionPointcut
AspectInstanceFactory
然后解析<point-cut>节点

parsePointcutProperty()

至此,方法createAdviceDefinition()执行结束,返回一个AbstractBeanDefinition类型的对象adviceDef。我们也来回答下介绍方法前的问题:这些生成的RootBeanDefinition对象具体都是哪些类呢?

methodDefinition:MethodLocatingFactoryBean
aspectFactoryDef:SimpleBeanFactoryAwareAspectInstanceFactory
adviceDef:AspectJMethodBeforeAdvice
adviceDefinition:AspectJPointcutAdvisor
回到方法parseAspect()中,将当前解析过的beanDefinition(advisorDefinition)添加进集合beanDefinitions中

接着进入下一轮循环♻️,继续解析列表中的节点
第二次循环执行完成在parseContext对象的readerContext -> reader -> registry -> beanDefinitionMap属性中又多了一个AspectJPointcutAdvisor对象(AspectJPointcutAdvisor#1),嘿嘿没错每完成一次循环就会多一个~~0、1、2……递增

这些类外部都是AspectJPointcutAdvisor对象,用后缀#1、#2、#3……来区分,但是内部真正的通知类型Advisor是不一样的
循环结束后,返回到parse()方法中,由于我在XML配置文件(如下图)中加了两个aspect标签🏷️,所以childElts里有两个Element,于是会再按上面👆得大致流程再执行一遍

全部遍历完成后一路返回
其实吧,说到底BeanDefinition的解析过程( loadBeanDefinitions()),也就是配置文件的加载过程,毕竟都是Bean嘛^ ^
相关文章:
【Spring源码】AOP的开端:核心对象创建的准备工作
AOP的核心成员是如何被被加载的?本篇我们主要分析使用xml的逻辑,如果使用注解,增加注解处理类即可(ConfigurationClassPostProcessor)拿之前分析循环的时候举的例子🌰,它的日志切面就是通过xml进…...
新号涨粉22w,搞笑博主再次爆火,小红书近期创作趋势是什么?
2月借势元宵、情人节,小红书平台又涌现出哪些黑马博主?品牌在投放种草方面有何亮眼表现?为洞察小红书平台的内容创作趋势及品牌营销策略,新红推出2月月度榜单,从创作者及品牌两方面入手,解析月榜数据&#…...
【C++】30h速成C++从入门到精通(内存管理、函数/类模板)
C内存分布我们先来看一下下面的一段代码相关问题int globalVar 1; static int staticGlobalVar 1; void Test() {static int staticVar 1;int localVar 1;int num1[10] {1, 2, 3, 4};char char2[] "abcd";char* pChar3 "abcd";int* ptr1 (int*)mal…...
自动驾驶决策概况
文章目录1. 第一章行为决策在自动驾驶系统架构中的位置2. 行为决策算法的种类2.1 基于规则的决策算法2.1.1 决策树2.1.2 有限状态机(FSM)2.1.3 基于本体论(Ontologies-based)2.2 基于统计的决策算法2.2.1 贝叶斯网络(B…...
金山轻维表项目进展自动通知
项目经理作为项目全局把控者,经常要和时间“赛跑”。需要实时了解到目前进展如何,跟进人是那些?哪些事项还未完成?项目整体会不会逾期?特别是在一些大型公司中,优秀的项目经理已经学会使用金山轻维表做项目…...
基于上下文分析的 Python 实时 API 推荐
原文来自微信公众号“编程语言Lab”:基于上下文分析的 Python 实时 API 推荐 搜索关注 “编程语言Lab”公众号(HW-PLLab)获取更多技术内容! 欢迎加入 编程语言社区 SIG-程序分析 参与交流讨论(加入方式:添加…...
软件测试-接口测试-代码实现接口测试
文章目录 1.request1.1 request介绍1.2 发送get请求1.3 发送set请求1.4 其他请求方式1.5 传递url参数1.6 响应内容解析1.7 cookie1.8 设置session2.集成UnitTest2.1 接口测试框架开发2.2 案例:使用TPShop项目完成对登录功能的接口测试1.request 1.1 request介绍 概念 基于py…...
中村成洋《垃圾回收的算法与实现》PDF 读书笔记
观前提醒 为了能够锻炼自己,我会查阅大量外文不停的修改内容,少部分会提示成中文。 可能有误,请见谅 提示:若是觉得阅读困难,可以看如下内容 脚本之家可获取,若失效可私信浏览器的沙拉查词扩展…...
docker 网络模式
docker 网络模式主要分为四种,可以通过docker network ls 查看 ~$ docker network ls NETWORK ID NAME DRIVER SCOPE a51d97d72f10 bridge br…...
数据库开发(一文概括mysql基本知识)
Mysql 是最流行的关系型数据库管理系统,在 WEB 应用方面 MySQL 是最好的 关系型数据库(Relational Database Management System:关系数据库管理系统)应用软件之一。mysql在问开发中,几乎必不可少,因为其他的可能是要收费的&#x…...
【JVM】详解Java内存区域和分配
这里写目录标题一、前言二、运行时数据分区2.1程序计数器(PC)2.2 Java虚拟机栈2.3 本地方法栈2.4 Java堆2.5 方法区2.5.1 运行时常量池2.6 直接内存三、HotSpot虚拟机对象探秘3.1 对象的创建3.2 对象的内存布局3.3 对象的访问定位一、前言 C/C需要自行回收和释放已经没用的对象…...
JAVA开发(史上最完整追本溯源JAVA历史、发展和学习)
(第二次世界大战1931-1945) 世界上最先进的技术往往是由于战争催生,在第二次世界大战中除了飞机,坦克和大炮的武器较量外,在隐秘战线的情报工作其实更为重要,在军队将领来往的电报中,为了防止军事情报的泄漏ÿ…...
Qt 防止程序退出
文章目录摘要QWidgetQML方法 1方法 2关键字: Qt、 eventFilter、 Close、 键盘、 任务管理器摘要 今天要聊得内容还是怎么防止别人关闭我的程序,之前都是在win下面,一般都是用过钩子连捕获键盘事件,完了吧对应的事件忽略&#x…...
【校验码 - 循环冗余校验码CRC】
水善利万物而不争,处众人之所恶,故几于道💦 目录 循环冗余校验码 1.多项式 2.CRC编码的组成 3.校验码的生成 4.例题: 循环冗余校验码 广泛地在网络通信及磁盘存储时采用。 1.多项式 在循环冗余校验(CRC)码中,无一例…...
【Rust】一文讲透Rust中的PartialEq和Eq
前言 本文将围绕对象:PartialEq和Eq,以及PartialOrd和Ord,即四个Rust中重点的Compare Trait进行讨论并解释其中的细节,内容涵盖理论以及代码实现。 在正式介绍PartialEq和Eq、以及PartialOrd和Ord之前,本文会首先介绍…...
Vulnhub靶场----9、DC-9
文章目录一、环境搭建二、渗透流程三、思路总结一、环境搭建 DC-9下载地址:https://download.vulnhub.com/dc/DC-9.zip kali:192.168.144.148 DC-9:192.168.144.158 二、渗透流程 1、信息收集nmap -T5 -A -p- -sV -sT 192.168.144.158思路&am…...
使用Containerd搭建K8s集群【v1.25】
[toc] 一、安装要求 在开始之前,部署Kubernetes集群机器需要满足以下几个条件: 一台或多台机器,操作系统 CentOS7.x-86_x64硬件配置:2GB或更多RAM,2个CPU或更多CPU,硬盘30GB或更多集群中所有机器之间网络互通可以访问外网,需要拉取镜像禁止swap分区二、准备环境 角色IP…...
NMT - 构建双语概率词典(Probabilistic dictionaries)
文章目录一、安装依赖包mosesdecoder安装 mgiza二、数据预处理三、训练本文参考:How to train your Bicleaner https://github.com/bitextor/bicleaner/wiki/How-to-train-your-Bicleaner 一、安装依赖包 这个过程主要依赖于 mosesdecodermgiza mosesdecoder git…...
《ChatGPT是怎样炼成的》
ChatGPT 在全世界范围内风靡一时,我现在每天都会使用 ChatGPT 帮我回答几个问题,甚至有的时候在一天内我和它对话的时间比和正常人类对话还要多,因为它确实“法力无边,功能强大”。 ChatGPT 可以帮助我解读程序,做翻译…...
Streaming System是第一章翻译
GIthub链接,欢迎志同道合的小伙伴一起翻译 Chapter 1.Streaming101 如今,流数据处理在大数据中是非常重要的,其主要原因是: 企业渴望对他们的数据有更及时的了解,而转换到流处理是实现更低延迟的一个好方法…...
从-15dBm到+16dBm:STC8G信标FM射频放大链路实测与优化
1. 从零开始的FM信标信号放大实战 去年我在做一个野外定位项目时,遇到了一个棘手的问题:用STC8G微控制器生成的FM信标信号,在空旷地带的有效传输距离还不到50米。当时测得的初始输出功率只有-15dBm左右,这个强度连穿过一片小树林都…...
GLM-ASR开源语音识别引擎:基于GLM架构的端到端实践指南
1. 项目概述:一个开源的、基于GLM架构的语音识别引擎最近在语音识别(ASR)这个圈子里,一个名为“GLM-ASR”的开源项目引起了我的注意。它来自zai-org组织,顾名思义,其核心是将自然语言处理领域大放异彩的GLM…...
CANN/ops-nn动态量化RMS归一化融合算子
aclnnAddRmsNormDynamicQuantV2 【免费下载链接】ops-nn 本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。 项目地址: https://gitcode.com/cann/ops-nn 📄 查看源码 产品支持情况 产品是否支持Ascend 950PR/Ascend 950DT√A…...
机器学习在非洲公共卫生疾病预测中的实战应用与技术解析
1. 项目概述:当AI遇见非洲公共卫生在非洲大陆,公共卫生系统长期面临着资源不均、基础设施薄弱和疾病负担沉重的多重挑战。传统的疾病监测依赖于被动报告和人工数据分析,往往存在滞后性,当疫情警报拉响时,病毒可能已经悄…...
Hermes模型优化实战:量化、剪枝与蒸馏技术全解析
1. 项目概述:一个为Hermes模型量身定制的“武士刀”如果你最近在关注大语言模型(LLM)的微调领域,特别是那些追求极致推理速度和响应效率的模型,那么“Hermes”这个名字你一定不陌生。它通常指代一系列基于Llama、Mistr…...
从冷餐台到神经拟态厨房:2026大会餐饮背后隐藏的12项IEEE P2851.3标准落地细节,仅限首批注册嘉宾解密
更多请点击: https://intelliparadigm.com 第一章:2026年AI技术大会餐饮安排总览 为保障全球参会者在高强度技术交流中的能量补给与文化体验,2026年AI技术大会(AIC 2026)联合本地智慧餐饮平台「CulinaOS」,…...
手机端数据恢复神器,值得收藏
今天给大家推荐一款好用的安卓端数据恢复工具,非常好用的,还有一款Wifi信号检测工具,有需要的小伙伴及时下载收藏! 软件介绍 第一款:数据恢复大师dumpster 提到数据恢复大师,之前好像也有推荐过࿰…...
从零构建AI编程助手:Groundhog项目解析与Rust实现
1. 项目概述:一个从零开始理解AI编程助手的教学项目如果你和我一样,对Cursor、GitHub Copilot这类AI编程助手背后的工作原理感到好奇,甚至有点“黑盒”恐惧,那么这个叫Groundhog的项目,可能就是为你量身打造的。它不是…...
2026年最佳同城小程序推荐榜单,助你高效解锁本地生活
本文围绕同城小程序的技术架构、功能覆盖及实际应用效果展开深度解析,系统梳理了当前市场上的主流工具如何助力用户高效解锁本地生活服务。通过对多项核心指标的横向测评与案例分析,重点探讨了同城小程序在资源匹配效率、数据安全机制及生态扩展性方面的…...
长曜创新获数千万元 A+ 融资,Tron Ultra 割草机器人年中全球发售破行业难题
硬氪获悉,智能庭院机器人公司「长曜创新」近日完成数千万元 A 融资,此前 A 轮融资也已在 2025 年 12 月完成,半年累计超亿元。其最新产品 Tron Ultra 系列将在年中全球发售。融资情况与发展方向长曜创新近日完成数千万元 A 轮融资,…...
