共计 9275 个字符,预计需要花费 24 分钟才能阅读完成。
Spring 源码解析之 ——ConfigurationClassPostProcessor
思考:
(1) @Configuration,@Component,@Bean,@Import 注解的作用是什么? 什么时候被解析的。
这里就 ConfigurationClassPostProcessor 就上场了
先看张图,这个就是 ConfigurationClassPostProcessor 解决的构建节点。ConfigurationClassPostProcessor 实现了 BeanDefinitionRegistryPostProcessor,
而 BeanDefinitionRegistryPostProcessor 继承了 BeanFactoryPostProcessor,所以 ConfigurationClassPostProcessor 中须要重写 postProcessBeanDefinitionRegistry()
办法和 postProcessBeanFactory()办法。而 ConfigurationClassPostProcessor 类的作用就是通过这两个办法去实现的。
ConfigurationClassPostProcessor 做些什么?
1:postProcessBeanDefinitionRegistry()将 @Configuration,@Component,@Bean,@Import 等注解的对象, 解析为 BeanDefinition, 放在容器中,期待被解析为 Spring bean;
这里会将 @Configuration 注解的类的 BeanDefinition 增加个属性,标记是 FULL,还是 LITE
2:postProcessBeanFactory()被标记 FULL 的 BeanDefinition 的 beanClass 替换为 Cglib 代理的 class 名
processConfigBeanDefinitions()代码解析
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
String[] candidateNames = registry.getBeanDefinitionNames();
//..... 省略
// 将候选者进行排序
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(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
if (generator != null) {
this.componentScanBeanNameGenerator = generator;
this.importBeanNameGenerator = generator;
}
}
}
if (this.environment == null) {this.environment = new StandardEnvironment();
}
// 创立 @Configuration 解析器
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
do {StartupStep processConfig = this.applicationStartup.start("spring.context.config-classes.parse");
// 解析配置类,在此处会解析配置类上的注解(ComponentScan 扫描出的类,@Import 注册的类,以及 @Bean 办法定义的类)
// 留神:这一步只会将加了 @Configuration 注解以及通过 @ComponentScan 注解扫描的类才会退出到 BeanDefinitionMap 中
// 通过其余注解 (例如 @Import、@Bean) 的形式,在 parse()办法这一步并不会将其解析为 BeanDefinition 放入到 BeanDefinitionMap 中,// 而是先解析成 ConfigurationClass 类
// 真正放入到 map 中是在上面的 this.reader.loadBeanDefinitions()办法中实现的
parser.parse(candidates);
parser.validate();
Set<ConfigurationClass> 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());
}
// 将上一步 parser 解析出的 ConfigurationClass 类加载成 BeanDefinition
// 实际上通过上一步的 parse()后,解析进去的 bean 曾经放入到 BeanDefinition 中了,然而因为这些 bean 可能会引入新的 bean,例如实现了 ImportBeanDefinitionRegistrar 或者 ImportSelector 接口的 bean,或者 bean 中存在被 @Bean 注解的办法
// 因而须要执行一次 loadBeanDefinition(),这样就会执行 ImportBeanDefinitionRegistrar 或者 ImportSelector 接口的办法或者 @Bean 正文的办法
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
processConfig.tag("classCount", () -> String.valueOf(configClasses.size())).end();
candidates.clear();
//.... 省略代码
}
while (!candidates.isEmpty());
//..... 省略代码
}
1.parser.parse()
依据 BeanDefinition 类型的不同,调用 parse()不同的重载办法。理论是调用 ConfigurationClassParser 中的 processConfigurationClass()办法
parse() 具体代码
public void parse(Set<BeanDefinitionHolder> configCandidates) {for (BeanDefinitionHolder holder : configCandidates) {BeanDefinition bd = holder.getBeanDefinition();
try {if (bd instanceof AnnotatedBeanDefinition) {parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
}
else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
}
else {parse(bd.getBeanClassName(), holder.getBeanName());
}
}
catch (BeanDefinitionStoreException ex) {throw ex;}
catch (Throwable ex) {
throw new BeanDefinitionStoreException("Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
}
}
this.deferredImportSelectorHandler.process();}
processConfigurationClass()办法中理论解析的办法为 doProcessConfigurationClass()办法
protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
//..... 省略代码
SourceClass sourceClass = asSourceClass(configClass, filter);
do {sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
}
while (sourceClass != null);
this.configurationClasses.put(configClass, configClass);
}
doProcessConfigurationClass()办法中就开始了 Spring 一些注解的解析
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
throws IOException {
// 解析 @Component 注解的类
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
// 遍历被注解类的外部类,这个也是为什么一些外部类一样会被 spring 获取到的起因
processMemberClasses(configClass, sourceClass, filter);
}
// 解析 @PropertySource 注解
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");
}
}
// 解析 @ComponentScans , @ComponentScan 注解
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) {
// 解析 @ComponentScans , @ComponentScan 扫描包下的 @Component,@Service,@Controller,@Repository 注解。// 将扫描进去的类转为 bd 增加到 beanDefinitionMap 中
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
// 对 @Configuration 注解进行非凡解决
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {bdCand = holder.getBeanDefinition();
}
//checkConfigurationClassCandidate 给 @Configuration 注解的类打上 FULL 标记
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
// 解析 Import 注解注册的 bean,这一步只会将 import 注册的 bean 变为 ConfigurationClass, 不会变成 BeanDefinition
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
// 引入配置文件
AnnotationAttributes importResource =
AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
if (importResource != null) {String[] resources = importResource.getStringArray("locations");
Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
for (String resource : resources) {String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
configClass.addImportedResource(resolvedResource, readerClass);
}
}
// 解析 @Bean 注解
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
//...... 省略代码
// No superclass -> processing is complete
return null;
}
componentScanParser.parse()在扫描时会通过 includeFilters 和 excludeFilters 条件去决定具体扫描的 bean, 然而理论 includeFilters 中只有
@Component 注解,然而理论中扫描的到的 bean, 也会将 @Service,@Controller,@Repository,@Controller 都会被扫描进去。
这里大略是 @Component 元注解,Spring 在读取 @Service,@Controller,@Repository,@Controller,也读取了它的元注解,并将作为 @Component 解决。这里就不做具体分析了。
2.this.reader.loadBeanDefinitions()
在执行 parse()办法后 @Component,@Service 等注解的 bean 会被注解增加到 beanDefinitionMap, 而 @Import,@Bean 这些会被转为 ConfigurationClass 进行下一步解析。
这里是 loadBeanDefinitions()外面外围办法
private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {if (trackedConditionEvaluator.shouldSkip(configClass)) {String beanName = configClass.getBeanName();
if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {this.registry.removeBeanDefinition(beanName);
}
this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
return;
}
// 注册 @Import 润饰的 bean
if (configClass.isImported()) {registerBeanDefinitionForImportedConfigurationClass(configClass);
}
// 注册 @Bean 润饰的 bean
for (BeanMethod beanMethod : configClass.getBeanMethods()) {loadBeanDefinitionsForBeanMethod(beanMethod);
}
// 注册 @ImportResources 配置的信息
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
//@Import 注解的 bean, 且 bean 实现了 ImportBeanDefinitionRegistrar
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
3.postProcessBeanFactory()办法
postProcessBeanFactory()对加了 @Configuration 注解的类进行 CGLIB 代理和向 Spring 中增加一个后置处理器 ImportAwareBeanPostProcessor。
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
//..... 省略代码
//@Configuration 注解的类进行 CGLIB 代理
enhanceConfigurationClasses(beanFactory);
// 增加一个后置处理器 ImportAwareBeanPostProcessor
beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}