我们在创建一个Spring boot应用的时候,通常都是使用SpringApplication或者SpringApplicationBuilder API,通过执行run方法进行启动Spring Boot应用;我们可以将整体的生命周期总结为以下几个阶段:
SpringApplication的初始化阶段
SpringApplication的运行阶段
SpringApplication的结束阶段
Spring Boot应用的退出
大致结构如下:
以上几个阶段又有细化的步骤,我们一起来分析下源代码进行查看:
1 初始化阶段
1.1 SpringApplication构造阶段
我们启动项目一般都是通过SpringApplicationBuilder进行初始化SpringApplication或者使用SpringApplication调用静态方法进行初始化启动项目,代码如下所示:
public class SpringBootApplicationBootstrap {
public static void main(String[] args) {
new SpringApplicationBuilder(MultipleSpringBootEventListener.class)
.web(WebApplicationType.NONE)
.run(args);
}
}
public class SpringBootApplicationBootstrap {
public static void main(String[] args) {
SpringApplication.run(SpringBootApplicationBootstrap.class, args);
}
}
两种方式最终都是在SpringApplication的构造方法中进行初始化操作,源码如下:
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.sources = new LinkedHashSet();
this.bannerMode = Mode.CONSOLE;
this.logStartupInfo = true;
this.addCommandLineProperties = true;
this.addConversionService = true;
this.headless = true;
this.registerShutdownHook = true;
this.additionalProfiles = new HashSet();
this.isCustomEnvironment = false;
this.lazyInitialization = false;
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = this.deduceMainApplicationClass();
}
我们所关心的就是最后四行代码了;
梳理整体的流程为:
1.1.1 判断应用类型
this.webApplicationType = WebApplicationType.deduceFromClasspath();
这个方法就是判断当前运行的应用是REACTIVE类型的还是SERVLET类型,或者是非Web应用;
1.1.2 加载ApplicationContextInitializer应用上下文初始化器
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = this.getClassLoader();
Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
通过跟踪源码,我们可以看到获取ApplicationContextInitializer实现类的方式,是使用的Spring的SPI机制,从spring.factories文件中获取配置的实现类名称列表,再通过调用SpringBoot新增的一个方法BeanUtils.instantiateClass(constructor, args)去创建实例,再进行排序操作(每一个实现类都实现了Ordered接口),最后将这些实现类实例保存在SpringApplication的initializers属性中;
ApplicationContextInitializer的作用,如下是官网的解释:
@FunctionalInterface public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> Callback interface for initializing a Spring ConfigurableApplicationContext prior to being refreshed. Typically used within web applications that require some programmatic initialization of the application context. For example, registering property sources or activating profiles against the context's environment. See |
我在网上查找到一个比较全面的解释,请参考:
ApplicationContextInitializer的实现与使用
1.1.3 加载ApplicationListener应用事件监听器
执行的流程和加载ApplicationContextInitializer方式流程一致;
1.1.4 获取主类(应用引导类)
将获取到的主类信息保存到mainApplicationClass属性中;
1.2 SpringApplication配置阶段
这个阶段介于1.1SpringApplication与2 SpringApplication运行阶段之间,其实就是在我们运行run方法之前,通过SpringApplication提供的公共方法,修改相关的配置信息,来达到我们期望的运行效果,例如:
public static void main(String[] args) {
SpringApplication springApplication = new SpringApplicationBuilder(MultipleSpringBootEventListener.class)
.web(WebApplicationType.NONE)
.bannerMode(Banner.Mode.OFF)
.application();
springApplication.getInitializers();
springApplication.addListeners(new MultipleSpringBootEventListener());
springApplication.setSources(new HashSet<>());
springApplication.run(args);
}
可以获取应用上下文初始化器,也可以添加自定义的应用上下文初始化器,添加事件监听器,添加配置源等信息;