文章目录
继续跟随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接口