SpringBoot源码解析系列(2) SpringBoot如何扫描并将对象注册Beandefinition

本小节主要解决两个问题

1 . 大家都知道对象是有Beanfination来的  1 . 那么BeanDefination是如何来的呢?  2 . SpringBoot是如何自动注入的 3 . 如何实现自动扫描的

那我们先从SpringAapplicatio#refreshContext方法一路进去会进入到AbstractApplicationContext#refresh方法 代码如下

			// 关于环境的一些前置处理 没啥大用
			prepareRefresh();

			// 设置ConfigurableListableBeanFactory
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// 对beanFactory进行初始化操作 
			//主要由设置classloader 设置SpringEL解析器 
			//ignoreDependencyInterface设置不进行自动注入的接口 (防止我们在创建此对象 自动注入注入错) 这些接口都有其对应的Aware接口 我们如果想要引入对应的接口 需要实现对应的Aware类
			//registerResolvableDependency设置当有这种类型注入的时候 直接注入此对象
			//注册比如系统环境这些bean
			prepareBeanFactory(beanFactory);

			try {
				// 没啥用 略过
				postProcessBeanFactory(beanFactory);

				// 这个方法很重要 我会单独开专题讲解
				invokeBeanFactoryPostProcessors(beanFactory);

进入到invokeBeanFactoryPostProcessors之前 我先简单讲一下 BeanFactoryPostProcessor以及其最重要的子接口BeanDefinitionRegistryPostProcessor

BeanFactoryPostProcessor作用 : 1 . 是针对已经添加进ConfigurableListableBeanFactory的BeanDefiantion属性进行修改或者根据已有属性进行检查(按照Spring的定义此接口是严格意义上不允许新增的!!!!!!!!!!!!!!!)  比如 :  AbstractDependsOnBeanFactoryPostProcessor 会针对通过构造器动态决定指定类型的 bean 应该依赖于哪些 bean。(修改BeanDefination的depensOn属性)

BeanDefinitionRegistryPostProcessor作用 : 严格意义上来讲 是新增BeanDefination , 比如 dubbo源码中 将各个接口包成ServiceBean 就是在这步生成ServiceBean的BeanDefination的 , 还比如Apollo会在这步进行注册一些针对Apollo独有的注解处理方式或者一些配置对象等等 太多了不细说

 

回到正题 : 会进入到PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors方法

1 . 先去执行 通过添加容器内的BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry(比如往SpringApplication添加的会在这里执行)

2 . !!!!! 处理此时beanFactory里面添加的BeanDefinitionRegistryPostProcessor (此时有一个类是ConfigurationClassPostProcessor)

这个ConfigurationClassPostProcessor是在AnnationConfigUtils里面添加的 代码如下

		if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
		}

ConfigurationClassPostProcessor 

这个类很重要  我先抛砖引玉  1 . SpringBoot自动装载就依赖于这个类 2 . @Configuration以及相关@Primary,@DependsOn,@Bean等等我把这些称为Spring元注解 (因为这些注解的处理是在Spring内部流程里面的 不是通过扩展的)处理地方 3 . 扫描类路径 等等功能

ConfigurationClassPostProcessor # processConfigBeanDefinitions方法都做了什么?

	public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
	//所有扫描好的BeanDefinition使用BeanDefinitionHolder包装类包装
		List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
		String[] candidateNames = registry.getBeanDefinitionNames();

		// 拿到带@Configuration标签的类 (初始化的时候及时SpringApplication里面的primySource也就是我们常说的启动类)
		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);
				}
			}
			else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
				configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
			}
		}

		if (configCandidates.isEmpty()) {
			return;
		}

        //...省略了一些非关键代码
		//...
		
		// 生成@Configuration标签处理器
		ConfigurationClassParser parser = new ConfigurationClassParser(
				this.metadataReaderFactory, this.problemReporter, this.environment,
				this.resourceLoader, this.componentScanBeanNameGenerator, registry);
		// ...
		do {
			// !!!!!!!!!!!! 处理@Configuration标签  包括扫描类路径什么的 
			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());
			}
			// !!!!!!!!!很重要详细讲
			this.reader.loadBeanDefinitions(configClasses);
			alreadyParsed.addAll(configClasses);
			// ...
	}
ConfigurationClassParser#parse有做了什么呢? 其实在上面我说的关于ConfigurationClassPostProcessor重要功能 具体实现都是在parse里面实现的

这个方法真的蛮重要的我就单独开一个专题

下一节SpringBoot源码解析系列(3) SpringBoot的ConfigurationParser#parse方法 : https://blog.csdn.net/weixin_44669461/article/details/116065005?spm=1001.2014.3001.5501

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值