Spring ConfigurationClassPostProcessor

ConfigurationClassPostProcessor 是spring框架中提供解析配置类的一个比较重要的后置处理器,其主要作用是解析配置类,即@Configuration标记的类

  • 其实现了BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor:

Spring ConfigurationClassPostProcessor
在容器BeanFactory创建好并加载了已经配置(比如配置文件)的bean定义后,会执行 postProcessBeanDefinitionRegistry 方法和 postProcessBeanFactory 方法;

ConfigurationClassPostProcessor#processConfigBeanDefinitions

  • postProcessBeanDefinitionRegistry 方法里解析BeanDefinition逻辑主要是processConfigBeanDefinitions完成的

方法签名:org.springframework.context.annotation.ConfigurationClassPostProcessor#processConfigBeanDefinitions

下面方法只保留了核心方法

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
		List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
		String[] candidateNames = registry.getBeanDefinitionNames();

		... 省略部分代码...

		// Parse each @Configuration class
		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 {
//@A		
			parser.parse(candidates);
			parser.validate();

			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());
			}
//@B			
			this.reader.loadBeanDefinitions(configClasses);
			alreadyParsed.addAll(configClasses);

			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());
		
		... 省略部分代码...
		
	}

ConfigurationClassParser#parse

上面标记@A的代码:其主要逻辑是委托ConfigurationClassParser类来完成;

这个工具类自身的逻辑并不注册bean定义,它的主要任务是发现@Configuration注解的所有配置类并将这些配置类交给调用者(调用者会通过其他方式注册其中的bean定义);而对于非@Configuration注解的其他bean定义,比如@Component注解的bean定义,该工具类使用另外一个工具ComponentScanAnnotationParser扫描和注册它们。

以下是配置类【Configuration标记的类】流程控制核心方法:

org.springframework.context.annotation.ConfigurationClassParser#parse(java.util.Set<org.springframework.beans.factory.config.BeanDefinitionHolder>)

public void parse(Set<BeanDefinitionHolder> configCandidates) {
		for (BeanDefinitionHolder holder : configCandidates) {
			BeanDefinition bd = holder.getBeanDefinition();
			try {
				if (bd instanceof AnnotatedBeanDefinition) {
//@AA				
					parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
				}
				else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
//@BB				
					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);
			}
		}
//@CC
		this.deferredImportSelectorHandler.process();
	}

//@AA:解析配置,内部会发生方法递归调用解析(主要发生在ComponentScan扫描出来的候选类,会被一一递归解析),最终是将解析到的类放到 this.configurationClasses 属性
//@BB:和 @AA逻辑一致
//@CC:在@AA 和@BB循环完毕后,会解析被@import的类,但是有个特殊的接口不会在@AA 和@BB中被处理,那就是DeferredImportSelector,嘿嘿 spring boot 中的 AutoConfigurationImportSelector就是一个DeferredImportSelector实现类;DeferredImportSelector 的设计目的是在所有其他的配置类被处理后才处理。

上一篇:ecstore中kvstore之memcached


下一篇:Go Web:Cookie