Spring Boot 工程的主函数
@SpringBootApplication()
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(WhidsSsApplication.class, args);
}
}
分为了两个部分:
SpringApplication
new SpringApplication
SpringApplication
springApplication.run()
配置基本的环境变量、资源、构造器、监听器。
初始化阶段的主要作用是为运行 SpringApplication
实例对象启动环境变量准备、以及进行资源构造器的初始化动作。
@SuppressWarnings({ "unchecked", "rawtypes" })
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
this.bootstrapRegistryInitializers = getBootstrapRegistryInitializersFromSpringFactories();
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
setInitializers
,实例化所有初始器:ApplicationContextInitializer
是在 SpringFactoriesLoader.loadFactoryNames
方法里面进行的。这个方法会尝试从类路径的 META-INF/spring.factories
读取相应配置文件,然后进行遍历,读取配置文件中Key为:org.springframework.context.ApplicationContextInitializer
的 value。Initializers
定义如下,Initializers
的作用在上一章中已详细解释# Application Context Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
org.springframework.boot.context.ContextIdApplicationContextInitializer,\
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer,\
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer
setListeners
,实例化所有监听器# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.env.EnvironmentPostProcessorApplicationListener
Spring Boot 正式启动加载过程,包括启动流程监控模块、配置环境加载模块、ApplicationContext
容器上下文环境加载模块。
其中的一些关键步骤:
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);
SpringApplicationRunListeners
本质上是一个事件发布者,它在 SpringBoot 应用启动的不同时间点发布不同应用事件类型(ApplicationEvent
):
由上文知在初始化的流程中,SpringApplication 加载了一系列 ApplicationListener
,其监听的事件就是在这里发布的。
ApplicationContext
,也就是我们所说的 Spring Ioc 容器,是在 BeanFactory 的基础之上的一种更高级的容器,除了具有基本的 bean 管理功能之外,还提供对事件监听机制以及国际化的支持等。context = createApplicationContext();
ApplicationContext
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
主要完成以下工作:
BeanNameGenerator
// public static final String CONFIGURATION_BEAN_NAME_GENERATOR =
// "org.springframework.context.annotation.internalConfigurationBeanNameGenerator";
context.getBeanFactory().registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
this.beanNameGenerator);
Spring 定义 bean 有两种模式:配置文件(xml,properties)和注解。BeanNameGenerator 是为 bean 定义生成 bean 名称的策略接口。
其实现类有两个:
DefaultBeanNameGenerator :用来处理 xml 资源文件,但一般情况下在 Spring Boot 中我们很少使用 xml 来引入 bean;
AnnotationBeanNameGenerator :处理 @Component 等注解生成 bean name。当注解中有 value 属性时,则给 bean 命名为 value 值。当没有指定名称时,则根据类名自动生成。
ApplicationContextInitializer
,依次执行initializer.initialize(context);
ApplicationContext
已经准备完毕listeners.contextLoaded(context);
void contextLoaded(ConfigurableApplicationContext context) {
doWithListeners("spring.boot.application.context-loaded", (listener) -> listener.contextLoaded(context));
}
// Load the sources
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[0]));
ApplicationContext
已经装载完毕listeners.contextLoaded(context);
refreshContext(context);
listeners.started(context);