Spring源码学习(二):Spring容器之prepareContext和BeanFactoryPostProcessor的介绍

23 篇文章 0 订阅
6 篇文章 0 订阅

继续跟随Springboot的启动过程分析spring的源码


前言

第一篇地址:Spring源码学习(一):Spring容器创建和初始化工作准备
今天接着第一篇进行下后续学习。
需要提前说明一下的是DefaultListableBeanFactory同时实现了BeanFactory接口和BeanDefinitionRegistry接口。BeanDefinitionRegistry接口的几个主要方法便是对BeanDefinition的一系列处理,包括:注册、移除等;

一、Springboot中prepareContext

上一次我们讲到了Springboot启动过程中,在run方法中通过调用了createApplicationContext(),生成了context,同时在context里面已经加入了5个重要的初始类。
介于我们目前只关心spring的源码,所以我们只关心run方法中跟context相关的代码。

在这里插入图片描述
这样,便来到了context的准备工作方法prepareContext。这个准备工作,具体干啥了呢?其实很简单,一句话总结,就是创建main方法类的BeanDefinition,同时注入到context的容器里。

1.1 获取提前放入的sources

具体逻辑可以详见prepare方法中的代码段:

		// 此处多数情况返回的便是你设定了main方法的那个类的Class对象,可以看下面的解析
		Set<Object> sources = getAllSources();
		load(context, sources.toArray(new Object[0]));

getAllSources的逻辑呢,如下:

/**
	 * Return an immutable set of all the sources that will be added to an
	 * ApplicationContext when {@link #run(String...)} is called. This method combines any
	 * primary sources specified in the constructor with any additional ones that have
	 * been {@link #setSources(Set) explicitly set}.
	 * @return an immutable set of all sources
	 */
	public Set<Object> getAllSources() {
		Set<Object> allSources = new LinkedHashSet<>();
		//这个是不会为空的,因为呢,咱们的run方法,启动的时候把xxxxApplication.class传进来了
		if (!CollectionUtils.isEmpty(this.primarySources)) {
			allSources.addAll(this.primarySources);
		}
		//而this.sources呢,如果咱们不手动调用setSources方法,一般都是empty的
		if (!CollectionUtils.isEmpty(this.sources)) {
			allSources.addAll(this.sources);
		}
		return Collections.unmodifiableSet(allSources);
	}

既然sources有了,那么我们再来看看是怎么把sources里面的register到咱们的context里面的。

1.2 把sources生成BeanDefinition放入到spring容器中

/**
	 * Load beans into the application context.
	 * @param context the context to load beans into
	 * @param sources the sources to load
	 */
	protected void load(ApplicationContext context, Object[] sources) {
		//对于这个loader来说,最重要的步骤是设置了loader的annotatedReader属性,而这个annotatedReader里面的registry属性又被设置成了context的beanfactory
		BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);
		if (this.beanNameGenerator != null) {
			loader.setBeanNameGenerator(this.beanNameGenerator);
		}
		if (this.resourceLoader != null) {
			loader.setResourceLoader(this.resourceLoader);
		}
		if (this.environment != null) {
			loader.setEnvironment(this.environment);
		}
		loader.load();
	}

通过loader进行source的load,最终会调用内部的

private int load(Class<?> source) {
		// do something
		if (isComponent(source)) {
		    //这一步把咱们的XxxxApplication注册进了容器:具体是生成一个BeanDefinition,然后放入进Spring容器里面
		    //这里便用到了咱们在Spring源码学习(一)里面说的AnnotatedBeanDefinitionReader的register方法
			this.annotatedReader.register(source);
			return 1;
		}
		return 0;
	}

二、BeanFactoryPostProcessor的介绍

2.1 BeanFactoryPostProcessor

BeanFactoryPostProcessor接口的主要是在Application Context初始化完毕,能够干预其内部的beanFactory属性

@FunctionalInterface
public interface BeanFactoryPostProcessor {

	/**
	 * Modify the application context's internal bean factory after its standard
	 * initialization. All bean definitions will have been loaded, but no beans
	 * will have been instantiated yet. This allows for overriding or adding
	 * properties even to eager-initializing beans.
	 * @param beanFactory the bean factory used by the application context
	 * @throws org.springframework.beans.BeansException in case of errors
	 */
	void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

}

2.2 BeanDefinitionRegistryPostProcessor

BeanFactoryPostProcessor接口还有个子接口BeanDefinitionRegistryPostProcessor,这个接口的作用是很重要的,作用是生成BeanDefinition,并把BeanDefinition都放入到容器中。

public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {

	/**
	 * Modify the application context's internal bean definition registry after its
	 * standard initialization. All regular bean definitions will have been loaded,
	 * but no beans will have been instantiated yet. This allows for adding further
	 * bean definitions before the next post-processing phase kicks in.
	 * @param registry the bean definition registry used by the application context
	 * @throws org.springframework.beans.BeansException in case of errors
	 */
	void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;

}

2.3 ConfigurationClassPostProcessor

这个类的重要性应该是Spring里面绝无仅有的了,这个类实现了BeanDefinitionRegistryPostProcessor接口,主要承担了postProcessBeanDefinitionRegistry接口具体逻辑的实现。
大家可以回忆一下上一篇,applicationContext在初始化的时候通过reader放入到容器的几个初始BeanDefinition,其中第一个就是ConfigurationClassPostProcessor类的BeanDefinition。
下一篇我们结合Spring容器的启动顺序好好梳理下ConfigurationClassPostProcessor在执行postProcessBeanDefinitionRegistry时具体是怎么做的。

总结

以上就是今天要讲的内容,讲了Springboot启动时,是如何把咱们最重要的配置类变成BeanDefinition,然后放入到Spring容器中,其实是放到了BeanFactory的beanDefinitionMap属性里。再简单介绍了下BeanFactoryPostProcessor接口

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值