首发于 java工程师成神之路

《Spring源码解析(九)》从源码深处体验Spring核心技术--详细解读Spring AOP源码

本文将带领大家对Spring Aop的源码进行详细阅读,可能会有点晕车,但是希望大家能咬牙坚持,可能多看几遍你就融汇贯通了,那种被人打开任督二脉的感觉,我试过,不知道有多爽!!!

进入正题

寻找入口

Spring 的 AOP 是通过接入 BeanPostProcessor 后置处理器开始的,它是 Spring IOC 容器经常使用到的一个特性,这个 Bean 后置处理器是一个监听器,可以监听容器触发的 Bean 声明周期事件。

后置处理器向容器注册以后,容器中管理的 Bean 就具备了接收 IOC 容器事件回调的能力。

BeanPostProcessor 的使用非常简单,只需要提供一个实现接口 BeanPostProcessor 的实现类,然后在 Bean 的配置文件中设置即可。

1、BeanPostProcessor 源码

这两个回调的入口都是和容器管理的 Bean 的生命周期事件紧密相关,可以为用户提供在 Spring IOC容器初始化 Bean 过程中自定义的处理操作。

2、AbstractAutowireCapableBeanFactory 类对容器生成的 Bean 添加后置处理器

BeanPostProcessor 后置处理器的调用发生在 Spring IOC 容器完成对 Bean 实例对象的创建和属性的依赖注入完成之后。

在对Spring依赖注入的源码分析过程中我们知道,当应用程序第一次调用 getBean()方法(lazy-init 预实例化除外)向 Spring IOC 容器索取指定 Bean 时,触发 Spring IOC 容器创建 Bean 实例 对 象 并 进 行 依 赖 注 入 的 过 程 , 其 中 真 正 实 现 创 建 Bean 对 象 并 进 行 依 赖 注 入 的 方 法 是 AbstractAutowireCapableBeanFactory 类的 doCreateBean()方法,主要源码如下:

从上面的代码中我们知道,为 Bean 实例对象添加 BeanPostProcessor 后置处理器的入口的是initializeBean()方法。

3、initializeBean()方法为容器产生的 Bean 实例对象添加 BeanPostProcessor 后置处理器

同样在 AbstractAutowireCapableBeanFactory 类中,initializeBean()方法实现为容器创建的 Bean实例对象添加 BeanPostProcessor 后置处理器,源码如下:

BeanPostProcessor 是一个接口,其初始化前的操作方法和初始化后的操作方法均委托其实现子类来实现,在 Spring 中,BeanPostProcessor 的实现子类非常的多,分别完成不同的操作,

如:AOP 面向切面编程的注册通知适配器、Bean 对象的数据校验、Bean 继承属性、方法的合并等等,我们以最简单的 AOP 切面织入来简单了解其主要的功能。

下面我们来分析其中一个创建 AOP 代理对象的子类 AbstractAutoProxyCreator 类。

该类重写了 postProcessAfterInitialization()方法。

选择代理策略

进入 postProcessAfterInitialization()方法,我们发现调到了一个非常核心的方法 wrapIfNecessary(),

其源码如下:

整个过程跟下来,我发现最终调用的是 proxyFactory.getProxy()方法。到这里我们大概能够猜到 proxyFactory 有 JDK 和 CGLib 的,那么我们该如何选择呢?最终调用的是 DefaultAopProxyFactory的 createAopProxy()方法:

调用代理方法

分析调用逻辑之前先上类图,看看 Spring 中主要的 AOP 组件:

上面我们已经了解到 Spring 提供了两种方式来生成代理方式有 JDKProxy 和 CGLib。下面我们来研究 一下 Spring 如何使用 JDK 来生成代理对象,具体的生成代码放在 JdkDynamicAopProxy 这个类中, 直接上相关代码:

通过注释我们应该已经看得非常明白代理对象的生成过程,此处不再赘述。

下面的问题是,代理对象生成了,那切面是如何织入的?

我们知道 InvocationHandler 是 JDK 动态代理的核心,生成的代理对象的方法调用都会委托到InvocationHandler.invoke()方法。

而从 JdkDynamicAopProxy 的源码我们可以看到这个类其实也实现了 InvocationHandler,下面我们分析 Spring AOP 是如何织入切面的,直接上源码看 invoke()方法:

主要实现思路可以简述为:首先获取应用到此方法上的通知链(Interceptor Chain)。

如果有通知,则应用通知,并执行 JoinPoint;如果没有通知,则直接反射执行 JoinPoint。

而这里的关键是通知链是如何获取的以及它又是如何执行的呢?

现在来逐一分析。

首先,从上面的代码可以看到,通知链是通过Advised.getInterceptorsAndDynamicInterceptionAdvice()这个方法来获取的,我们来看下这个方法的实现逻辑

通过上面的源码我们可以看到,实际获取通知的实现逻辑其实是由 AdvisorChainFactory 的 getInterceptorsAndDynamicInterceptionAdvice()方法来完成的,且获取到的结果会被缓存。

下面来分析 getInterceptorsAndDynamicInterceptionAdvice()方法的实现:

这个方法执行完成后,Advised 中配置能够应用到连接点(JoinPoint)或者目标类(Target Object)的 Advisor 全部被转化成了 MethodInterceptor,接下来我们再看下得到的拦截器链是怎么起作用的。

从 这 段 代 码 可 以 看 出 , 如 果 得 到 的 拦 截 器 链 为 空 , 则 直 接 反 射 调 用 目 标 方 法 , 否 则 创 建MethodInvocation,调用其 proceed()方法,触发拦截器链的执行,来看下具体代码:

至此,通知链就完美地形成了。

我们再往下来看 invokeJoinpointUsingReflection()方法,其实就是反射调用:

Spring AOP 源码就分析到这儿,相信小伙伴们应该有了基本思路,下面时序图来一波。

(需要高清的找我)

触发通知

在为 AopProxy 代理对象配置拦截器的实现中,有一个取得拦截器的配置过程,这个过程是由 DefaultAdvisorChainFactory 实现的,这个工厂类负责生成拦截器链,在它的getInterceptorsAndDynamicInterceptionAdvice 方法中,有一个适配器和注册过程,通过配置 Spring 预先设计好的拦截器,Spring 加入了它对 AOP 实现的处理。

GlobalAdvisorAdapterRegistry 负责拦截器的适配和注册过程。

而 GlobalAdvisorAdapterRegistry 起到了适配器和单例模式的作用,提供了一个 DefaultAdvisorAdapterRegistry,它用来完成各种通知的适配和注册过程。

DefaultAdvisorAdapterRegistry 设置了一系列的是配置,正是这些适配器的实现,为 Spring AOP 提供了编织能力。下面以 MethodBeforeAdviceAdapter 为例,看具体的 实现:

Spring AOP 为了实现 advice 的织入,设计了特定的拦截器对这些功能进行了封装。

我们接着看 MethodBeforeAdviceInterceptor 如何完成封装的?

可以看到,invoke 方法中,首先触发了 advice 的 before 回调,然后才是 proceed。

AfterReturningAdviceInterceptor 的源码:

ThrowsAdviceInterceptor 的源码:

至此,我们知道了对目标对象的增强是通过拦截器实现的,最后还是上时序图:

代做工资流水公司宁波企业贷流水代开宁波企业流水打印代开湛江自存流水公司徐州开车贷银行流水长沙代办工资流水单孝感工资流水账单徐州工资证明价格南昌开银行流水PS南阳银行流水单查询宁德贷款工资流水 报价潮州办理流水岳阳离职证明公司潍坊自存流水价格镇江流水单代开中山企业贷流水开具吉林打企业贷流水徐州查银行流水修改开封工资代付流水开具潮州自存流水代开成都制作企业贷流水漳州转账流水公司宜春流水开具惠州对公流水制作东莞做自存银行流水宜春个人工资流水 多少钱吉林代办银行流水宜春办理工资流水app截图淮安房贷收入证明多少钱淮安转账银行流水价格邢台薪资银行流水代开香港通过《维护国家安全条例》两大学生合买彩票中奖一人不认账让美丽中国“从细节出发”19岁小伙救下5人后溺亡 多方发声卫健委通报少年有偿捐血浆16次猝死汪小菲曝离婚始末何赛飞追着代拍打雅江山火三名扑火人员牺牲系谣言男子被猫抓伤后确诊“猫抓病”周杰伦一审败诉网易中国拥有亿元资产的家庭达13.3万户315晚会后胖东来又人满为患了高校汽车撞人致3死16伤 司机系学生张家界的山上“长”满了韩国人?张立群任西安交通大学校长手机成瘾是影响睡眠质量重要因素网友洛杉矶偶遇贾玲“重生之我在北大当嫡校长”单亲妈妈陷入热恋 14岁儿子报警倪萍分享减重40斤方法杨倩无缘巴黎奥运考生莫言也上北大硕士复试名单了许家印被限制高消费奥巴马现身唐宁街 黑色着装引猜测专访95后高颜值猪保姆男孩8年未见母亲被告知被遗忘七年后宇文玥被薅头发捞上岸郑州一火锅店爆改成麻辣烫店西双版纳热带植物园回应蜉蝣大爆发沉迷短剧的人就像掉进了杀猪盘当地回应沈阳致3死车祸车主疑毒驾开除党籍5年后 原水城县长再被查凯特王妃现身!外出购物视频曝光初中生遭15人围殴自卫刺伤3人判无罪事业单位女子向同事水杯投不明物质男子被流浪猫绊倒 投喂者赔24万外国人感慨凌晨的中国很安全路边卖淀粉肠阿姨主动出示声明书胖东来员工每周单休无小长假王树国卸任西安交大校长 师生送别小米汽车超级工厂正式揭幕黑马情侣提车了妈妈回应孩子在校撞护栏坠楼校方回应护栏损坏小学生课间坠楼房客欠租失踪 房东直发愁专家建议不必谈骨泥色变老人退休金被冒领16年 金额超20万西藏招商引资投资者子女可当地高考特朗普无法缴纳4.54亿美元罚金浙江一高校内汽车冲撞行人 多人受伤

代做工资流水公司 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化