一文学会Spring的@Configuration配置类解析
为了给组里的实习生妹妹讲如何自定义Springboot的Starter,
我觉得需要让她先知道Springboot的自动装配机制,
但又感觉是不是得先让她了解Spring的SPI机制,
最后又觉得还有必要说明一下一个@Configuration配置类在Spring中如何被解析,这又会引出对ConfigurationClassPostProcessor的讲解,
完了,收不住了,到处都是知识盲区。
知识盲区脑图如下。
前言
本篇文章将详细分析Spring中如何加载并解析由@Configuration注解修饰的配置类。
@Configuration注解是Spring中特别重要且知名的注解,大家都知道怎么使用(如果还不知道,那你一定是没看超详细总结Spring的配置注解),作用就是可以向容器注册bean,并且就像“每一个成功的男人背后都有一个优秀的女人在支持”,@Configuration注解的背后也有一个功能强大的类在支撑,那就是ConfigurationClassPostProcessor,所以本文的重点就是ConfigurationClassPostProcessor如何解析由@Configuration注解修饰的配置类。
本文的一个思维导图如下所示。
最后,请务必知道Spring的BeanDefinition是什么,不能只知道Spring有bean但不知道bean的前生BeanDefinition,如果真不知道,可以看一下超详细分析Spring的BeanDefinition
Springboot版本:2.4.1
Spring版本:5.3.2
正文
一. 示例工程搭建
在进行ConfigurationClassPostProcessor源码分析前,需要搭建示例工程来演示ConfigurationClassPostProcessor的执行逻辑。
定义如下几个业务类。
public class MyController {}
@Service
public class MyService {}
public class MyDao {}
配置类如下所示。
@ComponentScan
@Configuration
@Import({MyImportBeanDefinitionRegistrar.class,
MyImportSelector.class})
public class MyConfig {
@Bean
public MyDao myDao() {
return new MyDao();
}
}
MyImportBeanDefinitionRegistrar实现了ImportBeanDefinitionRegistrar接口,定义如下。
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
BeanDefinition beanDefinition = new RootBeanDefinition(MyController.class);
registry.registerBeanDefinition("myController", beanDefinition);
}
}
MyImportSelector实现了ImportSelector接口,定义如下。
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[] {
"com.learn.beanfactory.postprocessor.further.MyFurtherConfig"
};
}
}
上面中的MyFurtherConfig也是一个配置类,定义如下。
@Configuration
public class MyFurtherConfig {
@Bean
public MyFurtherService myFurtherService() {
return new MyFurtherService();
}
}
MyFurtherService是一个业务类,定义如下。
public class MyFurtherService {}
测试类定义如下。
public class MyTest {
public static void main(String[] args) {
ApplicationContext applicationContext
= new AnnotationConfigApplicationContext(MyConfig.class);
}
}
示例工程目录结构如下所示。
二. BeanFactoryPostProcessor
Spring中提供了大量的扩展点,而ConfigurationClassPostProcessor的扩展点类型叫做bean工厂后置处理器,也就是BeanFactoryPostProcessor。
先观察一下BeanFactoryPostProcessor的类图,如下所示。
BeanFactoryPostProcessor接口允许其实现类修改注册表中的BeanDefinition,这里的注册表指ConfigurableListableBeanFactory接口的实现类,通常为DefaultListableBeanFactory(如果不知道这是什么,可以就理解为我们常说的Spring容器)。
Spring启动并初始化容器阶段,会调用到AbstractApplicationContext#refresh方法来刷新容器,在AbstractApplicationContext#refresh方法中,会先执行invokeBeanFactoryPostProcessors() 方法来执行每一个BeanFactoryPostProcessor的逻辑,并且这一步在初始化bean之前完成。
refresh() 方法简要表示如下。
public void refresh() throws BeansException, IllegalStateException {
......
// 执行bean工厂后置处理器逻辑
invokeBeanFactoryPostProcessors(beanFactory);
......
// 添加bean后置处理器到容器
registerBeanPostProcessors(beanFactory);
......
// 初始化bean
finishBeanFactoryInitialization(beanFactory);
......
}
既然BeanFactoryPostProcessor接口允许其实现类修改注册表中的BeanDefinition,但是在Spring启动并且初始化容器的最开始阶段,Spring容器持有的注册表DefaultListableBeanFactory中是没有BeanDefinition的,那么肯定有一个时机存在一个类完成了将BeanDefinition加载到注册表中,时机就是invokeBeanFactoryPostProcessors() 方法的调用,类则是ConfigurationClassPostProcessor。
ConfigurationClassPostProcessor用于解析由@Configuration注解修饰的类(称为配置类),其类图如下所示。
ConfigurationClassPostProcessor实现了BeanDefinitionRegistryPostProcessor接口,BeanDefinitionRegistryPostProcessor接口继承于BeanFactoryPostProcessor接口,所以ConfigurationClassPostProcessor有如下两层身份。
- ConfigurationClassPostProcessor是一个bean工厂后置处理器;
- ConfigurationClassPostProcessor具备向容器注册BeanDefinition的功能。
所以在Spring启动并初始化容器的最开始阶段,Spring会执行ConfigurationClassPostProcessor的逻辑来解析配置类,并且Spring还会通过流程控制,让BeanDefinitionRegistryPostProcessor的执行先于非BeanDefinitionRegistryPostProcessor的bean工厂后置处理器。
小结
- BeanFactoryPostProcessor叫做bean工厂后置处理器,ConfigurationClassPostProcessor是由Spring提供的可以实现向容器注册BeanDefinition功能的bean工厂后置处理器;
- ConfigurationClassPostProcessor的执行先于非BeanDefinitionRegistryPostProcessor的bean工厂后置处理器;
- ConfigurationClassPostProcessor向容器注册BeanDefinition是通过解析配置类来实现。
三. BeanFactoryPostProcessor执行顺序
前文已知ConfigurationClassPostProcessor就是一个Spring内置的BeanFactoryPostProcessor,但是Spring中有那么多的BeanFactoryPostProcessor,包括Spring内置提供的,用户自定义的,这些BeanFactoryPostProcessor之间的执行肯定有一个先后,本节将对BeanFactoryPostProcessor执行顺序进行一个分析。
在示例工程中,创建AnnotationConfigApplicationContext容器时传入了MyConfig配置类的Class对象,称创建容器时传入的配置类为初始配置类,下面再给出初始配置类MyConfig的定义,如下所示。
@ComponentScan
@Configuration
@Import({MyImportBeanDefinitionRegistrar.class,
MyImportSelector.class})
public class MyConfig {
@Bean
public MyDao myDao() {
return new MyDao();
}
}
在MyConfig的定义中,使用了如下注解。
- @ComponentScan注解。默认将配置类所在包及其子包下所有由@Component,@Controller,@Service,@Repository,@Configuration注解修饰的类注册为容器中的bean;
- @Configuration注解。表示当前类是一个配置类,配置类也会被注册为容器中的bean;
- @Import注解。通过@Import注解可以导入ImportBeanDefinitionRegistrar和ImportSelector的实现类,并通过它们的实现类来向容器注册bean或配置类;
- @Bean注解。在配置类中所有由@Bean注解修饰的方法的返回值,会被注册为容器中的bean。
在配置类中,有两种方式来向容器注册bean。
- 通过配置类直接向容器注册bean。例如使用@Bean注解,使用@ComponentScan注解和使用@Import(业务类.class);
- 通过配置类向容器注册配置类从而间接注册bean。被注册的配置类也会被解析,从而被注册的配置类所配置的bean也会被注册到容器中,Springboot中的自动装配就是这样实现的。
上述讨论的通过配置类向容器注册bean,并且可以使用多种注解和基于多种方式,能够实现这样的功能,实际是依赖的ConfigurationClassPostProcessor。在Spring中,new一个容器就会触发这个容器的初始化逻辑,例如示例工程中AnnotationConfigApplicationContext的构造函数会调用到AbstractApplicationContext的refresh() 方法,在refresh() 方法中会在初始化bean之前调用到invokeBeanFactoryPostProcessors() 方法来执行bean工厂后置处理器的逻辑,invokeBeanFactoryPostProcessors() 方法实现如下所示。
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
// 将执行bean工厂后置处理器的操作委托给PostProcessorRegistrationDelegate
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
if (!IN_NATIVE_IMAGE && beanFactory.getTempClassLoader() == null
&& beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}
继续看PostProcessorRegistrationDelegate的invokeBeanFactoryPostProcessors() 方法。
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
// 记录已经执行逻辑的内置BeanDefinitionRegistryPostProcessor的标识以防止重复执行
Set<String> processedBeans = new HashSet<>();
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
// 保存自定义的非BeanDefinitionRegistryPostProcessor的bean工厂后置处理器
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
// 保存执行逻辑的内置BeanDefinitionRegistryPostProcessor
// 在执行完内置BeanDefinitionRegistryPostProcessor的逻辑后
// 还需要执行内置BeanDefinitionRegistryPostProcessor的BeanFactoryPostProcessor的逻辑
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
// 先执行自定义的BeanDefinitionRegistryPostProcessor的逻辑
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
}
else {
// 自定义的是非BeanDefinitionRegistryPostProcessor的bean工厂后置处理器
// 则保存到regularPostProcessors集合中,最后会调用这些自定义bean工厂后置处理器的逻辑
regularPostProcessors.add(postProcessor);
}
}
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
// 首先,执行实现了PriorityOrdered接口的内置BeanDefinitionRegistryPostProcessor的逻辑
// 由于ConfigurationClassPostProcessor实现了PriorityOrdered接口,所以其逻辑在这里就会执行
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
// 把本批次需要执行的内置BeanDefinitionRegistryPostProcessor保存到currentRegistryProcessors集合中
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
// 把本批次需要执行的内置BeanDefinitionRegistryPostProcessor的标识保存到processedBeans集合
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
// 把本批次需要执行的内置BeanDefinitionRegistryPostProcessor全部保存到registryProcessors集合中
registryProcessors.addAll(currentRegistryProcessors);
// 执行本批次符合条件的内置BeanDefinitionRegistryPostProcessor的逻辑
// ConfigurationClassPostProcessor的逻辑会在这里被执行
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors,
registry, beanFactory.getApplicationStartup());
currentRegistryProcessors.clear();
// 然后,执行实现了Ordered接口的内置BeanDefinitionRegistryPostProcessor的逻辑
// 尽管ConfigurationClassPostProcessor也实现了Ordered接口
// 但是其在上批次中已经执行过逻辑,所以这里不会重复执行ConfigurationClassPostProcessor的逻辑
// 依据就是判断processedBeans中是否保存有ConfigurationClassPostProcessor的标识
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors,
registry, beanFactory.getApplicationStartup());
currentRegistryProcessors.clear();
// 最后,执行剩余的内置BeanDefinitionRegistryPostProcessor的逻辑
boolean reiterate = true;
while (reiterate) {
reiterate = false;
postProcessorNames = beanFactory.getBeanNamesForType(
BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName)) {
currentRegistryProcessors.add(beanFactory.getBean(
ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
reiterate = true;
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors,
registry, beanFactory.getApplicationStartup());
currentRegistryProcessors.clear();
}
// 在执行完所有内置BeanDefinitionRegistryPostProcessor的逻辑后
// 现在需要执行所有内置BeanDefinitionRegistryPostProcessor的BeanFactoryPostProcessor的逻辑
// 以及执行所有自定义的BeanFactoryPostProcessor的逻辑
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
}
else {
invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
}
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (processedBeans.contains(ppName)) {
}
else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
// 把实现了PriorityOrdered接口的内置BeanFactoryPostProcessor保存到priorityOrderedPostProcessors集合中
priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
// 把实现了Ordered接口的内置BeanFactoryPostProcessor保存到orderedPostProcessorNames集合中
orderedPostProcessorNames.add(ppName);
}
else {
// 把其余内置BeanFactoryPostProcessor保存到nonOrderedPostProcessorNames集合中
nonOrderedPostProcessorNames.add(ppName);
}
}
// 首先,执行实现了PriorityOrdered接口的内置BeanFactoryPostProcessor
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
// 然后,执行实现了Ordered接口的内置BeanFactoryPostProcessor
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
for (String postProcessorName : orderedPostProcessorNames) {
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
// 最后,执行剩余的内置BeanFactoryPostProcessor
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
beanFactory.clearMetadataCache();
}
小结
invokeBeanFactoryPostProcessors() 方法特别长,但是实现的步骤特别清晰,耐得住性子的朋友可以自行对着注释看一下,耐不住性子的可以直接看小结。
- 先执行自定义的BeanDefinitionRegistryPostProcessor的逻辑;
- 然后执行实现了PriorityOrdered接口的内置BeanDefinitionRegistryPostProcessor的逻辑(ConfigurationClassPostProcessor的逻辑在这里被执行);
- 然后执行实现了Ordered接口的内置BeanDefinitionRegistryPostProcessor的逻辑;
- 然后执行剩余的内置BeanDefinitionRegistryPostProcessor的逻辑;
- 然后执行自定义的BeanDefinitionRegistryPostProcessor的BeanFactoryPostProcessor的逻辑;
- 然后执行内置BeanDefinitionRegistryPostProcessor的BeanFactoryPostProcessor的逻辑;
- 然后执行实现了PriorityOrdered接口的内置BeanFactoryPostProcessor的逻辑;
- 然后执行实现了Ordered接口的内置BeanFactoryPostProcessor的逻辑;
- 最后执行剩余的内置BeanFactoryPostProcessor的逻辑。
四. ConfigurationClassPostProcessor执行分析
1. 入口分析
在PostProcessorRegistrationDelegate的invokeBeanFactoryPostProcessors() 方法中,会调用到ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry() 方法,该方法的注释如下所示。
Derive further bean definitions from the configuration classes in the registry.
直译过来就是:从注册表中的配置类派生进一步的bean定义。这里的注册表指的就是容器持有的DefaultListableBeanFactory,注册表中的配置类指的就是创建Spring容器时传入的配置类即初始配置类,派生进一步的bean定义指的就是将初始配置类直接或间接向容器注册的bean解析为BeanDefinition并保存到DefaultListableBeanFactory的beanDefinitionMap中。
ConfigurationClassPostProcessor解析配置类的逻辑在processConfigBeanDefinitions() 方法中,该方法比较长,所以这里先给出其实现流程图。
概括一下就是。
- 先将初始配置类的BeanDefinition从注册表(这里指DefaultListableBeanFactory,后续如果无特殊说明,注册表默认指DefaultListableBeanFactory)的beanDefinitionMap中获取出来;
- 创建ConfigurationClassParser,解析初始配置类的BeanDefinition,即解析@PropertySource,@ComponentScan,@Import,@ImportResource,@Bean等注解并生成ConfigurationClass,最后缓存在ConfigurationClassParser的configurationClasses中;
- 创建ConfigurationClassBeanDefinitionReader,解析所有ConfigurationClass,基于ConfigurationClass创建BeanDefinition并缓存到注册表的beanDefinitionMap中。
下面开始分析源码。
ConfigurationClassPostProcessor#processConfigBeanDefinitions方法源码如下。
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
String[] candidateNames = registry.getBeanDefinitionNames();
// 从注册表中把初始配置类对应的BeanDefinition获取出来
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
// 如果未获取到初始配置类对应的BeanDefinition,则直接返回
if (configCandidates.isEmpty()) {
return;
}
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return Integer.compare(i1, i2);
});
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();
}
// 创建ConfigurationClassParser以解析初始配置类及其引出的其它配置类
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");
// ConfigurationClassParser开始执行解析
parser.parse(candidates);
parser.validate();
// 将ConfigurationClassParser解析得到的ConfigurationClass拿出来
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);
// 创建ConfigurationClassBeanDefinitionReader,以基于ConfigurationClass创建BeanDefinition
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
// 开始创建BeanDefinition并注册到注册表中
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
processConfig.tag("classCount", () -> String.valueOf(configClasses.size())).end();
candidates.clear();
if (registry.getBeanDefinitionCount() > candidateNames.length) {
String[] newCandidateNames = registry.getBeanDefinitionNames();
Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
Set<String> 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;
}
}
while (!candidates.isEmpty());
if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
}
if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
}
}
在processConfigBeanDefinitions() 方法中,ConfigurationClassPostProcessor将解析初始配置类以得到ConfigurationClass的操作委托给了ConfigurationClassParser,将基于ConfigurationClass创建BeanDefinition并注册到注册表的操作委托给了ConfigurationClassBeanDefinitionReader,所以下面会对这两个步骤进行分析。
首先是ConfigurationClassParser解析初始配置类,其parse() 方法如下所示。
public void parse(Set<BeanDefinitionHolder> configCandidates) {
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
if (bd instanceof AnnotatedBeanDefinition) {
// 初始配置类对应的BeanDefinition为AnnotatedGenericBeanDefinition
// AnnotatedGenericBeanDefinition实现了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);
}
}
// 延迟处理DeferredImportSelector
this.deferredImportSelectorHandler.process();
}
由于初始配置类对应的BeanDefinition为AnnotatedGenericBeanDefinition,而AnnotatedGenericBeanDefinition实现了AnnotatedBeanDefinition接口,所以继续看parse(AnnotationMetadata metadata, String beanName) 方法,如下所示。
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
processConfigurationClass(new ConfigurationClass(metadata, beanName), DEFAULT_EXCLUSION_FILTER);
}
继续跟进ConfigurationClassParser#processConfigurationClass方法,如下所示。
protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter)
throws IOException {
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
ConfigurationClass existingClass = this.configurationClasses.get(configClass);
if (existingClass != null) {
if (configClass.isImported()) {
if (existingClass.isImported()) {
existingClass.mergeImportedBy(configClass);
}
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);
// 将解析得到的ConfigurationClass缓存起来
this.configurationClasses.put(configClass, configClass);
}
对于上面的processConfigurationClass() 方法,有两点需要注意。
- 在解析配置类时,通过配置类引入的bean或配置类,都会在解析之后得到ConfigurationClass,并不是只有配置类才会得到ConfigurationClass。例如示例工程中的MyService,其是在解析初始配置类MyConfig的@ComponentScan注解时被引入的bean,但是也会得到一个MyService的ConfigurationClass并缓存到configurationClasses中;
- 上面的processConfigurationClass() 方法是会被递归调用的方法。只要在解析配置类时通过配置类引入了bean或者配置类,那么都会为引入的bean或者配置类生成ConfigurationClass然后递归的调用回上述processConfigurationClass() 方法。通常,如果是bean对应的ConfigurationClass,在processConfigurationClass() 方法中不会有实际的解析逻辑发生,如果是配置类对应的ConfigurationClass,在processConfigurationClass() 方法中就会有实际的解析逻辑发生。
知道了上述的注意点后,下面以解析示例工程中的初始配置类MyConfig为例,继续深入分析。
ConfigurationClassParser的doProcessConfigurationClass() 方法如下所示。
protected final SourceClass doProcessConfigurationClass(
ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
throws IOException {
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
processMemberClasses(configClass, sourceClass, filter);
}
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");
}
}
// 解析@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) {
// 使用ComponentScanAnnotationParser来解析@ComponentScan注解信息
// 解析得到的bean会直接被创建为BeanDefinition并注册到注册表中
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
// 为解析得到的bean创建ConfigurationClass,然后递归调用到processConfigurationClass()方法进行解析
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
// 在这里会基于bean创建ConfigurationClass,然后递归调用到processConfigurationClass()方法进行解析
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
// 解析@Import注解
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));
}
processInterfaces(configClass, sourceClass);
if (sourceClass.getMetadata().hasSuperClass()) {
String superclass = sourceClass.getMetadata().getSuperClassName();
if (superclass != null && !superclass.startsWith("java") &&
!this.knownSuperclasses.containsKey(superclass)) {
this.knownSuperclasses.put(superclass, configClass);
return sourceClass.getSuperClass();
}
}
return null;
}
ConfigurationClassParser的doProcessConfigurationClass() 方法中会依次完成对@ComponentScan注解,@Import注解和@Bean注解的解析。
2. 解析@ComponentScan注解
解析@ComponentScan注解的步骤概括如下。
- 将@ComponentScan注解信息获取出来;
- 调用ComponentScanAnnotationParser基于@ComponentScan注解元信息获取到需要注册到容器中的bean的信息,并为这些bean生成BeanDefinition并注册到注册表中;
- 基于每个bean对应的BeanDefinition生成ConfigurationClass对象,然后递归调用processConfigurationClass() 方法解析bean对应的ConfigurationClass对象。
3. 解析@Import注解
解析@Import注解的逻辑在ConfigurationClassParser#processImports方法中,如下所示。
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
boolean checkForCircularImports) {
if (importCandidates.isEmpty()) {
return;
}
if (checkForCircularImports && isChainedImportOnStack(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
else {
this.importStack.push(configClass);
try {
// importCandidates是通过@Import注解导入的类信息
// 或者是通过ImportSelector导入的类信息
for (SourceClass candidate : importCandidates) {
if (candidate.isAssignable(ImportSelector.class)) {
// @Import注解导入的类实现了ImportSelector接口
// 对应示例工程中的MyImportSelector类
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);
}
if (selector instanceof DeferredImportSelector) {
// 如果实现了DeferredImportSelector接口,则需要延迟处理
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
}
else {
// 调用ImportSelector的selectImports()方法获取ImportSelector导入的类的全限定名
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
// 为ImportSelector导入的类生成SourceClass
Collection<SourceClass> importSourceClasses = asSourceClasses(
importClassNames, exclusionFilter);
// 递归调用processImports()方法处理ImportSelector导入的类
processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
}
}
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
// @Import注解导入的类实现了ImportBeanDefinitionRegistrar接口
Class<?> candidateClass = candidate.loadClass();
ImportBeanDefinitionRegistrar registrar =
ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
this.environment, this.resourceLoader, this.registry);
// 将ImportBeanDefinitionRegistrar缓存到ConfigurationClass的importBeanDefinitionRegistrars字段中
// 后续在解析ConfigurationClass为BeanDefinition的过程中
// 会调用到ImportBeanDefinitionRegistrar的registerBeanDefinitions()方法
// 向注册表直接注册BeanDefinition
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
else {
// @Import注解导入的类即不是ImportSelector也不是ImportBeanDefinitionRegistrar
// 则为Import注解导入的类创建ConfigurationClass并递归调用processConfigurationClass()方法进行解析
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
}
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to process import candidates for configuration class [" +
configClass.getMetadata().getClassName() + "]", ex);
}
finally {
this.importStack.pop();
}
}
}
processImports() 方法在处理@Import注解时,将@Import注解导入的类分成了三种类型进行处理。
- 实现了
ImportSelector
接口的类
如果实现了ImportSelector接口的类还同时实现了DeferredImportSelector接口,则将其添加到DeferredImportSelectorHandler中以实现延迟处理DeferredImportSelector。
否则在processImports() 方法中会立即调用ImportSelector的selectImports() 方法获取ImportSelector导入的类信息,然后再递归调用processImports() 方法来解析ImportSelector导入的类。
在示例工程中,MyImportSelector实现了ImportSelector接口,同时MyImportSelector实现的selectImports() 方法会返回MyFurtherConfig配置类的全限定名,所以会基于MyFurtherConfig的类信息创建SourceClass并递归调用processImports() 方法进行解析,这里也是通过配置类引入配置类的一个示例;
- 实现了
ImportBeanDefinitionRegistrar
接口的类
由于ImportBeanDefinitionRegistrar的registerBeanDefinitions() 方法可以直接向注册表注册BeanDefinition,所以在processImports() 方法中仅会将ImportBeanDefinitionRegistrar添加到ConfigurationClass的importBeanDefinitionRegistrars字段中,后续在解析ConfigurationClass为BeanDefinition的过程中会调用到ImportBeanDefinitionRegistrar的registerBeanDefinitions() 方法向注册表直接注册BeanDefinition;
- 即没有实现
ImportSelector
接口也没有实现ImportBeanDefinitionRegistrar
的类
processImports() 方法中会为这种类型的类创建ConfigurationClass并递归调用processConfigurationClass() 方法进行解析。
假如通过@Import注解直接导入一个bean,或者示例工程中通过@Import注解导入了MyImportSelector同时又通过MyImportSelector导入了MyFurtherConfig,都会为这些bean或配置类创建ConfigurationClass然后递归的调用processConfigurationClass() 方法进行解析。
4. 解析@Bean注解
解析@Bean注解的步骤概括如下。
- 将当前配置类中所有由@Bean注解修饰的方法获取出来,并封装成BeanMethod对象;
- 将BeanMethod对象添加到配置类对应的ConfigurationClass的beanMethods字段中。
解析@Bean注解就是将配置类中的由@Bean注解修饰的方法和配置类对应的ConfigurationClass对象绑定,后续解析ConfigurationClass为BeanDefinition的时候会使用到这些方法。
5. DeferredImportSelector的延迟处理
DeferredImportSelector的类图,如下所示。
已知在解析@Import注解时,如果通过@Import注解导入了DeferredImportSelector,那么会将DeferredImportSelector先缓存到DeferredImportSelectorHandler类中来实现延迟处理DeferredImportSelector的效果,那么是在哪里处理的DeferredImportSelector呢。实际是在ConfigurationClassParser#processConfigurationClass中。
public void parse(Set<BeanDefinitionHolder> configCandidates) {
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
if (bd instanceof AnnotatedBeanDefinition) {
// 初始配置类对应的BeanDefinition为AnnotatedGenericBeanDefinition
// AnnotatedGenericBeanDefinition实现了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);
}
}
// 延迟处理DeferredImportSelector
this.deferredImportSelectorHandler.process();
}
对应的流程图如下。
6. 解析ConfigurationClass
已知在ConfigurationClassPostProcessor的processConfigBeanDefinitions() 方法中,会先解析配置类并得到配置类和bean对应的ConfigurationClass,然后会再使用ConfigurationClassBeanDefinitionReader来将ConfigurationClass解析为BeanDefinition并注册到注册表中。
ConfigurationClassBeanDefinitionReader解析ConfigurationClass的入口是ConfigurationClassBeanDefinitionReader#loadBeanDefinitions方法,如下所示。
public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
for (ConfigurationClass configClass : configurationModel) {
loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
}
}
在loadBeanDefinitions() 方法中遍历每一个ConfigurationClass并调用了loadBeanDefinitionsForConfigurationClass() 方法,继续看loadBeanDefinitionsForConfigurationClass() 方法,如下所示。
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()) {
// 基于ConfigurationClass自身创建BeanDefinition并缓存到注册表中
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
// 基于ConfigurationClass中由@Bean注解修饰的方法创建BeanDefinition并缓存到注册表中
loadBeanDefinitionsForBeanMethod(beanMethod);
}
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
// 在这里执行ConfigurationClass缓存的ImportBeanDefinitionRegistrar的逻辑
// 即调用ImportBeanDefinitionRegistrar的registerBeanDefinitions()方法
// 直接向注册表注册BeanDefinition
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
至此,@Configuration配置类向Spring容器注册的所有bean对应的BeanDefinition就已经全部被加载了。
总结
@Configuration注解是一个很简单但是又很重要的注解,支撑@Configuration注解运作的类是ConfigurationClassPostProcessor,本篇文章主要是对ConfigurationClassPostProcessor的工作原理进行了分析。
ConfigurationClassPostProcessor是bean工厂后置处理器,同时也是具备注册BeanDefinition功能(因为实现了BeanDefinitionRegistryPostProcessor接口)的bean工厂后置处理器,所以ConfigurationClassPostProcessor逻辑的执行会先于普通bean工厂后置处理器。
ConfigurationClassPostProcessor向注册表注册BeanDefinition的步骤分为两个大的步骤。
- 使用ConfigurationClassParser将配置类自身,以及配置类引入的bean和配置类均解析为ConfigurationClass;
- 使用ConfigurationClassBeanDefinitionReader将ConfigurationClass解析为BeanDefinition并注册到注册表中。
整体的时序图如下所示。
最后,还想提一下,看如下一个Springboot启动类。
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
由于@SpringBootApplication是一个包含了@Configuration注解的复合注解,所以在Springboot应用中,我们的启动类就是一个配置类,也就是初始配置类,关于Springboot美好的一切都是由这个初始配置类开始的。
如果觉得本篇文章对你有帮助,求求你点个赞,加个收藏最后再点个关注吧。创作不易,感谢支持!
转载自:https://juejin.cn/post/7212240532796391483