文章目录

  • 前言
  • 一、ConfigurationClassPostProcessor是什么?
  • 二、ConfigurationClassPostProcessor是如何工作的?
  • 1.开始创建拦截器实例并执行
  • 2.解析前置处理
  • 3.开始解析配置类


前言


在使用Spring框架的过程中,我们经常会声明一些配置文件及配置类从而达到自动装配目的,Spring在启动过程中会识别并解析这些声明的配置,最后实例化成对应的对象Bean装载到Spring容器中。常见的如:我们标注了@ComponentScan,则指定的路径下或者指定的类都能自动装载到Spring容器中,而负责这一步骤的重要角色就是ConfigurationClassPostProcessor。


一、ConfigurationClassPostProcessor是什么?

ConfigurationClassPostProcessor其实就是一个Spring容器生命周期中的一个拦截器实现类,即BeanDefinitionRegistryPostProcessors的实现类,作用的时机就是在Spring容器启动即BeanFactory实例化后进行拦截处理,读取并解析配置类,并将解析到的Bean封装为BeanDenifition注册到Spring容器中交由后续步骤进行统一的实例化。

关于BeanDefinitionRegistryPostProcessors定义如下:

public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {

		void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws 	BeansException;

	}

可以看出,它继承于标准的BeanFactoryPostProcessor接口并提供了一个额外的扩展方法#postProcessBeanDefinitionRegistry,该方法优先级比BeanFactoryPostProcessor#postProcessBeanFactory高,
该接口方法入参提供了一个 BeanDefinitionRegistry,从字面意思我们可以得知,该拦截器方法的主要作用就是注册BeanDenifition
这里的

二、ConfigurationClassPostProcessor是如何工作的?

说在前面的话:
如果是对Spring容器是如何启动不是太了解的话,建议先从玩转Spring 之 IOC容器这篇文章开始哦。

1.开始创建拦截器实例并执行

在刷新容器的第5步,即 AbstractApplicationContext#invokeBeanFactoryPostProcessors,首先通过getBeanFactoryPostProcessors()方法获取到所有的拦截器实例(正常情况下,这一步容器中还没有拦截器的实例),但是在容器实例化的阶段,Spring已经内置注册了一些BeanFactoryPostProcessor的Bean定义信息(具体见【玩转Spring 之 IOC容器】),所以PostProcessorRegistrationDelegate会根据已经注册的BeanFactoryPostProcessor定义信息去执行拦截器的创建及触发,源码如下:

@Override
	public void refresh() throws BeansException, IllegalStateException {
		......省略部分源码
			
		// 容器启动第5步
		// Invoke factory processors registered as beans in the context.
		invokeBeanFactoryPostProcessors(beanFactory);
			
		......省略部分源码
	}

	protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
		// 通过getBeanFactoryPostProcessors()
		// 在此处交由PostProcessorRegistrationDelegate委托执行
		PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
		
		......省略部分源码
	}

首先看一下ConfigurationClassPostProcessor定义:

public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
		PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {

ConfigurationClassPostProcessor 实现了BeanDefinitionRegistryPostProcessorPriorityOrdered ,在这一步就是根据实现这两个接口进行优先级的排序,即:

  • 首先,实例化并执行实现了BeanDefinitionRegistryPostProcessorPriorityOrdered
  • 其次,实例化并执行实现了BeanDefinitionRegistryPostProcessorOrdered
  • 最后,实例化并执行其他的BeanDefinitionRegistryPostProcessor
public static void invokeBeanFactoryPostProcessors(
			ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

			// 首先, 实例化并执行实现了PriorityOrdered的BeanDefinitionRegistryPostProcessors 
			String[] postProcessorNames =
					beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			for (String ppName : postProcessorNames) {
				if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
					// beanFactory.getBean()方式实例化BeanDefinitionRegistryPostProcessor
					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					processedBeans.add(ppName);
				}
			}
			// 排序
			sortPostProcessors(currentRegistryProcessors, beanFactory);
			registryProcessors.addAll(currentRegistryProcessors);
			// 执行,这一步就是解析配置类的入口
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
			currentRegistryProcessors.clear();

			// 接下来, 实例化并执行实现了Ordered的BeanDefinitionRegistryPostProcessors .
			
			// 最后, 实例化并执行剩余的 BeanDefinitionRegistryPostProcessors

			// 执行BeanDefinitionRegistryPostProcessors的postProcessBeanFactory方法作为回调
			invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
			invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
		}

		// 实例化并执行所有BeanFactoryPostProcessor,和上述优先级规则相同,都是根据实现PriorityOrdered,Ordered 进行排序
		
		...
	}

至此,ConfigurationClassPostProcessor 已经实例化并开始执行,见ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry

@Override
	public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
		......
		// 开始解析
		processConfigBeanDefinitions(registry);
	}
2.解析前置处理

调用流程如下:


ConfigurationClassPostProcessor ConfigurationClassParser processConfigBeanDefinitions 实例化 parse ConfigurationClassPostProcessor ConfigurationClassParser


  1. 获取BeanFactory中所有的BeanDefinition (这里除了在容器启动前期加入的一些BeanDefinition外,剩下的应该就是我们@Configuration配置类 )依次判断是否是需要解析的配置类,规则如下:
  • 标注了@Configuration则为FullConfiguration。
  • 标注了@Component@ComponentScan@Import@ImportResource则为LiteConfiguration
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
		List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
		
		// 1. 获取BeanFactory中所有的BeanDefinition 依次判断是否是需要解析的配置类
		String[] candidateNames = registry.getBeanDefinitionNames();
		for (String beanName : candidateNames) {
			BeanDefinition beanDef = registry.getBeanDefinition(beanName);
			if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
					ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
				if (logger.isDebugEnabled()) {
					logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
				}
			}
			// 重点关注该方法ConfigurationClassUtils.checkConfigurationClassCandidate
			// 该方法会判断是否是FullConfigurationClass(即加有@Configuration注解)
			// 是否是LiteConfigurationClass(即是否加了@Component,@Import,@ComponentScan,ImportResource)
			// 是否含有加了@Bean注解的方法
			else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
				// 以上条件满足,则标记为需要解析的配置类
				configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
			}
		}
		......
	}
  1. 对第一步确定下来的配置类进行排序。
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
	// 1. 获取BeanFactory中所有的BeanDefinition 依次判断是否是需要解析的配置类
	......接上述方法

	// 2. 对配置类进行排序
	configCandidates.sort((bd1, bd2) -> {
		int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
		int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
		return Integer.compare(i1, i2);
	});
	......
}
  1. 实例化ConfigurationClassParser解析器:
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
	// 1. 获取BeanFactory中所有的BeanDefinition 依次判断是否是需要解析的配置类
	......
	// 2. 对配置类进行排序
	......接上述方法
	
	// 3. 实例化解析器
	ConfigurationClassParser parser = new ConfigurationClassParser(
			this.metadataReaderFactory, this.problemReporter, this.environment,
			this.resourceLoader, this.componentScanBeanNameGenerator, registry);
	......
}
  1. 调用ConfigurationClassParser #parse(configCandidates)方法开始解析步骤1中的configCandidates:
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
	// 1. 获取BeanFactory中所有的BeanDefinition 依次判断是否是需要解析的配置类
	......
	// 2. 对配置类进行排序
	......
	// 3. 实例化解析器
	......
	Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
	Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
	do {
		// 4. 开始解析
		parser.parse(candidates);
		parser.validate();
		......
		}
	while (!candidates.isEmpty());
}
  1. 将需要解析的信息封装为ConfigurationClass进行统一的解析:
public void parse(Set<BeanDefinitionHolder> configCandidates) {
		for (BeanDefinitionHolder holder : configCandidates) {
			BeanDefinition bd = holder.getBeanDefinition();
			try {
				// 如果是基于注解的则会从这里开始解析
				if (bd instanceof AnnotatedBeanDefinition) {
					// 将配置类的Metadata传入封装为ConfigurationClass
					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());
				}
			}
			......
		}
		this.deferredImportSelectorHandler.process();
	}
	
	// 对ConfigurationClass 开始解析
	protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
		......
		// 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);
	}
3.开始解析配置类

doProcessConfigurationClass(configClass, sourceClass);解析的注解如下:

  • @Component
  • @PropertySource
  • @ComponentScan
  • @Import
  • @ImportResource
  • @Bean
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
			throws IOException {

		// 判断是否加了@Component注解
		// 注:@Configuration继承于@Component,所以这一步会去解析Config类
		if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
			// Recursively process any member (nested) classes first
			// 递归的去解析内部类
			processMemberClasses(configClass, sourceClass);
		}

		// 解析 @PropertySource 
		for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
				sourceClass.getMetadata(), PropertySources.class,
				org.springframework.context.annotation.PropertySource.class)) {
			if (this.environment instanceof ConfigurableEnvironment) {
				processPropertySource(propertySource);
			}
			......
		}
		// 解析 @ComponentScan
		Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
				sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
		// shouldSkip会解析@Conditional判断当前扫描的类是否跳过
		if (!componentScans.isEmpty() &&
				!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
			// 循环扫描@ComponentScan指定的包路径下的类
			for (AnnotationAttributes componentScan : componentScans) {
				Set<BeanDefinitionHolder> scannedBeanDefinitions =
						this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
				// 对扫描到的类信息进行递归解析
				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());
					}
				}
			}
		}

		// 解析 @Import annotations
		processImports(configClass, sourceClass, getImports(sourceClass), true);

		// 解析 @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);
			}
		}

		// 解析加了 @Bean 的方法
		Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
		for (MethodMetadata methodMetadata : beanMethods) {
			configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
		}
		......
		// null 表示当前类解析结束
		return null;
	}

下面具体看一下每个注解是如何解析的:

  • @Component注解解析:
    在解析@Component注解时,会判断当前类是否会有嵌套类的存在,如果存在,则判断嵌套类是否也需要解析:
private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
	// 获取当前configClassd的内部类
	Collection<SourceClass> memberClasses = sourceClass.getMemberClasses();
	if (!memberClasses.isEmpty()) {
		List<SourceClass> candidates = new ArrayList<>(memberClasses.size());
		for (SourceClass memberClass : memberClasses) {
			// 对内部类进行判断是否标注了@Configuration
			if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) &&
					!memberClass.getMetadata().getClassName().equals(configClass.getMetadata().getClassName())) {
				candidates.add(memberClass);
			}
		}
		OrderComparator.sort(candidates);
		for (SourceClass candidate : candidates) {
			if (this.importStack.contains(configClass)) {
				this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
			}
			else {
				this.importStack.push(configClass);
				try {
					// 将内部类封装为CofigurationClass开始解析
					processConfigurationClass(candidate.asConfigClass(configClass));
				}
				finally {
					this.importStack.pop();
				}
			}
		}
	}
}
  • @ComponentScan@ComponentScan的解析依赖于ComponentScanAnnotationParser,该解析器在实例化ConfigurationClassParser的构造方法中就已经创建了:
    获取@ComponentScan注解信息:
  • // Process any @ComponentScan annotations
    	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) {
    			// 开始解析 ComponentScan 进行扫描
    			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();
    				}
    				// 对扫描到的 BeanDenifition 进行判断,满足@Configuration,@Component 注解的才会作为ConfigurationClass进行解析
    				if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
    					parse(bdCand.getBeanClassName(), holder.getBeanName());
    				}
    			}
    		}
    	}
  • @ComponentScan指定的包路径进行扫描:
  • public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
    	...... 省略的内容主要是解析@ComponentScan的其他配置属性,如useDefaultFilters, lazyInit
    	
    	// basePackage 属性值
    	Set<String> basePackages = new LinkedHashSet<>();
    	String[] basePackagesArray = componentScan.getStringArray("basePackages");
    	for (String pkg : basePackagesArray) {
    		String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg),
    				ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
    		Collections.addAll(basePackages, tokenized);
    	}
    	// basePackageClasses 属性值
    	for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {
    		basePackages.add(ClassUtils.getPackageName(clazz));
    	}
    	// 如果没有指定对应的包路径或者class路径,则默认扫描声明@ComponentScan类的所在包
    	if (basePackages.isEmpty()) {
    		basePackages.add(ClassUtils.getPackageName(declaringClass));
    	}
    	// exclude当前的声明@ComponentScan的class,因为在容器初始阶段就已经注册,这里不会重复扫描并解析
    	scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
    		@Override
    		protected boolean matchClassName(String className) {
    			return declaringClass.equals(className);
    		}
    	});
    	// 开始扫描
    	return scanner.doScan(StringUtils.toStringArray(basePackages));
    }
  • @Import@ImportResource@Bean 这些注解,在上面的解析过程中并没有真正的开始,只是将这些注解引入的一些基础信息准备好,等到上述的步骤都完成后才开始真正解析需要的BeanDenifition:
    ConfigurationClassBeanDefinitionReader#loadBeanDefinitions:
// 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());
	}
	// 注册BeanDefinition
	this.reader.loadBeanDefinitions(configClasses);
private void loadBeanDefinitionsForConfigurationClass(
			ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
		// 判断是否需要过滤掉的configClass
		if (trackedConditionEvaluator.shouldSkip(configClass)) {
			String beanName = configClass.getBeanName();
			if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
				this.registry.removeBeanDefinition(beanName);
			}
			this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
			return;
		}
		// 如果是@Import注解引入的
		if (configClass.isImported()) {
			registerBeanDefinitionForImportedConfigurationClass(configClass);
		}
		// 从@Bean方式引入的
		for (BeanMethod beanMethod : configClass.getBeanMethods()) {
			loadBeanDefinitionsForBeanMethod(beanMethod);
		}
		// 从@ImportResource配置文件引入的
		loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
		// 如果是实现了ImportBeanDefinitionRegistrar
		loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
	}

到这里,ConfigurationClassPostProcessor 的职责就全部完成了,所有需要交由Spring实例化的BeanDenifition都已经注册到容器中,交由后续的步骤进行统一的实例化和初始化。