【Spring源码系列】工厂后置处理器之ConfigurationClassPostProcessor
日期: 2021-05-11 分类: 个人收藏 522次阅读
上一篇文章对spring的工厂后置处理器做了简单的介绍,对工厂后置处理器还不了解的可以看看噢,传送门:
今天就聊聊spring到底是如何使用工厂后置处理器的。
1.spring是怎么执行到ConfigurationClassPostProcessor的?
首先spring会在ApplicationContext的构造方法里去往beanDefinitionMap放几个spring内置的工厂后置处理器,其中最重要的就是今天要聊的ConfigurationClassPostProcessor。
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
在spring的refresh()方法里,会去处理所有的工厂后置处理器,方法路径:
AbstractApplicationContext—>refresh()—>invokeBeanFactoryPostProcessors(beanFactory);
上面是可以理解spring已经定义好它自己内置的工厂后置处理了,接下来就是要把这些后置处理器拿出来,搞事情了:
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
进入这个方法中,直接看最重要的一部分:
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
/**
* 这里执行工厂后置处理里的方法,这里当做是执行 ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry()方法
* 当这个方法执行完成后,自定义的工厂后置处理器、以及spring中所有的bean都会扫描完成
*/
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
}
else {
regularPostProcessors.add(postProcessor);
}
}
上面的代码中有一段 registryProcessor.postProcessBeanDefinitionRegistry(registry);
这里就是去执行spring中ConfigurationClassPostProcessor中的postProcessBeanDefinitionRegistry()
方法,下面直接进入该方法中,看看它到底做了些什么?
2.ConfigurationClassPostProcessor都干了些什么?
①扫描解析bean
在postProcessBeanDefinitionRegistry()
方法中,直接看processConfigBeanDefinitions(registry)
方法,一步一步的看:
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
/**
*
* 检查注解的类型:判断是否是Full全注解,即是否是@Configuration注解,如果是,会给beanDefinition设置一个full的标识
* 如果是Lite类型,给BeanDefinition 设置一个Lite的标识
*/
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
这段代码其实就是对beanDefinition加上一个标识:Full标识和Lite标识,这里记住只有加了*@Configuration
*注解的类,才会加上Full标识(后面spring会为该bean生成代理对象),其他的beanDefinition则加上Lite标识。
接下来spring创建了一个的解析器,用于后面对beanDefinition进行解析:
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
然后对所有的beanDefinition开始解析:
parser.parse(candidates);
下面我直接到最重要的一些代码,可以根据代码路径找到:
parser.parse(candidates)–>parse()–>processConfigurationClass()–>doProcessConfigurationClass()
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
throws IOException {
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
// Recursively process any member (nested) classes first
/**
* 处理内部类
*/
processMemberClasses(configClass, sourceClass);
}
// Process any @PropertySource annotations
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) {
if (this.environment instanceof ConfigurableEnvironment) {
processPropertySource(propertySource);
}
else {
logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
"]. Reason: Environment must implement ConfigurableEnvironment");
}
}
// Process any @ComponentScan annotations
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() &&
!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
for (AnnotationAttributes componentScan : componentScans) {
// The config class is annotated with @ComponentScan -> perform the scan immediately
/**
* 扫描普通类
* 这里出所有的@Component
*/
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
// Check the set of scanned definitions for any further config classes and parse recursively if needed
/**
*
* 检查扫描出来的类是否含有Configuration
*/
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
// Process any @Import annotations
/**
* 处理 @Import @ImportSelector @ImportBeanDefinitionRegistrar
*/
processImports(configClass, sourceClass, getImports(sourceClass), true);
......
}
上面的代码主要根据spring中的基本注解,然后对加了不同的注解的bean进行相应的处理。
这里涉及spring中的基本注解主要有:@Component
、@ComponentScans
、@Configuration
、@Import
接下来看看spring是怎么对这些注解进行处理的?
@Component
和@ComponentScans
:
标注了这两个注解,最后扫描出来,在spring中就是普通的bean。
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
这里面的具体代码就不写在文章里了,感兴趣的可以自己去看看,就简单的说一下它里面做的一些事情吧:
首先回去创建一个扫描器(scanner),然后拿到注解里(@ComponentScans)的包名,用scanner对包进行扫描,然后解析,最后会返回beanDefinition。
@Configuration
:
我们在标注了@Configuration这个注解的类里,往往会通过@Bean的方式去往spring中创建一个bean,我理解的就是该类的所有的@Bean就是在这里进行处理的。
@Import
:
这个注解可以说的东西就有很多了,后面我单独水一篇文章。
它可以引入三种类型的类:第一种是普通类,第二种是实现了ImportSelector
接口的类,第三种是实现了ImportBeanDefinitionRegistrar
接口的类。不要小看这个注解,很牛逼的,Mybatis以及SpringBoot的自动装配技术都通过@Import这个注解来实现的。
到这里,基本spring工程中的bean都扫描解析完成了,这里得到的是beanDefinition,而不是真正的bean,bean的实例化后面在说。
②执行自定义BeanDefinitionRegistryPostProcessor
经过上面的扫描解析,你自定义的BeanDefinitionRegistryPostProcessor
也会出现在spring的beanDefinitionMap中,然后会去执行自定义的BeanDefinitionRegistryPostProcessor
的postProcessBeanDefinitionRegistry()
方法。
③执行所有的BeanFactoryPostProcessor#postProcessBeanFactory()方法
因为在spring工程中有两个顶级的工厂后置处理器接口嘛,分别是BeanFactoryPostProcessor
、BeanDefinitionRegistryPostProcessor
。
前面都是执行的BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry()
方法,包括spring内置的ConfigurationClassPostProcessor
和你自定义的BeanDefinitionRegistryPostProcessor
。
后面就是执行BeanFactoryPostProcessor#postProcessBeanFactory()
方法。而spring内置的ConfigurationClassPostProcessor#postProcessBeanFactory()
方法中,主要干的事情就是为添加了@Configuration
的类生成代理:
public Class<?> enhance(Class<?> configClass, @Nullable ClassLoader classLoader) {
if (EnhancedConfiguration.class.isAssignableFrom(configClass)) {
if (logger.isDebugEnabled()) {
logger.debug(String.format("Ignoring request to enhance %s as it has " +
"already been enhanced. This usually indicates that more than one " +
"ConfigurationClassPostProcessor has been registered (e.g. via " +
"<context:annotation-config>). This is harmless, but you may " +
"want check your configuration and remove one CCPP if possible",
configClass.getName()));
}
return configClass;
}
//cglib 代理
Class<?> enhancedClass = createClass(newEnhancer(configClass, classLoader));
if (logger.isTraceEnabled()) {
logger.trace(String.format("Successfully enhanced %s; enhanced class name is: %s",
configClass.getName(), enhancedClass.getName()));
}
return enhancedClass;
}
到这里,基本ConfigurationClassPostProcessor
的事情就干完了,下面来个总结吧。
3.总结
①先执行BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry()
方法,spring内置的BeanDefinitionRegistryPostProcessor
,即ConfigurationClassPostProcessor
;
②spring通过ConfigurationClassPostProcessor
这个工厂后置处理,对整个spring工程进行扫描,解析,然后生成beanDefinition,放到beanDefinitionMap中;
③执行BeanFactoryPostProcessor#postProcessBeanFactory()
,而ConfigurationClassPostProcessor
为加了@Configuration
的类生成了代理
④工厂后置处理器的执行顺序:
先执行spring内置的BeanDefinitionRegistryPostProcessor
,即ConfigurationClassPostProcessor
;
再执行自定义的BeanDefinitionRegistryPostProcessor
;
最后执行BeanFactoryPostProcessor
。
这篇文章主要讲spring的ConfigurationClassPostProcessor,可能有些绕吧,其实读源码的时候更绕,只要抓住了核心,慢慢的就理解了,读源码是个枯燥的过程,也很容易放弃,我也是反反复复看了好多遍。
spring源码读完有什么好处吗?当然,spring源码读完,你在后面读SpringBoot、SpringCloud源码的时候,都会更加得心应手,就像是水到渠成一般的感觉。
今天文章里遗留了一个很重要的问题,就是@Import注解,下篇文章再单独写吧。
除特别声明,本站所有文章均为原创,如需转载请以超级链接形式注明出处:SmartCat's Blog
精华推荐