首页 > 编程语言 >Spring源码-11-后置处理器ConfigurationClassPostProcessor

Spring源码-11-后置处理器ConfigurationClassPostProcessor

时间:2022-12-16 16:34:13浏览次数:58  
标签:11 configClass beanFactory Spring Bean 源码 registry new BeanDefinition

Spring源码-11-后置处理器ConfigurationClassPostProcessor

Bean工厂后置处理器

一 类图

二 Demo

// MyTest00.java
public class MyTest00 {

	public static void main(String[] args) {
		DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
		beanFactory.registerBeanDefinition("myCfg00", new RootBeanDefinition(MyCfg00.class));
		ConfigurationClassPostProcessor postProcessor = new ConfigurationClassPostProcessor();
		postProcessor.postProcessBeanDefinitionRegistry(beanFactory);
	}
}
// MyCfg00.java
@Configuration
public class MyCfg00 {
}

三 BeanDefinitionRegistryPostProcessor抽象回调

// ConfigurationClassPostProcessor.java
@Override
	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);

		this.processConfigBeanDefinitions(registry);
	}
// ConfigurationClassPostProcessor.java
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
		/**
		 * 把配置类缓存起来
		 * 配置类区分为
		 *     - full型
		 *         - @Configuration注解的proxyBeanMethods属性是true
		 *     - lite型
		 *         - @Configuration注解的proxyBeanMethods属性是false
		 *         - 类上还有其他注解
		 *             - @Component
		 * 			   - @ComponentScan
		 * 			   - @Import
		 * 			   - @ImportResource
		 *         - 类有@Bean标识的方法
		 */
		List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
		String[] candidateNames = registry.getBeanDefinitionNames(); // 缓存在beanDefinitionNames中的名称

		for (String beanName : candidateNames) {
			BeanDefinition beanDef = registry.getBeanDefinition(beanName); // 缓存在beanDefinitionMap中的BeanDefinition
			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)) { // 判定是full型配置类还是lite型配置类
				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标识的优先级升序
		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
		SingletonBeanRegistry sbr = null;
		if (registry instanceof SingletonBeanRegistry) {
			sbr = (SingletonBeanRegistry) registry;
			if (!this.localBeanNameGeneratorSet) {
				BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
						AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR); // Bean名称生成器 配置类即将被封装成BeanDefinition放到Bean工厂 注册BeanDefinition时要指定名称
				if (generator != null) {
					this.componentScanBeanNameGenerator = generator;
					this.importBeanNameGenerator = generator;
				}
			}
		}

		if (this.environment == null) {
			this.environment = new StandardEnvironment();
		}

		// 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); // 配置类(full型和lite型)
		Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
		do {
			StartupStep processConfig = this.applicationStartup.start("spring.context.config-classes.parse");
			/**
			 * 解析配置类
			 *     - @Configuration标识的类封装成BeanDefinition注册到BeanFactory
			 *     - @ComponentScan扫描的类封装成BeanDefinition注册到BeanFactory
			 * @Import和@Bean注解的类不会封装成BeanDefinition
			 */
			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());
			}
			/**
			 * 将解析出来的配置类封装成BeanDefinition注册进BeanFactory
			 * @Import和@Bean注册的Bean在这一步被解析成BeanDefinition注册到Bean工厂
			 */
			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 = Set.of(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())) {
							// 还没解析的类加到集合中轮询到下一个loop中
							candidates.add(new BeanDefinitionHolder(bd, candidateName));
						}
					}
				}
				candidateNames = newCandidateNames;
			}
		}
		while (!candidates.isEmpty());

		// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
		if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
			sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
		}

		// Store the PropertySourceDescriptors to contribute them Ahead-of-time if necessary
		this.propertySourceDescriptors = parser.getPropertySourceDescriptors();

		if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory 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.clearCache();
		}
	}

1 配置类解析

配置类解析传送门

2 BeanDefinition注册Bean工厂

上面parse(...)阶段

  • 可能发生BeanDefinition注册Bean工厂

  • 可能在配置类中缓存了

    • importBeanDefinitionRegistrars
      • @Import注解导入了实现了ImportBeanDefinitionRegistrar的类
    • imports
      • @Import注解导入的类(没有实现ImportSelector接口和ImportBeanDefinitionRegistrar接口)
    • importedResources
      • @ImportResource导入的配置文件
    • beanMethods
      • @Bean标识的方法
// ConfigurationClassPostProcessor.java
/**
			 * 上面parse(...)阶段
			 *     - 可能发生BeanDefinition注册Bean工厂
			 *     - 可能在配置类中缓存了
			 *         - importBeanDefinitionRegistrars
			 *             - @Import注解导入了实现了ImportBeanDefinitionRegistrar的类
			 *         - imports
			 *             - @Import注解导入的类(没有实现ImportSelector接口和ImportBeanDefinitionRegistrar接口)
			 *         - importedResources
			 *             - @ImportResource导入的配置文件
			 *         - beanMethods
			 *             - @Bean标识的方法
			 *
			 */
			this.reader.loadBeanDefinitions(configClasses);
// ConfigurationClassBeanDefinitionReader.java
public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
		TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
		for (ConfigurationClass configClass : configurationModel) {
			loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
		}
	}
// ConfigurationClassBeanDefinitionReader.java
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()) { // 配置类是被@Import进来的
			registerBeanDefinitionForImportedConfigurationClass(configClass); // 导入进来的类是个配置类 封装成BeanDefinition注册Bean工厂
		}
		for (BeanMethod beanMethod : configClass.getBeanMethods()) { // 缓存着@Bean方法
			loadBeanDefinitionsForBeanMethod(beanMethod); // @Bean注解的方法 方法返回值类型的类封装成BeanDefinition注册Bean工厂
		}

		loadBeanDefinitionsFromImportedResources(configClass.getImportedResources()); // @ImportResource导入的配置文件
		// @Import注册的Bean实现了ImportBeanDefinitionRegistrar 回调这个接口的registerBeanDefinitions方法
		loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
	}

四 BeanFactoryPostProcessor抽象回调

// ConfigurationClassPostProcessor.java
@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		int factoryId = System.identityHashCode(beanFactory);
		if (this.factoriesPostProcessed.contains(factoryId)) {
			throw new IllegalStateException(
					"postProcessBeanFactory already called on this post-processor against " + beanFactory);
		}
		/**
		 * Bean工厂后置处理器
		 *     - 超类 BeanFactoryPostProcessor回调postProcessBeanFactory方法
		 *     - 子类 BeanDefinitionRegistryPostProcessor回调postProcessBeanDefinitionRegistry
		 * 两个两调中都会处理配置类
		 * 避免重复执行通过id进行标识后置处理器是否已经处理过配置类
		 */
		this.factoriesPostProcessed.add(factoryId);
		if (!this.registriesPostProcessed.contains(factoryId)) {
			// BeanDefinitionRegistryPostProcessor hook apparently not supported...
			// Simply call processConfigurationClasses lazily at this point then.
			processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
		}

		/**
		 * beanFactory实现是DefaultListableBeanFactory
		 * @Configuration(proxyBeanMethods=true)标识的full型配置类的Bean类进行增强
		 *     - 这个时候还没发生Bean实例化/初始化
		 *     - 仅仅是将BeanDefinition已经注册在了Bean工厂中
		 *     - 此时将BeanDefinition中Bean的Class进行增强
		 *     - 将来进行实例化时回调
		 */
		this.enhanceConfigurationClasses(beanFactory);
		// 向Bean工厂注册一个Bean后置处理器
		beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
	}

1 full型配置类增强

传送门

2 Bean后置处理器注册

传送门

3 Bean后置处理器ImportAwareBeanPostProcessor

传送门

标签:11,configClass,beanFactory,Spring,Bean,源码,registry,new,BeanDefinition
From: https://www.cnblogs.com/miss-u/p/16987722.html

相关文章

  • Spring源码-16-容器refresh之registerBeanPostProcessors方法
    Spring源码-16-容器refresh之registerBeanPostProcessors方法//AbstractApplicationContext.java/** *5Bean实例化初始化之前将后置处理器注册到容器中 *......
  • spring boot 配置记录
    1.spring-retry spring-retry 是Spring中的提供的一个重试框架,提供了注解的方式,在不入侵原有业务逻辑代码的方式下,优雅的实现重处理功能。使用步骤:a)添......
  • ubuntu 11.10(32位系统)下编译android源码 make错误解决办法
    本文介绍在ubuntu11.10系统下编译android2.3.3源码,编译之前请确定上两篇文章中所需的准备工作已经成功完成。编译完成生成系统镜像文件,并在模拟器中运行。准备工作完成......
  • java.lang.NoClassDefFoundError: Could not initialize class sun.awt.X11Graphi
    公司项目windows迁移到linux系统,导出Excel报错误,解决办法:配置Tomcat中的catalina.sh在JAVA_OPTS中添加-Djava.awt.headless=true这样的代码,在末尾加上-Djava.awt.hea......
  • SpringBoot(六):配置文件的位置以及优先级
    SpringApplication 从以下位置的 application.properties 文件中加载属性(properties),并将它们添加到Spring Environment 中:项目目录的 /config 子目录项目目录的......
  • 【转载】完美解决 java: 无效的目标发行版: 11
    在使用IDEA编译程序时出现下面的错误信息:java:无效的目标发行版:11问题描述经过研究才发现,这是因为作者使用了jdk8进行编译,而试图使用jdk11的功能,这就必然会导致版本问......
  • 视频直播系统源码,Android 读取联系人列表
    视频直播系统源码,Android读取联系人列表1、activity_main.xml只有一个listview列表项用于存储从手机联系人中获取的数据。 <?xmlversion="1.0"encoding="utf-8"?><......
  • 如何在SpringBoot中优雅地重试调用第三方API?
    前言作为后端程序员,我们的日常工作就是调用一些第三方服务,将数据存入数据库,返回信息给前端。但你不能保证所有的事情一直都很顺利。像有些第三方API,偶尔会出现超时。此时,......
  • Spring Batch -项目处理
    ItemReader和ItemWriter接口​对于其特定任务,但是如果要在编写之前插入业务逻辑怎么办?两者兼而有之的一个选项读写是使用复合模式:创建一个包含另一个或包含另一个.以......
  • Spring Batch -扩展和并行处理
    许多批处理问题可以通过单线程、单进程作业来解决,因此,在考虑之前正确检查这是否满足您的需求总是一个好主意关于更复杂的实现。衡量实际工作的表现,看看是否最简单的实现......