ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
ConfigurationClassPostProcessor读取BeanDefinition内部通过ConfigurationClassParser解析器来解析的
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());
}
}
//解析完之后,再处理deferredImportSelector
this.deferredImportSelectorHandler.process();
}
将待解析的配置类包装成一个ConfigurationClass类,这个类有这三个重要属性
AnnotationMetadata metadata 当前配置类的注解元数据对象
Resource resource 当前配置类的源
Set<ConfigurationClass> importedBy 当前配置类被谁导进来解析的
且还会传入一个filter,Predicate<String> DEFAULT_EXCLUSION_FILTER = className ->
(className.startsWith("java.lang.annotation.") || className.startsWith("org.springframework.stereotype."))
protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
//判断是否需要跳过不处理,主要是看配置类有没注解了@Conditional,且条件是满足的
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
// 判断当前配置是否已经被解析过了,若存在,说明之前解析过了,下面的这个逻辑最主要的判断就是,当前要解析的类是否为被导入的,若不是,优先进行解析,若是
// 则不再进行解析了
ConfigurationClass existingClass = this.configurationClasses.get(configClass);
if (existingClass != null) {
// 假如当前要解析的配置类是通过导入的方式(导入的方式主要有两种,一种是内部类,一种是通过@Import),且被解析过的也是通过导入的方式,那么直接
// 合并两者的importedBy即可
if (configClass.isImported()) {
if (existingClass.isImported()) {
existingClass.mergeImportedBy(configClass);
}
// 如果被解析过的类不是通过导入的,而当前要解析的是通过导入的,那么步处理,直接return
return;
}
else {
// 假如当前要解析的配置类不是被导入进来的,那么直接移除旧的,重新进行解析
this.configurationClasses.remove(configClass);
this.knownSuperclasses.values().removeIf(configClass::equals);
}
}
// 递归处理配置类和他的父类
SourceClass sourceClass = asSourceClass(configClass, filter);
do {
//每次解析完当前的配置类,会返回其继承的父类,若父类不为空,则继续递归解析,若为空了,则不解析
sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
}
while (sourceClass != null);
//将每次解析完的配置类添加到map中
this.configurationClasses.put(configClass, configClass);
}
doProcessConfigurationClass方法是解析配置类的核心,主要分为以下几个步骤
- 若配置类注解了@Component,那么也会解析其内部类
- 处理 @PropertySource,本文不做说明
- 处理@ComponentScan,扫描这个路径下的BeanDefinition
- 处理@Import注解
- 处理@ImportResource,这个一般是和xml相关的,本文不做说明
- 处理配置类内部注解了@Bean的方法
- processInterfaces,处理接口
- 处理父类,返回进行递归解析
步骤1,这种针对的是配置类有内部类的情况,会将内部类也当成配置类,进行递归解析
@Configuration
public class CoreConfig {
//当解析MemberClassConfig1这个ConfigurationClass类时,会将外部类CoreConfig添加到其属性importedBy集合中
class MemberClassConfig1 {
@Bean
public User user() {
return new User()
}
}
}
步骤3,解析@ComponentScan,若该注解没有显示的设定属性值,那么默认会扫描配置类所在的路径下的所有BeanDefinition
//获取注解了@ComponentScan的列表
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
//这里再次判断是否需要跳过,看有没注解了@Conditional且条件符合的
if (!componentScans.isEmpty() &&
!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
//循环遍历每个@ComponentScan,解析对应的@BeanDefinition
for (AnnotationAttributes componentScan : componentScans) {
//获取到ComponentScan扫描路径下的所有BeanDefinition
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
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
//判断每个BeanDefinition是否还是一个配置类,若是的话,需要进行递归解析。应用程序中定义的bean,一般都符合配置类的条件
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
//这里判断BeanDefinition是否为一个配置类,主要通过以下3个方面,满足其中任何一种即可
//1. 是否注解了@Configuration,且该注解属性值proxyBeanMethods不为False
//2. 不是接口,且注解了@Import @Component @ImportResource @ComponentScan中的任何一个
//3. 不是接口,且类内部是否有注解了@Bean的方法
步骤4,处理@Import,springboot很多扩展都是直接或间接的通过@Import来实现的,Import类主要分为三种情况,分别为ImportSelector、ImportBeanDefinitionRegistrar、普通的配置类
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
boolean checkForCircularImports) {
//这里省略一些判断是否为空、是否循环import的代码,将主要关注点放在解析Import
else {
this.importStack.push(configClass);
try {
for (SourceClass candidate : importCandidates) {
if (candidate.isAssignable(ImportSelector.class)) {
// ImportSelector --> ImportSelector主要是处理这种情况的,如果应用要导入外部的10个@Configuration配置类,可以通过在 // Import的value值写下这10个类,或者通过ImportSelector,只要实现了selectImports这个接口(返回这10个配置类),
// 然后通过@Import一个ImportSelector类,间接的将10个配置类导入进来解析,当然了,每个导入的配置类,还需要递归调用
// processImports,因为有可能这个配置类也是一个ImportSelector或ImportBeanDefinitionRegistrar
Class<?> candidateClass = candidate.loadClass();
ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
this.environment, this.resourceLoader, this.registry);
Predicate<String> selectorFilter = selector.getExclusionFilter();
if (selectorFilter != null) {
exclusionFilter = exclusionFilter.or(selectorFilter);
}
//DeferredImportSelector继承自ImportSelector,用于在所有的@Configuration都解析完了之后,再处理这种延迟的Selector
//这个主要处理注解了@Conditional的
if (selector instanceof DeferredImportSelector) {
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
}
else {
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
//递归解析Import
processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
}
}
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
// ImportBeanDefinitionRegistrar -> 通过实现registerBeanDefinitions这个接口,可以手动注册更多的BeanDefinition
// 这里只是将ImportBeanDefinitionRegistrar添加到ConfigurationClass的属性importBeanDefinitionRegistrars中,key为
// ImportBeanDefinitionRegistrar,值为导入ImportBeanDefinitionRegistrar的所属配置类
Class<?> candidateClass = candidate.loadClass();
ImportBeanDefinitionRegistrar registrar =
ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
this.environment, this.resourceLoader, this.registry);
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
else {
// Import类不是ImportSelector或者ImportBeanDefinitionRegistrar -> 当做@Configuration类进行递归解析
//candidate封装成ConfigurationClass进行解析,这类的逻辑和处理内部类的情况一样
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
}
}
}
//省略异常处理逻辑
finally {
this.importStack.pop();
}
}
}
步骤6,处理@Bean方法。解析配置类的所有@Bean方法,每个@Bean方法会生成一个BeanMethod对象,然后添加到ConfigurationClass的属性集合beanMethods中
步骤7,处理实现的接口。在java8之后,接口有默认方法,因此这里需要判断实现的接口是否有注解了@Bean的默认方法,若有,也需要将这些默认方法生成对应的BeanMethod对象,添加到ConfigurationClass的属性集合beanMethods中
步骤8,处理父类。
if (sourceClass.getMetadata().hasSuperClass()) {
//拿到当前配置类的父类,没显示extend的话,默认情况都是java.lang.Object
String superclass = sourceClass.getMetadata().getSuperClassName();
//若父类是Object类的话,或者knownSuperclasses包含了,那么直接返回null,无需解析父类
if (superclass != null && !superclass.startsWith("java") &&
!this.knownSuperclasses.containsKey(superclass)) {
//将父类添加到knownSuperclasses,防止重复解析,因为可能会有多个配置类继承同一个父类的情况,那么其中一个解析,其他就不能重复解析了
this.knownSuperclasses.put(superclass, configClass);
return sourceClass.getSuperClass();
}
}
当解析完所有的ConfigurationClass后,通过@ComponentScan扫描的BeanDefinition已经加入到容器中了,而通过其他方式的(@BeanMethod、@Import、@ImportResource)等,只是将一些中间对象维护到ConfigurationClass对象的某些属性值中,因此spring工厂还需要对这些进行处理,解析最终需要的BeanDefinition
public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
//循环对每个ConfigurationClass进行处理,加载BeanDefinition对象
for (ConfigurationClass configClass : configurationModel) {
loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
}
}
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;
}
if (configClass.isImported()) {
//将配置类自身转换成BeanDefinition对象,然后添加到容器中
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
//将BeanMethod对象转成BeanDefinition对象,然后添加到容器中
loadBeanDefinitionsForBeanMethod(beanMethod);
}
//解析通过ImportResource注解导入的BeanDefinition
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
//解析通过@Import注解导入的ImportBeanDefinitionRegistrar的BeanDefinition
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
网友评论