- ConfigurationClassPostProcessor作用
- 源码分析一BeanDefinition生成
- postProcessBeanDefinitionRegistry源码分析
- FUll 和 Lite模式简介
- Demo案例
- 总结
| 处理以下注解生成BeanDefinition |
|---|
| 处理@Component @Service @Controller @Repository解析 |
| 处理@ComponentScan @Bean @import @importResource@Configuration解析 |
| 处理@importSelecto导入的xml文件 |
ConfigurationClassPostProcessor包含两个点postProcessBeanDefinitionRegistry和postProcessBeanFactory
- postProcessBeanDefinitionRegistry目标完成BeanDefinition扫描解析注册
- postProcessBeanFactory目标是对FULL模式的BeanDefinition增强,增强的目的是为了更好的处理@Bean的依赖注入
| 核心作用 |
|---|
| 先解析启动类生成BD集合,在将解析过程中需要特殊处理的解析交给ConfigurationClassBeanDefinitionReader解析 |
| 自旋处理beanfactory中新生成的为full和lite的bd 直到完成全部bd生成 |
| FULL和lite模式是BeanDefinition的一种属性,在postProcessBeanFactory执行时会依赖这种属性决定是否增强,增强的作用在于处理@Bean注解的依赖注入,后文讲解其区别 |
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
int registryId = System.identityHashCode(registry);
if (this.registriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
}
if (this.factoriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + registry);
}
this.registriesPostProcessed.add(registryId);
先完成注解解析 其次完成@importResource,@import等的BeanDefinition解析
processConfigBeanDefinitions(registry);
}
- 1 摘要: 通过调用processConfigBeanDefinitions完成BeanDefinition加载
- 2 获取beanfactory已经注册的BeanDefinition[其中有个非常重要的beandefinition为springboot启动类的Application]
- 3 判断BeanDefinition是否是full或者lite模式,是则解析[解析时会设置full或者lite模式]
- 4 创建ConfigurationClassParser解析类( @Configuration @ComponentScan @Component @Bean @import @importResource)
- 5 parser.parse(candidates)完成【springboot启动类】解析以及递归解析
- 6 解析过程中会将@import等类加入parser的configurationClasses属性
- 7 通过ConfigurationClassBeanDefinitionReader解析parser的configurationClasses处理剩余的BeanDefinition生成
- 8 重新获取beanfactory中所有BeanDefinitionName,将没有解析过的重新解析生成BeanDefinition
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List configCandidates = new ArrayList<>();
- 1 通过调用processConfigBeanDefinitions完成BeanDefinition加载
- 2 获取beanfactory已经注册的BeanDefinition[其中有个非常重要的beandefinition为springboot启动类的Application]
String[] candidateNames = registry.getBeanDefinitionNames();
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
- 3 判断BeanDefinition是否是full或者lite模式,是则解析[解析时会设置full或者
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
判断是否是@Configuration 类
判断ComponentScan import importResource Compoment 或者方法上加了bean注解
如果是的话给bd设置上full或者lite属性
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
// configCandidates 包含了 @Configuration
if (configCandidates.isEmpty()) {
return;
}
排序 注入context的【configuration component】类可以有多个
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return Integer.compare(i1, i2);
});
// Detect any custom bean name generation strategy supplied through the enclosing application context
SingletonBeanRegistry sbr = null;
if (registry instanceof SingletonBeanRegistry) {
sbr = (SingletonBeanRegistry) registry;
if (!this.localBeanNameGeneratorSet) {
BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
if (generator != null) {
this.componentScanBeanNameGenerator = generator;
this.importBeanNameGenerator = generator;
}
}
}
if (this.environment == null) {
this.environment = new StandardEnvironment();
}
构建解析器
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
防止用户传入多个相同的candidate
Set candidates = new linkedHashSet<>(configCandidates);
已经处理的信息 用于幂等防重复
Set alreadyParsed = new HashSet<>(configCandidates.size());
do {
// 这里解析的是ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)后属性为lite 和full的类
- 5 parser.parse(candidates)完成【springboot启动类】解析以及递归解析
parser.parse(candidates);
parser.validate();
获取parse处理完毕的import的相关内容准备转换成BD
- 6 解析过程中会将@import等类加入parser的configurationClasses属性
Set configClasses = new linkedHashSet<>(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);
// Read the model and create bean definitions based on its content
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getimportRegistry());
}
- 7 通过ConfigurationClassBeanDefinitionReader解析parser的configurationClasses处理剩余的BeanDefinition生成
将configClasses转换成BD 【包含configuration 普通的bean importresource importSelector importBeanDefinitionRegister bean method】
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
candidates.clear();
- 8 重新获取beanfactory中所有BeanDefinitionName,将没有解析过的自旋重新解析生成BeanDefinition
if (registry.getBeanDefinitionCount() > candidateNames.length) {
String[] newCandidateNames = registry.getBeanDefinitionNames();
Set oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
Set alreadyParsedClasses = new HashSet<>();
for (ConfigurationClass configurationClass : alreadyParsed) {
alreadyParsedClasses.add(configurationClass.getmetadata().getClassName());
}
for (String candidateName : newCandidateNames) {
if (!oldCandidateNames.contains(candidateName)) {
BeanDefinition bd = registry.getBeanDefinition(candidateName);
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
!alreadyParsedClasses.contains(bd.getBeanClassName())) {
candidates.add(new BeanDefinitionHolder(bd, candidateName));
}
}
}
candidateNames = newCandidateNames;
}
}
// 一些特殊的bean直接这里进行实例化
while (!candidates.isEmpty());
// Register the importRegistry as a bean in order to support importAware @Configuration classes
if (sbr != null && !sbr.containsSingleton(import_REGISTRY_BEAN_NAME)) {
sbr.registerSingleton(import_REGISTRY_BEAN_NAME, parser.getimportRegistry());
}
if (this.metadataReaderFactory instanceof CachingmetadataReaderFactory) {
// Clear cache in externally provided metadataReaderFactory; this is a no-op
// for a shared cache since it'll be cleared by the ApplicationContext.
((CachingmetadataReaderFactory) this.metadataReaderFactory).clearCache();
}
}
FUll 和 Lite模式简介
spring将所有的配置类分为两种 一种是@Configuration注解标注的类
其余的都是lite类
| full | lite |
|---|---|
| @Configuration | @import @Component @ComponentScan @import @importResource @Bean |
下文第一段单纯这样配置不起作用,这个类不是lite模式类吗?为什么不起作用?
为什么第二段代码和第三段就可以起作用
- 首先扫描BeanDefinition的第一步是获取已经配置的[full,lite]BeanDefinition
- 根据已经配置的BeanDefinition进行递归解析lite和full模式的Configurationclass
@ComponentScan("com.renxl.compoment.scan")
public class Config {
不可以被解析
}
@ComponentScan(basePackages = {"com.renxl.compoment"})
public class AdminApplication {
public static void main(String[] args) {
可以被解析 因为在spring容器refresh之前 AdminApplication的BeanDefinition已经被注册到beanfactory
SpringApplication.run(AdminApplication.class, args);
}
}
@ComponentScan(basePackages = {"com.renxl.compoment"})
public class AdminApplication {
public static void main(String[] args) {
可以被解析 因为在spring容器refresh之前 AdminApplication的BeanDefinition已经被注册到beanfactory
SpringApplication.run(AdminApplication.class, args);
}
}
@ComponentScan(basePackages = {"com.renxl.compoment"})
@Component
package com.renxl.compoment.config;
public class ConfigAfterBeComponent {
当AdminApplication扫描到ConfigAfterBeComponent时,其作为一个Component被注册,那么就会递归判断其是否是一个lite或者full模式的配置类,很明显其是一个lite模式,所以可以被解析
}
总结
- ConfigurationClassPostProcessor 将实际的BD生成工作交给ConfigurationClassParser和ConfigurationClassBeanDefinitionReader去做
- ConfigurationClassParser 的核心作用是解析配置类[FULL,LITE] 完成BD的解析,并对解析的结果重新进行递归解析,所有的解析类都会放置到ConfigurationClassParser.configurationClasses
- ConfigurationClassPostProcessor会获取ConfigurationClassParser.configurationClasses并
调用ConfigurationClassBeanDefinitionReader完成协同工作 - ConfigurationClassBeanDefinitionReader主要用来完成imported[被导入]@Bean和importedResources以及importBeanDefinitionRegistrar的BeanDefinition生成



