在《配置类解析(中)》篇,介绍了解析配置类的核心流程,主要是介绍了parese()方法中的流程,那么在该方法的do-while循环中,还有哪些部分呢,这里将重点介绍
刚开始进行配置类解析时,获取到的配置类只是一小部分,更多的配置类是在解析过程中新生成,而新生成的配置类,一部分在当前轮解析的时候就已经解析过了,但还有一部分却没有解析。比如第二部分中介绍到的添加到当前配置类属性中的实例或资源,其中有importBeanDefinitionRegistrars、importedResources和BeanMethod,解析前两者时都有可能会生成新的配置类,尤其是importedResources
do {
StartupStep processConfig = this.applicationStartup.start("spring.context.config-classes.parse");
// 解析配置类,会把每个BeanDefinitionHolder首先封装为ConfigurationClass
// 在这个过程中会进行扫描、导入等步骤,从而会找到其他的ConfigurationClass
// 解析配置类的结果是什么?
parser.parse(candidates); // AppConfig.class--->BeanDefinition
……
}
while (!candidates.isEmpty());
1.1 加载配置类的BeanDefinition
首先获取所有已经解析过的配置类,这些配置类中可能就有上面三个属性的值,所以会去调用loadBeanDefinitions()方法去生成这些配置类对应的一些BeanDefinition,对于处理过的配置类,添加到alreadyParsed缓存中,表示这些配置类已经完全处理过了
// configClasses相当于就是解析之后的结果 SetconfigClasses = 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()); } // 把所有的ConfigurationClass加载成BeanDefinition,通过情况下一个配置类会对应一个BeanDefinition,不过也有可能一个配置类对应多个BeanDefinition // 比如一个配置类中有多个@Bean,一个配置配置了@importResource this.reader.loadBeanDefinitions(configClasses); alreadyParsed.addAll(configClasses); processConfig.tag("classCount", () -> String.valueOf(configClasses.size())).end(); // candidates中存的是BeanDefinition,configClasses中存的是ConfigurationClass candidates.clear();
遍历这些配置类
-
如果该配置类是通过import导入的或者是@Component类的内部类,都经过了解析,但还没生成BeanDefinition,在这里为这些配置类注册BeanDefinition
-
遍历当前配置类的BeanMethod实例列表,为@Bean注解方法生成BeanDefinition,在生成BeanDefinition的过程中,如果已经有该类型的BeanDefinition(方法重载)则不会再去重复生成,但需要把之前生成的BeanDefinition的isFactoryMethodUnique设置为false,表示有重载方法,当getBean()的时候,会根据这个标识去选择合适的方法创建Bean实例
-
如果配置类通过@importResource引入了spring.xml文件,则在这里去解析xml文件,在这个过程中,可能会生成新的配置类的BeanDefinition
-
最后去遍历实现了importBeanDefinitionRegistrar接口的实例,调用其registerBeanDefinitions()方法,这里也可能会生成新的配置类的BeanDefinition
public void loadBeanDefinitions(Set1.2 解析新注册的BeanDefinition的配置类configurationModel) { TrackedConditionevaluator trackedConditionevaluator = new TrackedConditionevaluator(); for (ConfigurationClass configClass : configurationModel) { loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionevaluator); } } private void loadBeanDefinitionsForConfigurationClass( ConfigurationClass configClass, TrackedConditionevaluator trackedConditionevaluator) { …… if (configClass.isimported()) { // 将被导入的类生成BeanDefinition并注册到Spring容器中 // @Component的内部类,@import所导入的类都是被导入的类 registerBeanDefinitionForimportedConfigurationClass(configClass); } // @Bean生成BeanDefinition并注册 for (BeanMethod beanMethod : configClass.getBeanMethods()) { loadBeanDefinitionsForBeanMethod(beanMethod); } // 处理@importResource("spring.xml") loadBeanDefinitionsFromimportedResources(configClass.getimportedResources()); // 处理importBeanDefinitionRegistrar,调用registerBeanDefinitions()方法 loadBeanDefinitionsFromRegistrars(configClass.getimportBeanDefinitionRegistrars()); }
在加载配置类的BeanDefinition时,生成的新的BeanDefinition可能是配置类,检查BeanDefinition是否是配置类,并且没有经过解析,加入到candidates中,循环进行解析
do {
StartupStep processConfig = this.applicationStartup.start("spring.context.config-classes.parse");
// 解析配置类,会把每个BeanDefinitionHolder首先封装为ConfigurationClass
// 在这个过程中会进行扫描、导入等步骤,从而会找到其他的ConfigurationClass
// 解析配置类的结果是什么?
parser.parse(candidates); // AppConfig.class--->BeanDefinition
……
// 如果发现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);
// 检查多出来的BeanDefinition是不是配置类,需不需要解析
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
!alreadyParsedClasses.contains(bd.getBeanClassName())) {
candidates.add(new BeanDefinitionHolder(bd, candidateName));
}
}
}
candidateNames = newCandidateNames;
}
}
while (!candidates.isEmpty());



