前言:
前文我们宏观的分析了 Spring Boot 的启动流程,本篇将分析一下 SpringApplication#run 的重点步骤。
Spring Boot 系列文章传送门
SpringApplication#run 方法源码解析
解析 SpringApplication#run 方法源码,Spring Boot 启动流程大概分为一下几点步骤,如下:
- 获取监听器,启动监听。
- 加载环境配置。
- 创建应用程序上下文。
- 准备上下文,各种初始化操作。
- 刷新上下文,最终调用到 AbstractApplicationContext#refresh 方法,也就是 Spirng 容器启动。
- 刷新后操作,模板方法,空实现。
java
//org.springframework.boot.SpringApplication#run(java.lang.String...)
public ConfigurableApplicationContext run(String... args) {
//计时器 记录启动耗时
StopWatch stopWatch = new StopWatch();
//启动开始
stopWatch.start();
//创建默认的引导上下文
DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
//可配置的应用程序上下文
ConfigurableApplicationContext context = null;
//java.awt.headless 是 J2SE 的一种模式用于在缺少显示屏、键盘或者鼠标时的系统配置 很多监控工具如jconsole 需要将该值设置为true 系统变量默认为true
this.configureHeadlessProperty();
//获取 SpringApplicationRunListener 实例数组 默认获取的是 EventPublishRunListener
SpringApplicationRunListeners listeners = this.getRunListeners(args);
//启动监听
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
//创建 ApplicationArguments 默认应用程序参数 对象
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//加载环境配置
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
//忽略配置 bena 信息
this.configureIgnoreBeanInfo(environment);
//Banner 打印
Banner printedBanner = this.printBanner(environment);
//创建 应用程序上下文
context = this.createApplicationContext();
//设置应用程序启动
context.setApplicationStartup(this.applicationStartup);
//准备上下文 就是各种初始化错误
this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
//刷新上下文 最终调用到 AbstractApplicationContext#refresh 方法
this.refreshContext(context);
//刷新后操作 空实现
this.afterRefresh(context, applicationArguments);
//结束计时
stopWatch.stop();
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
}
//监听器启动
listeners.started(context);
//调用 ApplicationRunner 和 CommandLineRunner
this.callRunners(context, applicationArguments);
} catch (Throwable var10) {
//失败处理
this.handleRunFailure(context, var10, listeners);
throw new IllegalStateException(var10);
}
try {
//通知监听器 Spring Boot 正在运行
listeners.running(context);
return context;
} catch (Throwable var9) {
//失败处理
this.handleRunFailure(context, var9, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var9);
}
}
获取监听器
SpringApplication#getRunListeners 方法获取监听器,启动监听,SpringApplicationRunListeners 类中有一个监听器数组 listeners,获取监听器的源码前文在分析 SpringApplication 构造函数的时候已经分析过了,就是加载 class 下 META-INF/spring.factories 文件中 ApplicationListener 的实现类。
java
//org.springframework.boot.SpringApplication#getRunListeners
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class[]{SpringApplication.class, String[].class};
//创建一个 SpringApplicationRunListeners 对象 加载 class 下 META-INF/spring.factories 文件中 ApplicationListener 的实现类
return new SpringApplicationRunListeners(logger, this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args), this.applicationStartup);
}
//org.springframework.boot.SpringApplication#getSpringFactoriesInstances(java.lang.Class<T>)
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
//真正处理的方法
return this.getSpringFactoriesInstances(type, new Class[0]);
}
//org.springframework.boot.SpringApplication#getSpringFactoriesInstances(java.lang.Class<T>)
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
//获取类加载器
ClassLoader classLoader = this.getClassLoader();
//获取所有类名 SpringFactoriesLoader.loadFactoryNames(type, classLoader) 重点关注一下
//SpringFactoriesLoader.loadFactoryNames(type, classLoader) 就是根据接口名字 获取实现类的名称
Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
//根据获取到的所有类名获取实例对象
List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
//排序
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
启动监听器
SpringApplicationRunListeners#starting 启动监听器,其调用的是 EventPublishingRunListener#starting 方法,最终调用的是 SimpleApplicationEventMulticaster#multicastEvent 方法来发布监听事件。
java
//org.springframework.boot.SpringApplicationRunListeners#starting
void starting() {
//迭代遍历所有监听器
Iterator var1 = this.listeners.iterator();
while(var1.hasNext()) {
SpringApplicationRunListener listener = (SpringApplicationRunListener)var1.next();
//调用 事件发布运行监听器 EventPublishingRunListener#starting 方法
listener.starting();
}
}
//org.springframework.boot.context.event.EventPublishingRunListener#starting
public void starting() {
//调用 简单应用程序事件多播器 SimpleApplicationEventMulticaster#multicastEvent 多播事件 也就是启动监听事件
this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}
//org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent(org.springframework.context.ApplicationEvent)
public void multicastEvent(ApplicationEvent event) {
//调用 简单应用程序事件多播器 SimpleApplicationEventMulticaster#multicastEvent
this.multicastEvent(event, this.resolveDefaultEventType(event));
}
//org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent(org.springframework.context.ApplicationEvent, org.springframework.core.ResolvableType)
public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) {
//解析事件类型
ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event);
//获取线程池
Executor executor = this.getTaskExecutor();
//迭代遍历监听器
Iterator var5 = this.getApplicationListeners(event, type).iterator();
while(var5.hasNext()) {
//监听器
ApplicationListener<?> listener = (ApplicationListener)var5.next();
if (executor != null) {
//线程池异步发送监听事件
executor.execute(() -> {
this.invokeListener(listener, event);
});
} else {
//同步发送监听事件
this.invokeListener(listener, event);
}
}
}
加载环境配置
SpringApplication#prepareEnvironment 方法就是获取一个环境对象,Environment 接口提供了三种实现,标准环境 StandardEnvironment、web 应用环境 StandardServletEnvironment、响应式 web 应用环境 StandardReactiveWebEnvironment。
java
//org.springframework.boot.SpringApplication#prepareEnvironment
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
//获取或创建 配置环境对象
ConfigurableEnvironment environment = this.getOrCreateEnvironment();
//配置环境
this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());
ConfigurationPropertySources.attach((Environment)environment);
//发布环境已准备事件
listeners.environmentPrepared(bootstrapContext, (ConfigurableEnvironment)environment);
DefaultPropertiesPropertySource.moveToEnd((ConfigurableEnvironment)environment);
this.configureAdditionalProfiles((ConfigurableEnvironment)environment);
//环境配置绑定到 Spring 应用程序上
this.bindToSpringApplication((ConfigurableEnvironment)environment);
//是否是自定义环境
if (!this.isCustomEnvironment) {
environment = (new EnvironmentConverter(this.getClassLoader())).convertEnvironmentIfNecessary((ConfigurableEnvironment)environment, this.deduceEnvironmentClass());
}
ConfigurationPropertySources.attach((Environment)environment);
//返回环境配置对象
return (ConfigurableEnvironment)environment;
}
//org.springframework.boot.SpringApplication#getOrCreateEnvironment
private ConfigurableEnvironment getOrCreateEnvironment() {
//环境为空判断
if (this.environment != null) {
//不为空 直接返回
return this.environment;
} else {
//为空 根据项目类型创建不同的环境对象
switch(this.webApplicationType) {
case SERVLET:
//响应式 web 应用环境
return new StandardServletEnvironment();
case REACTIVE:
//web 应用环境
return new StandardReactiveWebEnvironment();
default:
//标准环境
return new StandardEnvironment();
}
}
}
创建应用程序上下文
创建容器会调用 ApplicationContextFactory#create 方法,根据项目类型去创建容器,项目类型前文已经多次赘述,这里不再分析了。
java
protected ConfigurableApplicationContext createApplicationContext() {
return this.applicationContextFactory.create(this.webApplicationType);
}
package org.springframework.boot;
import java.util.function.Supplier;
import org.springframework.beans.BeanUtils;
import org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
@FunctionalInterface
public interface ApplicationContextFactory {
ApplicationContextFactory DEFAULT = (webApplicationType) -> {
try {
switch(webApplicationType) {
case SERVLET:
return new AnnotationConfigServletWebServerApplicationContext();
case REACTIVE:
return new AnnotationConfigReactiveWebServerApplicationContext();
default:
return new AnnotationConfigApplicationContext();
}
} catch (Exception var2) {
throw new IllegalStateException("Unable create a default ApplicationContext instance, you may need a custom ApplicationContextFactory", var2);
}
};
ConfigurableApplicationContext create(WebApplicationType webApplicationType);
static ApplicationContextFactory ofContextClass(Class<? extends ConfigurableApplicationContext> contextClass) {
return of(() -> {
return (ConfigurableApplicationContext)BeanUtils.instantiateClass(contextClass);
});
}
static ApplicationContextFactory of(Supplier<ConfigurableApplicationContext> supplier) {
return (webApplicationType) -> {
return (ConfigurableApplicationContext)supplier.get();
};
}
}
准备上下文,完成各种初始化操作
SpringApplication#prepareContext 方法主要是做一些容器刷新之前的动作,完成各类初始化动作,其中有一个比较核心的操作,把启动类注入容器,为后续开启自动化配置奠定了基础。
java
//org.springframework.boot.SpringApplication#prepareContext
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
//设置上下文环境
context.setEnvironment(environment);
//执行上下文后处理
this.postProcessApplicationContext(context);
//执行 ApplicationContextInitializer
this.applyInitializers(context);
//发布上下文准备好的监听事件
listeners.contextPrepared(context);
//关闭引导上下文
bootstrapContext.close(context);
if (this.logStartupInfo) {
this.logStartupInfo(context.getParent() == null);
this.logStartupProfileInfo(context);
}
//获取 ApplicationContextInitializer
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
//注册单例bean springApplicationArguments 容器指定的参数封装成 bean 注入容器
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
//将 Banner 封装成 bean 注入到容器中
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
//是否是 DefaultListableBeanFactory 类型的容器
if (beanFactory instanceof DefaultListableBeanFactory) {
//是 强行覆盖
((DefaultListableBeanFactory)beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
//是否懒加载
if (this.lazyInitialization) {
//加 懒加载 beanFactory 处理器
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
//获取启动类指定的参数
Set<Object> sources = this.getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
//加载启动类 将启动类注入容器
this.load(context, sources.toArray(new Object[0]));
//发布容器加载完成事件
listeners.contextLoaded(context);
}
刷新上下文
刷新上下文,最终调用到 AbstractApplicationContext#refresh 方法,也就是 Spirng 容器启动的核心方法。
AbstractApplicationContext#refresh 方法传送门:
深入理解 Spring IOC 底层实现机制(refresh 方法源码分析)
java
//org.springframework.boot.SpringApplication#refreshContext
private void refreshContext(ConfigurableApplicationContext context) {
//判斷是否注册关闭钩子函数 默认注册
if (this.registerShutdownHook) {
try {
//注册关闭钩子函数
context.registerShutdownHook();
} catch (AccessControlException var3) {
}
}
//继续调用 refresh 方法
this.refresh((ApplicationContext)context);
}
//org.springframework.boot.SpringApplication#refresh(org.springframework.context.ApplicationContext)
@Deprecated
protected void refresh(ApplicationContext applicationContext) {
Assert.isInstanceOf(ConfigurableApplicationContext.class, applicationContext);
//继续调用 refresh 方法
this.refresh((ConfigurableApplicationContext)applicationContext);
}
//org.springframework.boot.SpringApplication#refresh(org.springframework.context.ConfigurableApplicationContext)
protected void refresh(ConfigurableApplicationContext applicationContext) {
//调用 AbstractApplicationContext#refresh 方法
applicationContext.refresh();
}
//org.springframework.context.support.AbstractApplicationContext#refresh
//IOC 核心方法
public void refresh() throws BeansException, IllegalStateException {
//防止 启动和销毁并发执行
synchronized(this.startupShutdownMonitor) {
//启动步骤记录
StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
//刷新准备工作
this.prepareRefresh();
//创建 beanFactory 将配置文件解析为 beandefiniton 对象 注册到 beanFactory 中
//ConfigurableListableBeanFactory是一个接口 真正干活的是 DefaultListableBeanFactory
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
//beanFactory 预处理 主要是设置 beanFactory 类加载器及忽略一些自动装配 设置一些默认bena
this.prepareBeanFactory(beanFactory);
try {
//beanFactory 后置处理 准备完成后需要做的事情 默认是空实现 是一个扩展点 可以子类去实现
this.postProcessBeanFactory(beanFactory);
//启动 bean post-process 步骤记录
StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
//回调 beanFactory 后置处理器 beanFactoryPostProcessors 的 postProcessorsBeanFactory 方法 (也可以说是激活 beanFactoryPostPorcess)
this.invokeBeanFactoryPostProcessors(beanFactory);
//注册beanPostProcessors bean 后置处理器(注意上面是beanFactory后置处理器) 在bean 初始化之前之后执行
this.registerBeanPostProcessors(beanFactory);
//bean 后置处理器步骤结束
beanPostProcess.end();
//初始化国际化资源
this.initMessageSource();
//初始化应用程序事件多播器
this.initApplicationEventMulticaster();
//默认是空方法 可以子类重写 自己进行扩展
this.onRefresh();
//注册监听器
this.registerListeners();
//初始化单例bean(非懒加载)
this.finishBeanFactoryInitialization(beanFactory);
//完成后刷新 包括清空资源 发布事件等
this.finishRefresh();
} catch (BeansException var10) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var10);
}
//销毁ben
this.destroyBeans();
//取消刷新
this.cancelRefresh(var10);
throw var10;
} finally {
this.resetCommonCaches();
contextRefresh.end();
}
}
}
刷新后操作
SpringApplication#afterRefresh 方法是个模板方法,默认空实现,可以自己去扩展。
java
//org.springframework.boot.SpringApplication#afterRefresh
protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) {
}
SpringApplication#callRunners 方法分析
SpringApplication#callRunners 调用 ApplicationRunner 和 CommandLineRunner 的实现类,也就是平时我们自定义一些实现了 Runner 接口的类,在项目启动时候执行。
java
//org.springframework.boot.SpringApplication#callRunners
private void callRunners(ApplicationContext context, ApplicationArguments args) {
//存储所有的 Runner
List<Object> runners = new ArrayList();
//获取所有的 ApplicationRunner 的实现类 加入到 runners 中
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
//获取所有的 CommandLineRunner 的实现类 加入到 runners 中
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
//对所有 Runner 排序
AnnotationAwareOrderComparator.sort(runners);
//迭代遍历
Iterator var4 = (new LinkedHashSet(runners)).iterator();
while(var4.hasNext()) {
Object runner = var4.next();
//ApplicationRunner 类型 runner
if (runner instanceof ApplicationRunner) {
//调用 runner 的 run 方法
this.callRunner((ApplicationRunner)runner, args);
}
//CommandLineRunner 类型 runner
if (runner instanceof CommandLineRunner) {
//调用 runner 的 run 方法
this.callRunner((CommandLineRunner)runner, args);
}
}
}
//org.springframework.boot.SpringApplication#callRunner(org.springframework.boot.CommandLineRunner, org.springframework.boot.ApplicationArguments)
private void callRunner(CommandLineRunner runner, ApplicationArguments args) {
try {
//执行 runner 的 run 方法 也就是我们自己定义的 runner 的业务方法
runner.run(args.getSourceArgs());
} catch (Exception var4) {
throw new IllegalStateException("Failed to execute CommandLineRunner", var4);
}
}
至此,Spring Boot 的启动流程分析完毕,希望可以帮助到有需要的小伙伴。
如有不正确的地方请各位指出纠正。