栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

spring核心源码分析第七篇 refresh流程之invokeBeanFactoryPostProcessors-ConfigurationClassPostProcessor执行

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

spring核心源码分析第七篇 refresh流程之invokeBeanFactoryPostProcessors-ConfigurationClassPostProcessor执行

这里写目录标题
  • ConfigurationClassPostProcessor作用
    • 源码分析一BeanDefinition生成
      • postProcessBeanDefinitionRegistry源码分析
      • FUll 和 Lite模式简介
      • Demo案例
  • 总结

ConfigurationClassPostProcessor作用
处理以下注解生成BeanDefinition
处理@Component @Service @Controller @Repository解析
处理@ComponentScan @Bean @import @importResource@Configuration解析
处理@importSelecto导入的xml文件
源码分析一BeanDefinition生成

ConfigurationClassPostProcessor包含两个点postProcessBeanDefinitionRegistry和postProcessBeanFactory

  • postProcessBeanDefinitionRegistry目标完成BeanDefinition扫描解析注册
  • postProcessBeanFactory目标是对FULL模式的BeanDefinition增强,增强的目的是为了更好的处理@Bean的依赖注入
postProcessBeanDefinitionRegistry源码分析
核心作用
先解析启动类生成BD集合,在将解析过程中需要特殊处理的解析交给ConfigurationClassBeanDefinitionReader解析
自旋处理beanfactory中新生成的为full和lite的bd 直到完成全部bd生成
FULL和lite模式是BeanDefinition的一种属性,在postProcessBeanFactory执行时会依赖这种属性决定是否增强,增强的作用在于处理@Bean注解的依赖注入,后文讲解其区别
	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);
		先完成注解解析 其次完成@importResource,@import等的BeanDefinition解析
		processConfigBeanDefinitions(registry);
	}
  • 1 摘要: 通过调用processConfigBeanDefinitions完成BeanDefinition加载
  • 2 获取beanfactory已经注册的BeanDefinition[其中有个非常重要的beandefinition为springboot启动类的Application]
  • 3 判断BeanDefinition是否是full或者lite模式,是则解析[解析时会设置full或者lite模式]
  • 4 创建ConfigurationClassParser解析类( @Configuration @ComponentScan @Component @Bean @import @importResource)
  • 5 parser.parse(candidates)完成【springboot启动类】解析以及递归解析
  • 6 解析过程中会将@import等类加入parser的configurationClasses属性
  • 7 通过ConfigurationClassBeanDefinitionReader解析parser的configurationClasses处理剩余的BeanDefinition生成
  • 8 重新获取beanfactory中所有BeanDefinitionName,将没有解析过的重新解析生成BeanDefinition
	public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
		List configCandidates = new ArrayList<>();
	
	 - 1 通过调用processConfigBeanDefinitions完成BeanDefinition加载
     - 2 获取beanfactory已经注册的BeanDefinition[其中有个非常重要的beandefinition为springboot启动类的Application]

		String[] candidateNames = registry.getBeanDefinitionNames();

		for (String beanName : candidateNames) {
			BeanDefinition beanDef = registry.getBeanDefinition(beanName);
		
		 -  3 判断BeanDefinition是否是full或者lite模式,是则解析[解析时会设置full或者
			if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
					ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
				if (logger.isDebugEnabled()) {
					logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
				}
			}
			 判断是否是@Configuration 类
			 判断ComponentScan import importResource Compoment 或者方法上加了bean注解
			 如果是的话给bd设置上full或者lite属性
			else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
				configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
			}
		}

		//  configCandidates 包含了   @Configuration
		if (configCandidates.isEmpty()) {
			return;
		}
		排序 注入context的【configuration component】类可以有多个
		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(CONFIGURATION_BEAN_NAME_GENERATOR);
				if (generator != null) {
					this.componentScanBeanNameGenerator = generator;
					this.importBeanNameGenerator = generator;
				}
			}
		}

		if (this.environment == null) {
			this.environment = new StandardEnvironment();
		}
		构建解析器
		ConfigurationClassParser parser = new ConfigurationClassParser(
				this.metadataReaderFactory, this.problemReporter, this.environment,
				this.resourceLoader, this.componentScanBeanNameGenerator, registry);

		防止用户传入多个相同的candidate
		Set candidates = new linkedHashSet<>(configCandidates);
		已经处理的信息 用于幂等防重复
		Set alreadyParsed = new HashSet<>(configCandidates.size());
		do {
			// 这里解析的是ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)后属性为lite 和full的类
			 - 5 parser.parse(candidates)完成【springboot启动类】解析以及递归解析
			parser.parse(candidates);
			parser.validate();
			    获取parse处理完毕的import的相关内容准备转换成BD
			 - 6 解析过程中会将@import等类加入parser的configurationClasses属性
			Set 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());
			}
			 - 7 通过ConfigurationClassBeanDefinitionReader解析parser的configurationClasses处理剩余的BeanDefinition生成
			将configClasses转换成BD 【包含configuration 普通的bean importresource  importSelector importBeanDefinitionRegister bean method】
			this.reader.loadBeanDefinitions(configClasses);
			alreadyParsed.addAll(configClasses);
			candidates.clear();
			 - 8 重新获取beanfactory中所有BeanDefinitionName,将没有解析过的自旋重新解析生成BeanDefinition
			if (registry.getBeanDefinitionCount() > candidateNames.length) {
				String[] newCandidateNames = registry.getBeanDefinitionNames();
				Set oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
				Set 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;
			}
		}



		// 一些特殊的bean直接这里进行实例化
		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());
		}

		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();
		}
	}
FUll 和 Lite模式简介

spring将所有的配置类分为两种 一种是@Configuration注解标注的类
其余的都是lite类

fulllite
@Configuration@import @Component @ComponentScan @import @importResource @Bean
Demo案例

下文第一段单纯这样配置不起作用,这个类不是lite模式类吗?为什么不起作用?
为什么第二段代码和第三段就可以起作用

  • 首先扫描BeanDefinition的第一步是获取已经配置的[full,lite]BeanDefinition
  • 根据已经配置的BeanDefinition进行递归解析lite和full模式的Configurationclass
@ComponentScan("com.renxl.compoment.scan")
public class Config {
		不可以被解析
}

@ComponentScan(basePackages = {"com.renxl.compoment"})
public class AdminApplication {
	public static void main(String[] args) {
		可以被解析 因为在spring容器refresh之前 AdminApplication的BeanDefinition已经被注册到beanfactory
		SpringApplication.run(AdminApplication.class, args);
	}
	
}
@ComponentScan(basePackages = {"com.renxl.compoment"})
public class AdminApplication {
	public static void main(String[] args) {
		可以被解析 因为在spring容器refresh之前 AdminApplication的BeanDefinition已经被注册到beanfactory
		SpringApplication.run(AdminApplication.class, args);
	}
	
}
@ComponentScan(basePackages = {"com.renxl.compoment"})
@Component
package com.renxl.compoment.config;
public class ConfigAfterBeComponent {
	当AdminApplication扫描到ConfigAfterBeComponent时,其作为一个Component被注册,那么就会递归判断其是否是一个lite或者full模式的配置类,很明显其是一个lite模式,所以可以被解析
}
总结
  • ConfigurationClassPostProcessor 将实际的BD生成工作交给ConfigurationClassParser和ConfigurationClassBeanDefinitionReader去做
  • ConfigurationClassParser 的核心作用是解析配置类[FULL,LITE] 完成BD的解析,并对解析的结果重新进行递归解析,所有的解析类都会放置到ConfigurationClassParser.configurationClasses
  • ConfigurationClassPostProcessor会获取ConfigurationClassParser.configurationClasses并
    调用ConfigurationClassBeanDefinitionReader完成协同工作
  • ConfigurationClassBeanDefinitionReader主要用来完成imported[被导入]@Bean和importedResources以及importBeanDefinitionRegistrar的BeanDefinition生成
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/685564.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号