SpringBoot启动流程简析(三)

时间:2021-06-12 12:49:17

我们在上一节中说了SpringBoot的应用上下文的对象是AnnotationConfigEmbeddedWebApplicationContext,通过名字直译就是注解配置的可嵌入的web应用上下文。我们对它先不做过多的介绍,在不远的文章中我们就会对它进行一下简单的分析。

//上下文的一些准备动作
prepareContext(context, environment, listeners, applicationArguments,printedBanner);
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
//将之前创建的环境变量的对象放入到应用上下文中
context.setEnvironment(environment);
//像Spring容器中先行注入BeanNameGenerator和ResourceLoader的实例
postProcessApplicationContext(context);
//调用之前在SpringBoot中加载的ApplicationContextInitializer的实现类,先进行一些初始化的动作
//在之前的文章中我分析过在SpringBoot启动的过程中会从META-INF/spring.factories中加载ApplicationContextInitializer的对象
applyInitializers(context);
//这里是一个空实现
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
//// Add boot specific singleton beans
//将之前得到的的应用参数解析器注入到Spring容器中
context.getBeanFactory().registerSingleton("springApplicationArguments",
applicationArguments);
//将之前得到的的springBootBanner注入到Spring容器中
if (printedBanner != null) {
context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
}
// Load the sources
// 加载sources 这里是指我们的启动类
Set<Object> sources = getSources();
//sources不能为空
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[sources.size()]));
//监听上下文的变化
listeners.contextLoaded(context);
}
load(context, sources.toArray(new Object[sources.size()]));
protected void load(ApplicationContext context, Object[] sources) {
//创建BeanDefinition的加载器 直接new BeanDefinitionLoader
BeanDefinitionLoader loader = createBeanDefinitionLoader(
getBeanDefinitionRegistry(context), sources);
//如果beanNameGenerator 对象不为空的话,则在BeanDefinitionLoader中set beanNameGenerator
if (this.beanNameGenerator != null) {
loader.setBeanNameGenerator(this.beanNameGenerator);
}
//如果resourceLoader 对象不为空的话,则在BeanDefinitionLoader中set resourceLoader
if (this.resourceLoader != null) {
loader.setResourceLoader(this.resourceLoader);
}
//如果environment 对象不为空的话,则在BeanDefinitionLoader中set environment
if (this.environment != null) {
loader.setEnvironment(this.environment);
}
//用BeanDefinitionLoader进行加载
loader.load();
}
private BeanDefinitionRegistry getBeanDefinitionRegistry(ApplicationContext context) {
//由于AnnotationConfigEmbeddedWebApplicationContext实现了BeanDefinitionRegistry接口,所以这里直接返回AnnotationConfigEmbeddedWebApplicationContext的实例
if (context instanceof BeanDefinitionRegistry) {
return (BeanDefinitionRegistry) context;
}
//DefaultListableBeanFactory也实现了BeanDefinitionRegistry的接口
if (context instanceof AbstractApplicationContext) {
return (BeanDefinitionRegistry) ((AbstractApplicationContext) context)
.getBeanFactory();
}
throw new IllegalStateException("Could not locate BeanDefinitionRegistry");
}
public int load() {
int count = 0;
//这里的sources即是我们上面说的sources
for (Object source : this.sources) {
//load source
count += load(source);
}
return count;
}
private int load(Object source) {
Assert.notNull(source, "Source must not be null");
//如果是Class类型
if (source instanceof Class<?>) {
return load((Class<?>) source);
}
//如果是Resource类型
if (source instanceof Resource) {
return load((Resource) source);
}
if (source instanceof Package) {
return load((Package) source);
}
if (source instanceof CharSequence) {
return load((CharSequence) source);
}
//不是上面说的四种类型,则抛出异常
throw new IllegalArgumentException("Invalid source type " + source.getClass());
}
private int load(Class<?> source) {
//如果是Groovy环境
if (isGroovyPresent()) {
// Any GroovyLoaders added in beans{} DSL can contribute beans here
if (GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source,
GroovyBeanDefinitionSource.class);
load(loader);
}
}
//判断当前Class上面是否有Component注解
if (isComponent(source)) {
//将启动应用主类注入到Spring容器中 由于SpringBoot的自动配置的特性,所以这里在注入Spring容器的过程中会判断应不应该将这个类注入到Spring容器中
this.annotatedReader.register(source);
return 1;
}
return 0;
}
//这个方法的调用算是Spring容器开始启动工作了,这个过程是相当复杂我们以后会断断续续的分析点
refreshContext(context);

在这一篇文章中主要是分析了SpringBoot应用上下文的创建,和加载预先定义的几个Bean,像DefaultApplicationArguments、SpringBootBanner启动主类等。