ConfigurationClassPostProcessor

ConfigurationClassPostProcessor



前言

介绍下基于AnnotationConfigApplicationContext的ConfigurationClassPostProcessor,其实现了BeanDefinitionRegistryPostProcessor,Spring回调后置处理器时加载其功能,下面介绍下两个方法。


一、postProcessBeanDefinitionRegistry

1.processConfigBeanDefinitions

1 其实这个方法大体就是把所有的候选类挑选出来 并包装成beanDef
在这里插入图片描述
首先拿beanDef的名称-列表并循环,Spring内置的咱不考虑,看下自己的配置类是如何进行生成的
这里只需要重点看下(ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)这个判断,点进去。
在这里插入图片描述在这里插入图片描述
其实这些都是想办法拿类上的注解(额外说一句 BeanDefinition分不同的类) 拿到注解后:
在这里插入图片描述
这里还是进行判断 是否为什么类型的注解,若为@Configuration注解则标记元数据中的某个属性为FULL,若为@Component、@ComponentScan、@Import、@ImportResource则设置属性为Lite,这些属性在postProcessBeanFactory会用到,判断挺简单的 我截下图放到下面。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2 好了回归正题 继续主流程
在这里插入图片描述
在这里插入图片描述

根据不同beanDef类型 分别进行处理,说明一下上面第一次运行是配置类 所以第一个条件成立,继续往下进行。
在这里插入图片描述
这里点进去就是比较重点的代码片段了,一个一个的讲

3 首先声明一下,可以把这里理解为递归,比如Import 一个类 类中加载多个bd(普通类、配置类、加了@ComponentScan的类等),递归解析这些类,直到找出全部beanDef来, 先看@ComponentScan 和 @ComponentScans如何处理的
在这里插入图片描述
点进来后 上面代码都是拿配置类上@ComponentScan 配置的信息及初始化scanner,最后代码调用scanner.doScan方法,点进去后定位到核心代码
在这里插入图片描述
根据包去查找候选类,找到后循环,下面介绍,先看下findCandidateComponents(basePackage)方法详情。
在这里插入图片描述
找到所有的Resource列表 然后进行循环解析,定位到关键代码
在这里插入图片描述
其实这里可以看到 如果通过@ComponentScan扫描出来的beanDef 类型为 ScannedGenericBeanDefinition,看下关键代码isCandidateComponent(metadataReader)
在这里插入图片描述
在这里插入图片描述

这里我的类加的Component注解 所以不跳过 返回true 然后回到此图,把所有候选beanDef加入到candidates列表中,然后一路返回到主流程
在这里插入图片描述
方法返回到这里 找到所有的候选beanDef了 然后循环
在这里插入图片描述
在这里插入图片描述
点进去后如图 看一下就能明白
在这里插入图片描述
继续主流程
在这里插入图片描述
点进去 大家看一下就行
在这里插入图片描述

继续主流程
在这里插入图片描述
这里就是把bd放到beanFactory中 一直点到最里面代码,如图所示
在这里插入图片描述
至此就分析完了 回到主流程
在这里插入图片描述
把扫描出来的再进行一遍parse看里面是否也存在配置类 加@ComponetScan等情况,其它情况大家自己看看。

二、postProcessBeanFactory

1. enhanceConfigurationClasses

1 大家肯定都用过 配置类 其类上加了@Configuration注解,类中通过@Bean方式注册BeanDefinition
其实@Configuration 在被Spring 解析过程中做了特殊标记,设置其属性configurationClass为 FULL,
其目的是为了将其代理,保证其@Bean创建的Bean正常化,在回调此方法时 再进行判断,如图所示,若为FULL则将此beanDef put到map中。
在这里插入图片描述
2 如果此configBeanDefs为空代表没有FULL的beanDef 则returan;如图所示
在这里插入图片描述
3 生成CGLIB代理,并将原有的beanDef的BeanClass属性设置为代理的类,其代理的类为BeanMethodInterceptor和BeanFactoryAwareMethodInterceptor 讲一下BeanMethodInterceptor。
在这里插入图片描述
4 在实例化配置类@Bean的过程中 则会调用BeanMethodInterceptor的intercept进行代理
在这里插入图片描述
在isCurrentlyInvokedFactoryMethod(beanMethod)方法中 会判断当前线程(currentlyInvoked)的方法于执行的方法名称(method)是否一致,若一致则invokeSuper,否则就是处理下面的情况了。
在这里插入图片描述
5 分析@Bean方法中调用其它@Bean方法
其实就是分析
return resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName);
在这里插入图片描述
看到这 应该就会明白了 其实他解决此问题的方法就是beanFactory.getBean(beanName);此方法是拿Bean,拿不到则创建,这样B则不会被创建两次,试想以下若没有代理 会发生什么情况,在A先调用情况下 B肯定会初始化两次,还有说明一下上上图中 a方法调用了b方法,如果此时b方法再调用a()方法就会报异常了。

总结

Spring在设计上很巧妙,利用递归、代理等 合理解决一些问题,希望大家能多看几遍,我每隔一年都会大体阅读一下Spring源码,每年读完后的体会都是不一样的,一年比一年升华!

  • 18
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值