Spring源码深度解析:六、ConfigurationClassPostProcessor

news2024/11/26 4:45:00

在这里插入图片描述

一、前言

文章目录:Spring源码分析:文章目录

ConfigurationClassPostProcessor是非常重要的一个 后处理器。 ConfigurationClassPostProcessor完成了 配置类的解析和保存以及@Component注解、@Import等注解的解析工作 。将所有需要注入的bean解析成BeanDefinition保存到BeanFactory中。
在这里插入图片描述
首先来讲解一下ConfigurationClassPostProcessor的结构图如下。
可见ConfigurationClassPostProcessor接口实现了BeanDefinitionRegistryPostProcessor(BeanFactory的后处理器)
PriorityOrdered(设置自己的优先级为最高) 和各种Aware接口。

Springboot启动后,会通过SpringApplication#createApplicationContext()来创建应用上下文,默认请情况下我们一般创建AnnotationConfigServletWebServerApplicationContext作为应用上下文。而在AnnotationConfigServletWebServerApplicationContext构造函数中会创建AnnotatedBeanDefinitionReader。而在AnnotatedBeanDefinitionReader构造函数中会调用 AnnotationConfigUtils#registerAnnotationConfigProcessors(this.registry);,该方法将一些必要Bean(如ConfigurationClassPostProcessorAutowiredAnnotationBeanPostProcessorCommonAnnotationBeanPostProcessor等)注入到了容器中。

我们这里重点看的是BeanDefinitionRegistryPostProcessor接口的两个方法:

// 完成对 @Bean 方法的代理
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
// 允许在Spring容器启动后,在下一个阶段开始前,添加BeanDefinition的定义
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;

关于这两个方法的调用时机和作用,我们在之前的文章(Spring源码分析五:BeanFactoryPostProcessor的处理 - invokeBeanFactoryPostProcessors)已经讲过,调用过程主要是在 Spring容器刷新的过程中,其中postProcessBeanDefinitionRegistry方法先于 postProcessBeanFactory方法被调用。

通过本篇分析ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry()方法。得知了ConfigurationClassPostProcessor解析配置类(这里的配置类不仅仅局限于@Configuration 注解,还包括 @Import、 @ImportResource等注解),将解析到的需要注入到Spring容器中的bean的BeanDefinition保存起来。在后面的bean 初始化都需要BeanDefinition
ConfigurationClassPostProcessor#postProcessBeanFactory方法通过cglib代理配置类,来拦截@Bean修饰的方法。这么做的目的是为了在配置类中多次调用@Bean方法返回的是同一个结果。即在下面的代码中demoController()demoController2()方法中调用的demoService()方法返回的结果是同一个值。避免了单例模式下的多例创建。

二 、入口 - invokeBeanFactoryPostProcessors()

首先Spring容器的启动我们debug进入的是Spring的容器刷新方法:refresh(),接着我们F7进入子方法invokeBeanFactoryPostProcessors()该方法就是激活各种BeanFactory后处理器(调用在上下文中注册为bean的工厂处理器(BeanFactoryPostProcessor))。具体代码如下:
AbstractApplicationContext#invokeBeanFactoryPostProcessors()

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
		// getBeanFactoryPostProcessors方法获取了所有硬编码的bean工厂处理器
		PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

		// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
		// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
		// 默认情况下这里判断不会为空,在refresh方法调用的prepareBeanFactory方法内已经执行过这段代码了
		if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
			// 添加bean后置处理器,负责调用实现了LoadTimeWeaverAware接口setLoadTimeWeaver方法的bean
			beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
			// 添加一个临时类加载器
			beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
		}
	}

invokeBeanFactoryPostProcessors()>>> PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors()

public static void invokeBeanFactoryPostProcessors(
			ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

		// Invoke BeanDefinitionRegistryPostProcessors first, if any.
		// 记录所有即将或已经处理的beanName,用于防止重复处理
		Set<String> processedBeans = new HashSet<>();

		// 对BeanDefinitionRegistry类型的处理,这里是交由BeanDefinitionRegistryPostProcessor来处理
		// 这里判断BeanFactory如果是BeanDefinitionRegistry子类 则需要进行BeanDefinitionRegistryPostProcessor的处理,否则直接按照BeanFactoryPostProcessor处理即可。
		// 关于为什么BeanDefinitionRegistry比较特殊上面也说过,因为BeanDefinitionRegistryPostProcessor只能处理BeanDefinitionRegistry的子类,所以这里需要区分是否是BeanDefinitionRegistry类型
		if (beanFactory instanceof BeanDefinitionRegistry) {
			// 下面逻辑看似复杂,其实就两步:
			// 1. 获取所有硬编码的BeanDefinitionRegistryPostProcessor类型,激活postProcessBeanDefinitionRegistry方法
			// 2. 获取所有配置的BeanDefinitionRegistryPostProcessor,激活postProcessBeanDefinitionRegistry方法

			BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
			// 记录通过硬编码方式注册的BeanFactoryPostProcessor类型的处理器
			List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
			// 记录所有注册的BeanDefinitionRegistryPostProcessor类型的处理器(含有硬编码注册的和配置注入注册的)
			List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
			// 遍历硬编码注册的后处理器(都保存AbstractApplicationContext#beanFactoryPostProcessors中,这里通过参数beanFactoryPostProcessors传递过来)
			for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
				if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
					BeanDefinitionRegistryPostProcessor registryProcessor =
							(BeanDefinitionRegistryPostProcessor) postProcessor;
					registryProcessor.postProcessBeanDefinitionRegistry(registry);
					// 将硬编码注册BeanDefinitionRegistryPostProcessor放到registryProcessors中
					registryProcessors.add(registryProcessor);
				}
				else {
					regularPostProcessors.add(postProcessor);
				}
			}

			// Do not initialize FactoryBeans here: We need to leave all regular beans
			// uninitialized to let the bean factory post-processors apply to them!
			// Separate between BeanDefinitionRegistryPostProcessors that implement
			// PriorityOrdered, Ordered, and the rest.
			// 一个临时变量,记录通过配置方式注册的BeanDefinitionRegistryPostProcessor类型的处理器
			List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

			// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
			// 获取所有的实现了BeanDefinitionRegistryPostProcessor的beanName
			String[] postProcessorNames =
					beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			// 筛选出实现了PriorityOrdered接口的实现类,优先执行
			for (String ppName : postProcessorNames) {
				if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
					// 记录到currentRegistryProcessors中
					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					processedBeans.add(ppName);
				}
			}
			// 进行排序
			sortPostProcessors(currentRegistryProcessors, beanFactory);
			// 以配置方式注册的且实现了PriorityOrdered接口的BeanDefinitionRegistryPostProcessor集合全部放到registryProcessors中
			registryProcessors.addAll(currentRegistryProcessors);
			// 激活 postProcessBeanDefinitionRegistry 方法
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
			// 清空临时变量currentRegistryProcessors的内容
			currentRegistryProcessors.clear();

			// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
			postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			// 筛选出实现了Ordered接口的实现类,第二执行
			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);
			// 以配置方式注册的且实现了Ordered接口的BeanDefinitionRegistryPostProcessor集合全部放到registryProcessors中
			registryProcessors.addAll(currentRegistryProcessors);
			// 激活
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
			// 清空临时变量currentRegistryProcessors的内容
			currentRegistryProcessors.clear();

			// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
			// 最后获取No-Ordered(没有实现排序)接口的 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);
				// 将配置方式注册的且没有实现排序(No-Ordered)接口的BeanDefinitionRegistryPostProcessor集合全部放到registryProcessors中
				registryProcessors.addAll(currentRegistryProcessors);
				// 激活
				invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
				// 清空临时变量currentRegistryProcessors的内容
				currentRegistryProcessors.clear();
			}

			// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
			// 到这里,所有的 BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry()方法都已经激活结束。

			// 开始激活postProcessBeanFactory方法
			// 因为BeanDefinitionRegistryPostProcessor是BeanFactoryPostProcessor的子类,所有这里激活的是BeanDefinitionRegistryPostProcessor的postProcessBeanFactory()方法
			invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
			// regularPostProcessors中记录的是硬编码注入的BeanFactoryPostProcessor
			invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
		}

		else {
			// Invoke factory processors registered with the context instance.
			// 如果 beanFactory instanceof BeanDefinitionRegistry = false,那么BeanDefinitionRegistryPostProcessor.postProcessBeanDefinitionRegistry()方法并不生效,就直接激活postProcessBeanFactory()方法即可。
			// 激活硬编码注册的BeanFactoryPostProcessor.postProcessBeanFactory()方法
			invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
		}

		// 到这一步,所有的硬编码方式注入的后处理器都处理完毕; 配置注入的BeanDefinitionRegistryPostProcessor后处理器的postProcessBeanDefinitionRegistry()和postProcessBeanFactory()方法都已经激活。
		// 下面开始处理配置注入的BeanFactoryPostProcessor的postProcessBeanFactory后处理器。

		// Do not initialize FactoryBeans here: We need to leave all regular beans
		// uninitialized to let the bean factory post-processors apply to them!
		// 获取所有后处理器的beanName,用于后面处理
		String[] postProcessorNames =
				beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

		// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
		// Ordered, and the rest.
		// 创建几个保存不同排序的集合,按照实现的排序接口调用
		// 筛选出实现了排序接口PriorityOrdered的类
		List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
		// 筛选出实现了排序接口Ordered的类
		List<String> orderedPostProcessorNames = new ArrayList<>();
		// 筛选出未实现排序接口的类
		List<String> nonOrderedPostProcessorNames = new ArrayList<>();
		for (String ppName : postProcessorNames) {
			if (processedBeans.contains(ppName)) {
				// skip - already processed in first phase above
			}
			else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
				priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
			}
			else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
				orderedPostProcessorNames.add(ppName);
			}
			else {
				nonOrderedPostProcessorNames.add(ppName);
			}
		}

		// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
		// 排序和激活(实现了PriorityOrdered接口的后处理器)
		sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
		invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

		// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
		// 排序和激活(实现了Ordered接口的后处理器)
		List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();
		for (String postProcessorName : orderedPostProcessorNames) {
			orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
		}
		sortPostProcessors(orderedPostProcessors, beanFactory);
		invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

		// Finally, invoke all other BeanFactoryPostProcessors.
		// 排序和激活(没有实现排序接口的后处理器)
		List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
		for (String postProcessorName : nonOrderedPostProcessorNames) {
			nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
		}
		invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

		// Clear cached merged bean definitions since the post-processors might have
		// modified the original metadata, e.g. replacing placeholders in values...
		// 清除元数据缓存
		beanFactory.clearMetadataCache();
	}

从代码中我们可以看到激活 postProcessBeanDefinitionRegistry() 方法
invokeBeanFactoryPostProcessors() >>> invokeBeanDefinitionRegistryPostProcessors()

private static void invokeBeanDefinitionRegistryPostProcessors(
			Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {

		for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
			postProcessor.postProcessBeanDefinitionRegistry(registry);
		}
	}

下面我们就来解析一下这个主要方法postProcessBeanDefinitionRegistry()

三、ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry()

ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry()

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);

		// 关键方法,解析 配置类的定义
		processConfigBeanDefinitions(registry);
	}

可以看到postProcessBeanDefinitionRegistry()方法中并没有处理什么逻辑,真正逻辑在其调用的 processConfigBeanDefinitions方法中

1、解析配置类的定义 - processConfigBeanDefinitions

processConfigBeanDefinitions 方法完成了关于配置类的所有解析。

需要注意的是,到达这一步的时候, Springboot 启动类已经被解析成BeanDefinition 注册到容器中。

具体代码如下:
ConfigurationClassPostProcessor#processConfigBeanDefinitions()

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
		List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
		// 获取已经解析的BeanName。这里需要注意的是,Springboot的话,启动类已经被注册。具体的注册时机是在Springboot启动时候的SpringApplication#prepareContext方法中。
		String[] candidateNames = registry.getBeanDefinitionNames();
		// 遍历BeanName
		for (String beanName : candidateNames) {
			// 获取BeanDefinition
			BeanDefinition beanDef = registry.getBeanDefinition(beanName);
			// 如果bean被解析过(Bean被解析后会在beanDef中设置属性CONFIGURATION_CLASS_ATTRIBUTE),if条件成立,这里是为了防止重复解析
			if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
					ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
				if (logger.isDebugEnabled()) {
					logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
				}
			}
			// 1. ConfigurationClassUtils.checkConfigurationClassCandidate 解析了当前bean是否是配置类,关于其详细内容,后面解析 需要注意的是,
			// 本文所说的配置类即使满足 full 或 lite 条件的类,而不仅仅是被 @Configuration 修饰的类。
			else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
				// 添加到配置类集合中
				configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
			}
		}

		// Return immediately if no @Configuration classes were found
		// 如果没有找到配置类,则直接返回,不需要下面的解析
		if (configCandidates.isEmpty()) {
			return;
		}

		// Sort by previously determined @Order value, if applicable
		// 按照@Order 注解进行排序(如果使用了 @Order 注解的话)
		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
		// 判断如果是registry是SingletonBeanRegistry类型,则从中获取beanName生成器(BeanNameGenerator)。
		// 实际上这里是register类型是DefaultListableBeanFactory。是SingletonBeanRegistry的子类
		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;
				}
			}
		}
		// 如果环境变量为空则指定一个标准环境,这里是StandardServletEnvironment类型,在前面的启动篇我们可以知道。
		if (this.environment == null) {
			this.environment = new StandardEnvironment();
		}

		// Parse each @Configuration class
		// 下面开始解析每一个配置类
		// 准备配置类的解析类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..while 循环解析。因为一个配置类可能引入另一个配置类,需要循环解析,直至没有其他需要解析的类。
		do {
			// 2. 开始解析。后面详细分析
			parser.parse(candidates);
			// 3. 这里的校验规则是如果是被@Configuration修饰且proxyBeanMethods属性为true,则类不能为final。如果@Bean修饰的方法,则必须是可覆盖的.
			// 因为@Configuration(proxyBeanMethods = true) 是需要cglib代理的,所以不能为终态, @Bean所修饰的方法也有一套约束规则,下面详细讲
			// 是否需要代理是根据 类或方法上的 @Scope 注解指定的,默认都是不代理
			parser.validate();
			// configClasses保存这次解析出的配置类。此时这些ConfigurationClass中保存了解析出来的各种属性值,等待最后构建BeanDefinition
			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());
			}
			// 4. 注册bean
			this.reader.loadBeanDefinitions(configClasses);
			alreadyParsed.addAll(configClasses);

			candidates.clear();
			// if条件如果成立,说明有新的bean注册了,则需要解析新的bean
			if (registry.getBeanDefinitionCount() > candidateNames.length) {
				// 获取新的beanName
				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)) {
						// 过滤出未解析的bean检测是否是未解析过的配置类
						BeanDefinition bd = registry.getBeanDefinition(candidateName);
						if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
								!alreadyParsedClasses.contains(bd.getBeanClassName())) {
							// 如果是未解析的配置类,则保存到candidates中
							candidates.add(new BeanDefinitionHolder(bd, candidateName));
						}
					}
				}
				candidateNames = newCandidateNames;
			}
		}
		// 如果 candidates 不为空,则说明有未被解析的配置类,循环解析。
		while (!candidates.isEmpty());

		// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
		// 到这里已经把配置类解析完毕了。
		// 将ImportRegistry  注册为 bean,以支持ImportAware @Configuration 类
		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();
		}
	}

这里简单总结一下流程;

  1. 获取已经注册的Bean, 并筛选出配置类,按照@Order进行排序,得到配置类集合configCandidates
  2. 调用parser.parse(candidates);对配置类进行解析
  3. 调用this.reader.loadBeanDefinitions(configClasses);进行配置类的注册
  4. 检验registry.getBeanDefinitionCount() > candidateNames.length是否成立。这里由于第三步会将新解析出来的bean进行注册,如果这里成立,则说明有新的配置类完成了注册,获取到新注册的配置类candidateNames。循环从第二步重新解析,直到没有新注入的配置类。

上面解释的可能比较乱,因为我们下面详细去分析几个方法。

1.1 校验是否是配置类 - checkConfigurationClassCandidate()

ConfigurationClassUtils#checkConfigurationClassCandidate()

processConfigBeanDefinitions方法中。判断一个类是否是配置类就是通过checkConfigurationClassCandidate方法来判断的,那么我们需要看看这个方法中是怎么实现的。

在这个方法里,关键的部分是 给BeanDefinition设置了CONFIGURATION_CLASS_ATTRIBUTE为 full 或者 lite 设置这两个属性标识,如果一个类满足full或 lite的条件,则会被认为是配置类。需要注意的是,本文所说的配置类即使满足 full 或 lite 条件的类,而不仅仅是被@Configuration修饰的类

首先需要注意的是,在checkConfigurationClassCandidate()方法中,配置类的类型分为两种,Full 和 Lite,即完整的配置类和精简的配置类。

full 和 lite 设置的规则如下:

  • Full : 即类被 @Configuration 注解修饰 && proxyBeanMethods属性为true (默认为 true)
  • Lite : 被 @Component、@ComponentScan、@Import、@ImportResource 修饰的类 或者 类中有被@Bean修饰的方法。

Full 配置类就是我们常规使用的配置类

Lite 配置类就是一些需要其他操作引入一些bean 的类

下面我们来看具体代码:
ConfigurationClassUtils#checkConfigurationClassCandidate()

public static boolean checkConfigurationClassCandidate(BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
		// 获取className
		String className = beanDef.getBeanClassName();
		//如果beanDef名字为空,或者beanDef中工厂方法名字factoryMethodName不为空,则直接返回false
		if (className == null || beanDef.getFactoryMethodName() != null) {
			return false;
		}

		// 解析关于当前被解析类的 注解元数据
		AnnotationMetadata metadata;
		// 如果当前BeanDefinition是AnnotatedBeanDefinition(相较于一般的BeanDefinition,他多了一些注解信息的解析)类型。直接获取注解元数据即可
		if (beanDef instanceof AnnotatedBeanDefinition &&
				className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {
			// Can reuse the pre-parsed metadata from the given BeanDefinition...
			//获取beanDef注解元数据
			metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();
		}
		else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) {
			// Check already loaded Class if present...
			// since we possibly can't even load the class file for this Class.
			/**
			 * 	排除我们启动时注册的几个spring内部类(BeanFactoryPostProcessor、BeanPostProcessor、AopInfrastructureBean、EventListenerFactory),这几个内部类均为下面几个接口的实现或者扩展
			 * 	第一次检查配置类会排除spring内部类,之后我们自定义的符合这几个接口的类不会进入逻辑,一般是AnnotatedBeanDefinition的实现
			 * 	所有不会被排除
			 */
			Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();
			// 获取注解元数据
			metadata = new StandardAnnotationMetadata(beanClass, true);
		}
		else {
			// 按照默认规则解析
			try {
				MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className);
				metadata = metadataReader.getAnnotationMetadata();
			}
			catch (IOException ex) {
				if (logger.isDebugEnabled()) {
					logger.debug("Could not find class file for introspecting configuration annotations: " + className, ex);
				}
				return false;
			}
		}

		/**
		 * 该版本代码的和其他版本代码有点不同,我这边写出来了
		 * // 获取Configuration注解信息
		 * Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
		 */

		/**
		 * 	// 1、如果该beanDef存在@Configuration,并且@Configuration中proxyBeanMethods为true,则设置为CONFIGURATION_CLASS_FULL:full,即全注解
		 * 	// 2、proxyBeanMethods默认为true,即对于全注解配置类中的@Bean方法生成bean时会通过代理子类也即cglib来生成bean,而不是直接调用@Bean方法,主要时在子类中首先判断是否已经生成了该bean,防止生成多个bean
		 * 	if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
		 * 		beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
		 *  }
		 */
		if (isFullConfigurationCandidate(metadata)) {
			// 设置 CONFIGURATION_CLASS_ATTRIBUTE 为 full
			beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
		}
		/**
		 * 执行这一步存在以下几种情况
		 *  1 config != null但是该配置类不存在@Bean修饰的方法
		 *  2 config == null 但是符合isConfigurationCandidate条件如下
		 *  	2.1 不是接口
		 *  	2.2 被下面几个注解修饰
		 *  		candidateIndicators.add(Component.class.getName());
		 * 		    candidateIndicators.add(ComponentScan.class.getName());
		 * 		    candidateIndicators.add(Import.class.getName());
		 * 		    candidateIndicators.add(ImportResource.class.getName());
		 * 		 2.3 存在@Bean修饰的方法
		 *   符合2.1且满足2.2 其中一个或者2.3则该类是设置为CONFIGURATION_CLASS_LITE:lite即使半注解配置类
		 *
		 */
		else if (isLiteConfigurationCandidate(metadata)) {
			// 设置 CONFIGURATION_CLASS_ATTRIBUTE 为 lite
			beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
		}
		else {
			return false;
		}

		// It's a full or lite configuration candidate... Let's determine the order value, if any.
		Integer order = getOrder(metadata);
		// 如果存在order则可以设置该属性,以后可以进行排序设定执行顺序
		if (order != null) {
			beanDef.setAttribute(ORDER_ATTRIBUTE, order);
		}

		return true;
	}

主要是检测有没有对应的注解@Configurable@Component@ComponentScan@Import@ImportResource@Bean标注的方法,并根据相应的注解和条件设置属性为full:全注解和lite:半注解。

1.1.1 是否是半注解 - isLiteConfigurationCandidate()

ConfigurationClassUtils#isLiteConfigurationCandidate()

在上面的代码中,我们看到判断是否是 Lite 的关键方法是isLiteConfigurationCandidate()。其代码如下:

public static boolean isLiteConfigurationCandidate(AnnotationMetadata metadata) {
		// Do not consider an interface or an annotation...
		// 不能是接口
		if (metadata.isInterface()) {
			return false;
		}

		// Any of the typical annotations found?
		// 被 candidateIndicators 中的注解修饰。其中 candidateIndicators(@Component、@ComponentScan、@Import、@ImportResource) 注解在静态代码块中加载了
		for (String indicator : candidateIndicators) {
			if (metadata.isAnnotated(indicator)) {
				return true;
			}
		}

		// Finally, let's look for @Bean methods...
		try {
			// 类中包含被 @Bean 注解修饰的方法
			return metadata.hasAnnotatedMethods(Bean.class.getName());
		}
		catch (Throwable ex) {
			if (logger.isDebugEnabled()) {
				logger.debug("Failed to introspect @Bean methods on class [" + metadata.getClassName() + "]: " + ex);
			}
			return false;
		}
	}

1.2 开始解析 - parser.parse(candidates);

ConfigurationClassParser#parse(Set configCandidates)

上面解析了如何判断一个类是否是配置类。也完成了配置类的筛选。那么开始进行配置类的解析,在 processConfigBeanDefinitions()方法中,对配置类的解析也只是一句话完成:

	parser.parse(candidates);

parser.parse(candidates); 的作用是:

  1. 将所有的配置类保存到ConfigurationClassParser.configurationClasses集合中
	private final Map<ConfigurationClass, ConfigurationClass> configurationClasses = new LinkedHashMap<>();
  1. 解析注解并赋值给每个ConfigurationClass对应的属性。如解析@Import注解,并通过如下语句将结果保存到ConfigurationClass.importBeanDefinitionRegistrars集合中。
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());

同样的还有 将@ImportResource注解保存到ConfigurationClass.importedResources中,将@Bean修饰的方法和接口静态方法保存到ConfigurationClass.beanMethods中。
而在之后的this.reader.loadBeanDefinitions(configClasses);中才进行了这些属性的进一步处理

下面我们来具体看代码,其代码如下:

public void parse(Set<BeanDefinitionHolder> configCandidates) {
		this.deferredImportSelectors = new LinkedList<>();

		for (BeanDefinitionHolder holder : configCandidates) {
			BeanDefinition bd = holder.getBeanDefinition();
			try {
				// 针对不同类型的 BeanDefinition 做一些处理
				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);
			}
		}

		processDeferredImportSelectors();
	}

里面的 parse 方法殊途同归,最终都会调用 processConfigurationClass()方法,所以我们直接进入该方法:

ConfigurationClassParser#processConfigurationClass(ConfigurationClass configClass)

protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
		// 判断是否应该跳过当前类的解析。这里面解析了 @Conditional 注解
		if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
			return;
		}
		// 判断是否已经解析过。configurationClasses 中保存着已经解析过的配置类。在下面解析过的类都会被保存到 configurationClasses 中
		// 这里应该是 注入的配置类优先级高于引入的配置类
		// 如果配置类被多次引入则合并属性
		ConfigurationClass existingClass = this.configurationClasses.get(configClass);
		if (existingClass != null) {
			// 一个类被重复解析,那么可能被重复引入了,可能是通过 @Import 注解或者嵌套在其他配置类中被引入。如果这两者都是通过这种方式被引入,那么则进行引入合并
			// 如果当前配置类和之前解析过的配置类都是引入的,则直接合并
			if (configClass.isImported()) {
				if (existingClass.isImported()) {
					existingClass.mergeImportedBy(configClass);
				}
				// Otherwise ignore new imported config class; existing non-imported class overrides it.
				// 否则,忽略新导入的配置类;现有的非导入类将覆盖它
				return;
			}
			else {
				// Explicit bean definition found, probably replacing an import.
				// Let's remove the old one and go with the new one.
				// 如果当前的配置类不是引入的,则移除之前的配置类,重新解析
				this.configurationClasses.remove(configClass);
				this.knownSuperclasses.values().removeIf(configClass::equals);
			}
		}

		// Recursively process the configuration class and its superclass hierarchy.
		SourceClass sourceClass = asSourceClass(configClass);
		do {
			sourceClass = doProcessConfigurationClass(configClass, sourceClass);
		}
		while (sourceClass != null);

		// 保存解析过的 配置类
		this.configurationClasses.put(configClass, configClass);
	}

这里需要注意的是配置类的重复引入优先级的问题 :
一般来说,Spring有一个自己的规则 :自身注入方式 优先于 引入方式。这里的引入方式指的被 @Import 或者其他配置类引入。当一个类被多次引入时,会使用自身注入的方式的bean 替代 被引入方式的bean。如果二者都是引入方式,则进行合并(在 ConfigurationClass 类中有一个importedBy 集合,将新引入的来源保存到 importedBy 中)

ConfigurationClass#mergeImportedBy(ConfigurationClass otherConfigClass)

public void mergeImportedBy(ConfigurationClass otherConfigClass) {
		this.importedBy.addAll(otherConfigClass.importedBy);
	}

看了这么久的源码,也知道了Spring的套路,方法名以do开头的才是真正做事的方法, 所以我们来看 doProcessConfigurationClass() 方法。

ConfigurationClassParser#doProcessConfigurationClass()

@Nullable
	protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
			throws IOException {

		// Recursively process any member (nested) classes first
		// 1. 处理 @Component 注解
		processMemberClasses(configClass, sourceClass);

		// Process any @PropertySource annotations
		// 2. 处理 @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.warn("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
						"]. Reason: Environment must implement ConfigurableEnvironment");
			}
		}

		// Process any @ComponentScan annotations
		// 3. 处理 @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) {
				// The config class is annotated with @ComponentScan -> perform the scan immediately
				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();
					}
					if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
						parse(bdCand.getBeanClassName(), holder.getBeanName());
					}
				}
			}
		}

		// Process any @Import annotations
		// 4. 处理 @Import 注解
		processImports(configClass, sourceClass, getImports(sourceClass), true);

		// Process any @ImportResource annotations
		// 5. 处理 @ImportResource 注解
		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);
			}
		}

		// Process individual @Bean methods
		// 6. 处理 @Bean修饰的方法
		Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
		for (MethodMetadata methodMetadata : beanMethods) {
			configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
		}

		// Process default methods on interfaces
		// 7. 处理其他默认接口方法
		processInterfaces(configClass, sourceClass);

		// Process superclass, if any
		// 处理父类,如果存在
		if (sourceClass.getMetadata().hasSuperClass()) {
			String superclass = sourceClass.getMetadata().getSuperClassName();
			if (superclass != null && !superclass.startsWith("java") &&
					!this.knownSuperclasses.containsKey(superclass)) {
				this.knownSuperclasses.put(superclass, configClass);
				// Superclass found, return its annotation metadata and recurse
				return sourceClass.getSuperClass();
			}
		}

		// No superclass -> processing is complete
		return null;
	}

doProcessConfigurationClass方法中的逻辑很清楚,因为他把大部分的逻辑直接封装成了方法。下面我们就来一个一个分析。

1.2.1 处理@Component注解 - processMemberClasses()

这里对@Component的处理其实是处理配置类的内部类,即如果当前类是被 @Component修饰,则需要判断其内部类是否需要解析。

processMemberClasses()方法的代码如下:
代码逻辑也很简单。即如果配置类中有内部类,则判断其内部类是否是配置类,如果是则递归去解析新发现的内部配置类。
ConfigurationClassParser#processMemberClasses()

private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
		// 获取内部类
		Collection<SourceClass> memberClasses = sourceClass.getMemberClasses();
		if (!memberClasses.isEmpty()) {
			// 如果有内部类,则遍历内部类,判断内部类是否是配置类,如果是,则添加到 candidates 集合中。
			List<SourceClass> candidates = new ArrayList<>(memberClasses.size());
			for (SourceClass memberClass : memberClasses) {
				// 这里判断的是是否是lite 类型的配置类
				if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) &&
						!memberClass.getMetadata().getClassName().equals(configClass.getMetadata().getClassName())) {
					candidates.add(memberClass);
				}
			}
			// 进行排序
			OrderComparator.sort(candidates);
			for (SourceClass candidate : candidates) {
				// importStack 用来缓存已经解析过的内部类,这里处理循环引入问题。
				if (this.importStack.contains(configClass)) {
					// 打印循环引用异常
					this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
				}
				else {
					// 解析前入栈,防止循环引入
					this.importStack.push(configClass);
					try {
						// 递归去解析新发现的配置类
						processConfigurationClass(candidate.asConfigClass(configClass));
					}
					finally {
						// 解析完毕出栈
						this.importStack.pop();
					}
				}
			}
		}
	}

注:

  1. 判断内部类是否是配置类,使用的方法是 ConfigurationClassUtils.isConfigurationCandidate,这里是检测内部类是否满足lite 的配置类规则,并未校验 full的规则。
  2. 代码中使用了this.importStack 来防止递归引入。避免了A引入B,B又引入A这种无限循环的情况。

1.2.2 处理 @PropertySource 注解

@PropertySource注解可以引入配置文件使用。在这里进行@PropertySource注解的解析,将引入的配置文件加载到环境变量中

	// 去重后遍历 PropertySource 注解所指向的属性。注意这里有两个注解@PropertySources 和 @PropertySource。
	for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
			sourceClass.getMetadata(), PropertySources.class,
			org.springframework.context.annotation.PropertySource.class)) {
		if (this.environment instanceof ConfigurableEnvironment) {
			// 解析PropertySource  注解
			processPropertySource(propertySource);
		}
		else {
			logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
					"]. Reason: Environment must implement ConfigurableEnvironment");
		}
	}

processPropertySource代码如下,在这里解析每一个@PropertySource注解属性 :
ConfigurationClassParser#processPropertySource()

private void processPropertySource(AnnotationAttributes propertySource) throws IOException {
		// 获取 @PropertySource 注解的各个属性
		String name = propertySource.getString("name");
		if (!StringUtils.hasLength(name)) {
			name = null;
		}
		String encoding = propertySource.getString("encoding");
		if (!StringUtils.hasLength(encoding)) {
			encoding = null;
		}
		// 获取指向的文件路径
		String[] locations = propertySource.getStringArray("value");
		Assert.isTrue(locations.length > 0, "At least one @PropertySource(value) location is required");
		boolean ignoreResourceNotFound = propertySource.getBoolean("ignoreResourceNotFound");

		Class<? extends PropertySourceFactory> factoryClass = propertySource.getClass("factory");
		PropertySourceFactory factory = (factoryClass == PropertySourceFactory.class ?
				DEFAULT_PROPERTY_SOURCE_FACTORY : BeanUtils.instantiateClass(factoryClass));
		// 遍历文件路径
		for (String location : locations) {
			try {
				// 根据路径获取到资源文件并保存到environment 中
				String resolvedLocation = this.environment.resolveRequiredPlaceholders(location);
				// 解决占位符,获取真正路径
				Resource resource = this.resourceLoader.getResource(resolvedLocation);
				//保存 PropertySource 到 environment 中
				addPropertySource(factory.createPropertySource(name, new EncodedResource(resource, encoding)));
			}
			catch (IllegalArgumentException | FileNotFoundException | UnknownHostException | SocketException ex) {
				// Placeholders not resolvable or resource not found when trying to open it
				if (ignoreResourceNotFound) {
					if (logger.isInfoEnabled()) {
						logger.info("Properties location [" + location + "] not resolvable: " + ex.getMessage());
					}
				}
				else {
					throw ex;
				}
			}
		}
	}

1.2.3 处理 @ComponentScan、@ComponentScans 注解

@componentScans指定自动扫描的路径。

		// 这里会将 @ComponentScans 中的多个 @ComponentScan 也解析出来封装成一个个AnnotationAttributes对象
		Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
				sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
		// 如果当前配置类被 @componentScans 或 @componentScan 注解修饰 && 不应跳过
		if (!componentScans.isEmpty() &&
				!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
				// 遍历 @ComponentScans、 @ComponentScan
			for (AnnotationAttributes componentScan : componentScans) {
				// The config class is annotated with @ComponentScan -> perform the scan immediately
				// 直接执行扫描,根据指定路径扫描出来bean。
				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
				// 遍历扫描出来的bean
				for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
				// 获取原始的bean的定义
					BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
					if (bdCand == null) {
						bdCand = holder.getBeanDefinition();
					}
					// 检测如果是配置类,则递归调用 parse 解析。
					if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
						parse(bdCand.getBeanClassName(), holder.getBeanName());
					}
				}
			}
		}

这里需要注意 :

  1. this.componentScanParser.parse()方法完成了指定路径下的bean的扫描,这里不再具体分析。

  2. 这里校验是否是配置类调用的是checkConfigurationClassCandidate方法,即校验了 full或lite的规则,和 处理 @Component中的内部类的规则并不相同。

  3. 没错,又是递归,如果扫描到的bean中发现了新的配置类,则递归去解析。

  4. 之前的我们提过,Springboot 在启动过程中将 启动类注册到了容器中,那么在这里进行递归遍历的时候就会通过启动类指定的默认路径来进行遍历, 完成了Springboot的启动注册。

1.2.4 处理 @Import、ImportSelector、ImportBeanDefinitionRegistrar

processImports(configClass, sourceClass, getImports(sourceClass), filter, true); 该方法处理的包括@Import、ImportSelector、 ImportBeanDefinitionRegistrar。这三个注解或接口都可以完成Bean的引入功能。

@Import:可以通过 @Import(XXX.class)的方式,将指定的类注册到容器中
ImportSelector : Spring会将 ImportSelector#selectImports())方法返回的内容通过反射加载到容器中
ImportBeanDefinitionRegistrar : 可以通过registerBeanDefinitions()方法声明BeanDefinition 并自己注册到Spring容器中 比如 : MyBatis 中的 AutoConfiguredMapperScannerRegistrar@Mapper修饰类的注册过程
需要注意的是,这里解析的ImportSelector、ImportBeanDefinitionRegistrar都是通过 @Import注解引入的。如果不是通过@Import引入(比如直接通过@ComponentImportSelector、ImportBeanDefinitionRegistrar 注入)的类则不会被解析。

注意 getImports(sourceClass)方法的作用是解析@Import注解
我们直接来看 processImports 方法,注释都比较清楚 :

ConfigurationClassParser#processImports()

private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
			Collection<SourceClass> importCandidates, boolean checkForCircularImports) {
		// importCandidates 是通过getImports() 方法解析 @Import 注解而来, 如果为空则说明没有需要引入的直接返回
		if (importCandidates.isEmpty()) {
			return;
		}
		// 检测是否是循环引用。
		if (checkForCircularImports && isChainedImportOnStack(configClass)) {
			this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
		}
		else {
			// 解析前先入栈,防止循环引用
			this.importStack.push(configClass);
			try {
				for (SourceClass candidate : importCandidates) {
					// 判断是否是ImportSelector类型。ImportSelector 则需要调用selectImports 方法来获取需要注入的类。
					if (candidate.isAssignable(ImportSelector.class)) {
						// Candidate class is an ImportSelector -> delegate to it to determine imports
						Class<?> candidateClass = candidate.loadClass();
						ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
						ParserStrategyUtils.invokeAwareMethods(
								selector, this.environment, this.resourceLoader, this.registry);
						if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) {
							this.deferredImportSelectors.add(
									new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));
						}
						else {
							// 调用 selectImports 方法获取需要引入的类,并递归再次处理。
							String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
							Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
							// 递归解析
							processImports(configClass, currentSourceClass, importSourceClasses, false);
						}
					}
					// 如果是 ImportBeanDefinitionRegistrar 类型,则委托它注册其他bean定义
					else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
						// Candidate class is an ImportBeanDefinitionRegistrar ->
						// delegate to it to register additional bean definitions
						Class<?> candidateClass = candidate.loadClass();
						ImportBeanDefinitionRegistrar registrar =
								BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
						ParserStrategyUtils.invokeAwareMethods(
								registrar, this.environment, this.resourceLoader, this.registry);
						configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
					}
					else {
						// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
						// process it as an @Configuration class
						this.importStack.registerImport(
								currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
						// 否则递归处理需要引入的类。
						processConfigurationClass(candidate.asConfigClass(configClass));
					}
				}
			}
			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();
			}
		}
	}

1.2.5 处理 @ImportResource 注解

@ImportResource就显得很简单了,直接保存到configClass 中

	// 5. 处理 @ImportResource 注解
		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);
			}
		}

1.2.6 处理 @Bean修饰的方法

@Bean也很简单了,直接保存到 configClass 的中

	// Process individual @Bean methods
		Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
		for (MethodMetadata methodMetadata : beanMethods) {
			configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
		}

1.2.7 处理接口默认方法

这里是 检测 配置类实现的接口中的默认方法是否被@Bean修饰,如果被修饰则也需要保存到 configClass

private void processInterfaces(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
		for (SourceClass ifc : sourceClass.getInterfaces()) {
			Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(ifc);
			for (MethodMetadata methodMetadata : beanMethods) {
				if (!methodMetadata.isAbstract()) {
					// A default method or other concrete method on a Java 8+ interface...
					configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
				}
			}
			processInterfaces(configClass, ifc);
		}
	}

1.2.8 处理父类

如果存在父类,则将父类返回,对父类进行解析。

		// Process superclass, if any
		if (sourceClass.getMetadata().hasSuperClass()) {
			String superclass = sourceClass.getMetadata().getSuperClassName();
			if (superclass != null && !superclass.startsWith("java") &&
					!this.knownSuperclasses.containsKey(superclass)) {
				this.knownSuperclasses.put(superclass, configClass);
				// Superclass found, return its annotation metadata and recurse
				return sourceClass.getSuperClass();
			}
		}

这里这么处理是解析到最上层的父类。这里理一下调用顺序:parse -> processConfigurationClass -> doProcessConfigurationClass 。而 doProcessConfigurationClass有如下一个循环,只有sourceClass = null才会跳出循环。当configClass没有满足上面判断条件的父类时,才会返回null

	SourceClass sourceClass = asSourceClass(configClass, filter);
		do {
			sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
		}
		while (sourceClass != null);
	this.configurationClasses.put(configClass, configClass);

1.3 parser.validate();

到了 这一步,是对解析出来的配置类进行进一步的校验,确保没有问题

这里我们看看其代码如下:
ConfigurationClassParser#validate()

public void validate() {
		for (ConfigurationClass configClass : this.configurationClasses.keySet()) {
			configClass.validate(this.problemReporter);
		}
	}

这里可以看到是调用每个 ConfigurationClass 类的 validate 方法进行校验,我们进去看看ConfigurationClass#validate的代码 :

	public void validate(ProblemReporter problemReporter) {
		// A configuration class may not be final (CGLIB limitation) unless it declares proxyBeanMethods=false
		// 获取 @Configuration 注解的属性信心
		Map<String, Object> attributes = this.metadata.getAnnotationAttributes(Configuration.class.getName());
		// 如果 @Configuration 存在(attributes != null)  && attributes.get("proxyBeanMethods") == true 才进行进一步的校验
		if (attributes != null && (Boolean) attributes.get("proxyBeanMethods")) {
			// 如果配置类 是  final 修饰,即终态类,则是错误,因为无法动态代理
			if (this.metadata.isFinal()) {
				problemReporter.error(new FinalConfigurationProblem());
			}
			// 对配置类中的 @Bean 注解修饰的方法进行校验
			for (BeanMethod beanMethod : this.beanMethods) {
				beanMethod.validate(problemReporter);
			}
		}
	}

这里我们再来看看@Bean方法的校验 BeanMethod#validate如下:

	@Override
	public void validate(ProblemReporter problemReporter) {
		// 如果是静态方法没有约束规则,直接返回。
		if (getMetadata().isStatic()) {
			// static @Bean methods have no constraints to validate -> return immediately
			return;
		}
		// 校验该方法所属的类是否被 @Configuration 修饰。
		if (this.configurationClass.getMetadata().isAnnotated(Configuration.class.getName())) {
			// 判断是否可重写。cglib代理需要方法可重写。不可重写则错误
			if (!getMetadata().isOverridable()) {
				// instance @Bean methods within @Configuration classes must be overridable to accommodate CGLIB
				problemReporter.error(new NonOverridableMethodError());
			}
		}
	}

1.4 this.reader.loadBeanDefinitions(configClasses);

上面也说了,在parser.parse(candidates); 方法中,将各种注解的属性值都解析了出来,并保存到了 configClass的各种属性中。而在 this.reader.loadBeanDefinitions(configClasses); 中才真正处理了这些属性。所以我们接下来看看loadBeanDefinitions 的处理流程。

loadBeanDefinitions遍历了每一个ConfigurationClass,通过loadBeanDefinitionsForConfigurationClass()方法处理。

ConfigurationClassBeanDefinitionReader#loadBeanDefinitions()

	public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
		TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
		for (ConfigurationClass configClass : configurationModel) {
			loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
		}
	}

所以我们来看看loadBeanDefinitionsForConfigurationClass的实现。可很清楚的看到,每个部分的解析都封装到了不同的方法中。
loadBeanDefinitions() >>> ConfigurationClassBeanDefinitionReader#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;
		}
		// 1. 如果配置是被引入的(被 @Import 或者其他配置类内部引入)
		if (configClass.isImported()) {
			registerBeanDefinitionForImportedConfigurationClass(configClass);
		}
		// 2. 遍历配置类中的所有 BeanMethod方法
		for (BeanMethod beanMethod : configClass.getBeanMethods()) {
			loadBeanDefinitionsForBeanMethod(beanMethod);
		}
		// 3. 加载 通过 @ImportResource 的 获取的bean
		loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
		// 4. 加载 通过 @Import 的 获取的bean
		loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
	}

下面 我们来详细看看每个方法。

1.4.1 registerBeanDefinitionForImportedConfigurationClass

这一步的工作很简单,就是将引入的配置类注册为 BeanDefinition。

private void registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass) {
		AnnotationMetadata metadata = configClass.getMetadata();
		AnnotatedGenericBeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata);

		ScopeMetadata scopeMetadata = scopeMetadataResolver.resolveScopeMetadata(configBeanDef);
		configBeanDef.setScope(scopeMetadata.getScopeName());
		String configBeanName = this.importBeanNameGenerator.generateBeanName(configBeanDef, this.registry);
		AnnotationConfigUtils.processCommonDefinitionAnnotations(configBeanDef, metadata);

		BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(configBeanDef, configBeanName);
		// 创建代理,根据 scopeMetadata 的代理模式。默认不创建代理。
		definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
		// 注册了BeanBeanDefinition 。这里将BeanDefinition保存到了 DefaultListableBeanFactory#beanDefinitionMap 中
		this.registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition());
		configClass.setBeanName(configBeanName);

		if (logger.isDebugEnabled()) {
			logger.debug("Registered bean definition for imported class '" + configBeanName + "'");
		}
	}

这里需要注意的是 AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); 根据scopeMetadata的代理模式创建了代理。代理模式有四种,分别为

  • DEFAULT : 默认模式。默认等同于NO
  • NO : 不使用代理
  • INTERFACES : Jdk 动态代理
  • TARGET_CLASS : Cglib代理

applyScopedProxyMode方法中 通过获取ScopeMetadata.getScopedProxyMode()来判断使用什么代理方式。而ScopeMetadata的代理方式 是在创建scopeMetadata的过程中,获取类上面的@ScopeproxyMode属性来指定的。

ScopeMetadata scopeMetadata =  scopeMetadataResolver.resolveScopeMetadata(configBeanDef);

resolveScopeMetadata方法如下
ScopeMetadataResolver#resolveScopeMetadata()

	ScopeMetadata resolveScopeMetadata(BeanDefinition definition);

AnnotationScopeMetadataResolver#resolveScopeMetadata()

@Override
	public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) {
		ScopeMetadata metadata = new ScopeMetadata();
		if (definition instanceof AnnotatedBeanDefinition) {
			AnnotatedBeanDefinition annDef = (AnnotatedBeanDefinition) definition;
			// 获取 @Scope 注解
			AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(
					annDef.getMetadata(), this.scopeAnnotationType);
			if (attributes != null) {
				metadata.setScopeName(attributes.getString("value"));
				// 获取 @Scope 的proxyMode属性
				ScopedProxyMode proxyMode = attributes.getEnum("proxyMode");
				if (proxyMode == ScopedProxyMode.DEFAULT) {
					proxyMode = this.defaultProxyMode;
				}
				// 设置 scopedProxyMode 属性,后面根据此属性判断使用什么代理方式
				metadata.setScopedProxyMode(proxyMode);
			}
		}
		return metadata;
	}

1.4.2 loadBeanDefinitionsForBeanMethod

具体代码如下,基本上就是解析各种注解,创建对应的 BeanDefinition 并注册。

	private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
		ConfigurationClass configClass = beanMethod.getConfigurationClass();
		MethodMetadata metadata = beanMethod.getMetadata();
		String methodName = metadata.getMethodName();

		// Do we need to mark the bean as skipped by its condition?
		// 是否应该跳过
		if (this.conditionEvaluator.shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN)) {
			configClass.skippedBeanMethods.add(methodName);
			return;
		}
		if (configClass.skippedBeanMethods.contains(methodName)) {
			return;
		}
		// 获取被 @Bean修饰的方法
		AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class);
		Assert.state(bean != null, "No @Bean annotation attributes");

		// Consider name and any aliases
		// 获取别名
		List<String> names = new ArrayList<>(Arrays.asList(bean.getStringArray("name")));
		String beanName = (!names.isEmpty() ? names.remove(0) : methodName);

		// Register aliases even when overridden
		// 注册别名
		for (String alias : names) {
			this.registry.registerAlias(beanName, alias);
		}

		// Has this effectively been overridden before (e.g. via XML)?
		// 判断是否已经被定义过
		if (isOverriddenByExistingDefinition(beanMethod, beanName)) {
			if (beanName.equals(beanMethod.getConfigurationClass().getBeanName())) {
				throw new BeanDefinitionStoreException(beanMethod.getConfigurationClass().getResource().getDescription(),
						beanName, "Bean name derived from @Bean method '" + beanMethod.getMetadata().getMethodName() +
						"' clashes with bean name for containing configuration class; please make those names unique!");
			}
			return;
		}
		// 定义配置类的  BeanDefinition
		ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);
		beanDef.setResource(configClass.getResource());
		beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));
		// 处理静态 @Bean 方法和 非静态 @Bean 方法
		if (metadata.isStatic()) {
			// static @Bean method
			if (configClass.getMetadata() instanceof StandardAnnotationMetadata) {
				beanDef.setBeanClass(((StandardAnnotationMetadata) configClass.getMetadata()).getIntrospectedClass());
			}
			else {
				beanDef.setBeanClassName(configClass.getMetadata().getClassName());
			}
			// 设置唯一工厂方法名称
			beanDef.setUniqueFactoryMethodName(methodName);
		}
		else {
			// instance @Bean method
			// 指定要使用的工厂bean(如果有)。这是用于调用指定工厂方法的bean的名称
			beanDef.setFactoryBeanName(configClass.getBeanName());
			// 设置唯一工厂方法名称,内部调用了 setFactoryMethodName(name); 保存 FactoryMethodName
			beanDef.setUniqueFactoryMethodName(methodName);
		}

		if (metadata instanceof StandardMethodMetadata) {
			beanDef.setResolvedFactoryMethod(((StandardMethodMetadata) metadata).getIntrospectedMethod());
		}
		// 设置构造模式 构造注入
		beanDef.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
		// 设置跳过属性检查
		beanDef.setAttribute(org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor.
				SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);
		// 处理通用的注解: @Lazy、@Primary、@DependsOn、@Role、@Description。设置到 BeanDefinition 中
		AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata);
		// 获取注解的其他属性并设置到 BeanDefinition
		Autowire autowire = bean.getEnum("autowire");
		if (autowire.isAutowire()) {
			beanDef.setAutowireMode(autowire.value());
		}

		boolean autowireCandidate = bean.getBoolean("autowireCandidate");
		if (!autowireCandidate) {
			beanDef.setAutowireCandidate(false);
		}

		String initMethodName = bean.getString("initMethod");
		if (StringUtils.hasText(initMethodName)) {
			beanDef.setInitMethodName(initMethodName);
		}

		String destroyMethodName = bean.getString("destroyMethod");
		beanDef.setDestroyMethodName(destroyMethodName);

		// Consider scoping
		ScopedProxyMode proxyMode = ScopedProxyMode.NO;
		// 处理方法上的 @Scope 注解
		AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(metadata, Scope.class);
		if (attributes != null) {
			beanDef.setScope(attributes.getString("value"));
			proxyMode = attributes.getEnum("proxyMode");
			if (proxyMode == ScopedProxyMode.DEFAULT) {
				proxyMode = ScopedProxyMode.NO;
			}
		}

		// Replace the original bean definition with the target one, if necessary
		// 如果有必要(代理模式不同),替换掉旧的BeanDefinition
		BeanDefinition beanDefToRegister = beanDef;
		if (proxyMode != ScopedProxyMode.NO) {
			BeanDefinitionHolder proxyDef = ScopedProxyCreator.createScopedProxy(
					new BeanDefinitionHolder(beanDef, beanName), this.registry,
					proxyMode == ScopedProxyMode.TARGET_CLASS);
			beanDefToRegister = new ConfigurationClassBeanDefinition(
					(RootBeanDefinition) proxyDef.getBeanDefinition(), configClass, metadata);
		}

		if (logger.isTraceEnabled()) {
			logger.trace(String.format("Registering bean definition for @Bean method %s.%s()",
					configClass.getMetadata().getClassName(), beanName));
		}
		// 注册BeanDefinition
		this.registry.registerBeanDefinition(beanName, beanDefToRegister);
	}

这里特意提一下下面几句的功能

// 设置引入该bean 的配置类的类名
beanDef.setFactoryBeanName(configClass.getBeanName());
// 设置 引入bean 的类名
beanDef.setBeanClassName(configClass.getMetadata().getClassName());
// 设置在配置类中引入该bean 的方法名
beanDef.setUniqueFactoryMethodName(methodName);

这里会为 @Bean修饰的方法创建出一个ConfigurationClassBeanDefinition注册到Spring容器中,ConfigurationClassBeanDefinition是特指用于表示从配置类(而不是其他任何配置源)创建了Bean定义。在需要确定是否在外部创建bean定义的bean覆盖情况下使用。在后面的Bean实例化过程中,会有多次使用。比如在 AbstractAutowireCapableBeanFactory#resolveBeforeInstantiation()

		// 在 determineTargetType 方法中根据  factoryMethodName 是否为空,判断bean注入方式,来获取注入的 Class类型
		Class<?> targetType = determineTargetType(beanName, mbd)

以及会在AbstractAutowireCapableBeanFactory#createBeanInstance()方法中有如下两句。
@Bean的修饰的方法会调用instantiateUsingFactoryMethod()方法,通过反射调用方法,并将反射结果注入到Spring容器中,完成@Bean注解的功能。

1.4.3 loadBeanDefinitionsFromImportedResources

loadBeanDefinitionsFromImportedResources从导入的资源加载Bean定义。即通过解析 @ImportResource注解引入的资源文件,获取到BeanDefinition并注册。

private void loadBeanDefinitionsFromImportedResources(
			Map<String, Class<? extends BeanDefinitionReader>> importedResources) {

		Map<Class<?>, BeanDefinitionReader> readerInstanceCache = new HashMap<>();
		// 遍历引入的资源文件
		importedResources.forEach((resource, readerClass) -> {
			// Default reader selection necessary?
			if (BeanDefinitionReader.class == readerClass) {
				// 处理 .groovy 类型文件
				if (StringUtils.endsWithIgnoreCase(resource, ".groovy")) {
					// When clearly asking for Groovy, that's what they'll get...
					readerClass = GroovyBeanDefinitionReader.class;
				}
				else {
					// Primarily ".xml" files but for any other extension as well
					// 这里使用 XmlBeanDefinitionReader 类型来解析
					readerClass = XmlBeanDefinitionReader.class;
				}
			}
			// 从缓冲中获取
			BeanDefinitionReader reader = readerInstanceCache.get(readerClass);
			// 如果缓存中没有,则创建一个 reader 用于 resource 的解析。
			if (reader == null) {
				try {
					// Instantiate the specified BeanDefinitionReader
					reader = readerClass.getConstructor(BeanDefinitionRegistry.class).newInstance(this.registry);
					// Delegate the current ResourceLoader to it if possible
					if (reader instanceof AbstractBeanDefinitionReader) {
						AbstractBeanDefinitionReader abdr = ((AbstractBeanDefinitionReader) reader);
						abdr.setResourceLoader(this.resourceLoader);
						abdr.setEnvironment(this.environment);
					}
					readerInstanceCache.put(readerClass, reader);
				}
				catch (Throwable ex) {
					throw new IllegalStateException(
							"Could not instantiate BeanDefinitionReader class [" + readerClass.getName() + "]");
				}
			}

			// TODO SPR-6310: qualify relative path locations as done in AbstractContextLoader.modifyLocations
			// 解析resource资源中的内容
			reader.loadBeanDefinitions(resource);
		});
	}

1.4.4 loadBeanDefinitionsFromRegistrars

loadBeanDefinitionsFromRegistrars方法注册了了@Import 注解引入的内容。这里很简单,将@Import引入的内容注入到容器中。

	private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) {
		registrars.forEach((registrar, metadata) ->
				registrar.registerBeanDefinitions(metadata, this.registry, this.importBeanNameGenerator));
	}

四、总结

从目前我看到的来说(虽然也没看过几个),有两个后处理器非常重要:

  • ConfigurationClassPostProcessor : 即本文解析的这个后处理器。虽然仅仅是上篇,但是其作用已经非常清楚了。ConfigurationClassPostProcessor 解析配置类(这里的配置类不仅仅局限于@Configuration 注解,还包括 @Import@ImportResource 等注解),将解析到的需要注入到Spring容器中的bean的BeanDefinition保存起来。在后面的bean 初始化都需要BeanDefinition

  • AutowiredAnnotationBeanPostProcessor : 之前解析过。完成了Bean所依赖的属性的注入。 解析bean中的 需要自动注入的bean @Autowired@Inject @Value注解。
    简单来说ConfigurationClassPostProcessor完成了 Bean的扫描与解析, AutowiredAnnotationBeanPostProcessor完成了Bean 属性的注入

本文只分析了ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry()方法,对于ConfigurationClassPostProcessor#postProcessBeanFactory方法的分析则放在后篇,这里简单的说明ConfigurationClassPostProcessor#postProcessBeanFactory()方法通过cglib动态代理,完成了 对@Bean修饰方法的代理,以确保其正确语义。

以上:内容部分参考
《Spring源码深度解析》
如有侵扰,联系删除。 内容仅用于自我记录学习使用。如有错误,欢迎指正

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/27650.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【学习日志】2022.11.18 Technical Artist Training Tutorial----Unlit Shader Of Unity

着色器 - Unity 手册 (unity3d.com)https://docs.unity3d.com/cn/current/Manual/Shaders.html 常用板块&#xff08;Properties&#xff09; _MainTex("MainTex",2D)"black"{} _Float("Float",Float)0.0 _Range("Range",Range(0.0,1…

【测试沉思录】14. 性能测试中的系统资源分析之一:CPU

作者&#xff1a;马海琴 编辑&#xff1a;毕小烦 在日常的性能测试中&#xff0c;我们除了关注应用本身的性能&#xff0c;比如服务的响应时间、TPS 等&#xff0c;也需要关注服务器本身的资源使用情况&#xff0c;比如 CPU、内存、磁盘、网络等。当然&#xff0c;不光要分析服…

Java中string、int、char之间互相转换

String转int &#xff08;1&#xff09;Integer.parseInt(String) 方法 支持“负号”&#xff01; String str "123"; int num Integer.parseInt(str); 如果这个字符串中间有字母会报错&#xff01; &#xff08;2&#xff09;Integer.valueOf(String) 方法 …

白炽灯护眼还是LED护眼?2022年被央视315表扬的护眼灯

根据各方面对比下来&#xff0c;还是LED灯更护眼的&#xff0c;听我分析一下。 白炽灯是最早的出现的灯具&#xff0c;是由灯丝通电加热到白炽状态的&#xff0c;热辐射比较严重&#xff0c;灯光泛黄&#xff0c;并且白炽灯的光电转换效率低&#xff0c;费电&#xff0c;寿命太…

排序算法图解(六):归并排序

文章目录1 归并排序简介2 思路简介及图解3 代码实现写在最后1 归并排序简介 归并排序是建立在归并操作上的一种有效&#xff0c;稳定的排序算法&#xff0c;该算法是采用分治法&#xff08;Divide and Conquer&#xff09;的一个非常典型的应用。将已有序的子序列合并&#xf…

stm32cubemx hal学习记录:FreeRTOS软件定时器

一、配置过程 1、配置RCC、USART1、时钟84M 2、配置SYS&#xff0c;将Timebase Source修改为除滴答定时器外的其他定时器。 3、初始化LED的两个引脚、两个按键引脚 4、开启FreeRTOS&#xff0c;v1与v2版本不同&#xff0c;一般选用v1即可 5、打开定时器选项 6、创建两个定…

健身中心健身管理系统的设计与实现(源码+数据脚本+论文+技术文档)

项目描述 临近学期结束&#xff0c;还是毕业设计&#xff0c;你还在做java程序网络编程&#xff0c;期末作业&#xff0c;老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。这里根据疫情当下&#xff0c;你想解决的问…

Mysql进阶学习(三)排序查询与常见函数

Mysql进阶学习&#xff08;三&#xff09;排序查询与常见函数一、进阶3&#xff1a;排序查询1、语法&#xff1a;2、特点&#xff1a;3、排序方式3.1、按单个字段排序3.2、添加筛选条件再排序案例&#xff1a;查询部门编号>90的员工信息&#xff0c;并按员工编号降序3.3、按…

基于SSM实现企业生资源管理系统-ERP系统

作者主页&#xff1a;编程指南针 作者简介&#xff1a;Java领域优质创作者、CSDN博客专家 、掘金特邀作者、多年架构师设计经验、腾讯课堂常驻讲师 主要内容&#xff1a;Java项目、毕业设计、简历模板、学习资料、面试题库、技术互助 收藏点赞不迷路 关注作者有好处 文末获取源…

FlinkSql+Stream综合使用+广播流

Flink状态管理状态的分类Flink容错机制State Vs CheckPointCheckPoint原理State状态后端/State存储介质状态恢复和重启策略SavePointFlink TableAPI&SQL案例广播流状态管理 状态的分类 State ManagerState–开发中推荐使用&#xff1a;Flink自动管理/优化&#xff0c;支持多…

day 32 文件上传二次渲染.htaccess变异免杀

前言&#xff1a; #知识点&#xff1a; 1、文件上传-二次渲染 2、文件上传-简单免杀变异 3、文件上传-.htaccess妙用 4、文件上传-PHP语言特性 #详细点&#xff1a; 1、检测层面&#xff1a;前端&#xff0c;后端等 2、检测内容&#xff1a;文件头&#xff0c;完整性&am…

拥抱 Spring 全新 OAuth 解决方案

以下全文 Spring Authorization Server 简称为: SAS 背景 Spring 团队正式宣布 Spring Security OAuth 停止维护&#xff0c;该项目将不会再进行任何的迭代目前 Spring 生态中的 OAuth2 授权服务器是 Spring Authorization Server 已经可以正式生产使用 作为 SpringBoot 3.0 的…

设计文档编写要点

文章目录设计文档大致流程E-R关系图流程图UML图word制作目录设计文档大致流程 概要 表结构及其之间的关系&#xff08;E-R 图&#xff1a;实体-联系图 Entity Relationship Diagram&#xff09; 业务流程图、时序图&#xff08;按照人操作的维度&#xff09; 程序流程图、时序…

在X11图形环境下开启/关闭勿扰模式及其背后机制

开启/关闭勿扰模式 在Linux系统中、X11图形环境下&#xff0c;开启/关闭勿扰模式很简单&#xff0c;按照以下步骤操作即可&#xff1a; &#xff08;1&#xff09;鼠标左键点击右下角的“^”&#xff0c;即“显示隐藏的图标”。如下图所示&#xff1a; &#xff08;2&#xf…

退火算法研究分析

模拟退火算法采用类似于模拟退火的过程。先在一个高温状态下&#xff0c;逐渐退火&#xff0c;在每个温度下慢慢冷却&#xff0c;最终达到物理基态(相当于算法找到最优解&#xff09; 模拟退火算法属于贪心算法&#xff0c;在其过程中引入随机因素&#xff0c;以一定概率接收一…

Vue挂载(mount)和继承(extend)

vue.$mount 挂载 //index.html文件 <body><div id"app"></div> </body>//index.js文件 //1. 先看看普通的绑定 new Vue({el: #app,// el: document.getElementById(app) template: <div id"app">如果new Vue时候的option的…

【HTML5】弹性盒子实现导航栏和留言框

调CSS就像上方那样&#xff0c;代码逐渐变得扭曲&#xff0c;情绪逐渐变得暴躁。 目录 弹性盒子的核心属性 1、display设置元素生成框 2、弹性盒子比例划分 2.1flex-basis基本宽度 2.2flex-grow放大宽度 2.3flex-shrink缩小宽度 2.4单独的一个flex用法 3、flex-directi…

Windows安装配置Vagrant

1、下载 1.1、连接&#xff1a;https://developer.hashicorp.com/vagrant/downloads 1.2 、选择系统、版本、型号&#xff0c;然后下载 2、安装 2.1、双击运行下载的可执行文件&#xff0c;点击Next 2.2、先同意许可&#xff0c;然后点击Next 2.3、点击Change&#xff0c;选…

数理统计笔记2:总体均值的抽样分布

引言 数理统计笔记的第2篇总结了数理统计中样本均值的分布&#xff0c;可以帮助理解样本均值和总体均值分布之间的联系。举了一个例子可以加深理解&#xff0c;并且还补充了中心极限定理的知识。 一个关键的结论就此诞生了&#xff01;&#xff01;&#xff01; 样本均值的均值…

sqli-labs/Less-50

这一关仍然是以sort作为注入点的 首先我们输入rand() 判断是数字型还是字符型 多次尝试 发生变化 说明属于数字型 接着试试报错注入 输入以下语句 sortupdatexml(1,if(11,concat(0x7e,database(),0x7e),1),1)-- 存在回显 说明可以使用报错注入哦 这一关要训练的是堆叠注入…