ConfigurationClassPostProcessor

ConfigurationClassPostProcessor


文章目录

  • ConfigurationClassPostProcessor
  • 前言
  • 一、postProcessBeanDefinitionRegistry
    • 1.processConfigBeanDefinitions
  • 二、postProcessBeanFactory
    • 1. enhanceConfigurationClasses
  • 总结


前言

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


一、postProcessBeanDefinitionRegistry

1.processConfigBeanDefinitions

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

2 好了回归正题 继续主流程
ConfigurationClassPostProcessor_第7张图片
ConfigurationClassPostProcessor_第8张图片

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

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

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

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

二、postProcessBeanFactory

1. enhanceConfigurationClasses

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

总结

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

你可能感兴趣的:(spring)