运行流程详细代码
public ConfigurableApplicationContext run(String... args) {
//初始化计时器
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
//初始化异常报告的集合
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
//设置默认属性(不重要)
this.configureHeadlessProperty();
//下面两根方法是重点方法
SpringApplicationRunListeners listeners = this.getRunListeners(args);
//上面的listeners从spring.properties加载出来只有一个EventPublishingRunListener
listeners.starting();
Collection exceptionReporters;
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//构造容器环境
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
//设置需要忽略的bean spring.Beaninfo.ignore
this.configureIgnoreBeanInfo(environment);
//打印banner
Banner printedBanner = this.printBanner(environment);
//创建容器
context = this.createApplicationContext();
//实例化SpringBootExceptionReporter.class,用来支持报告关于启动的错误
exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
//准备容器
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
//刷新容器
this.refreshContext(context);
//刷新容器后的扩展接口
this.afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
}
listeners.started(context);
this.callRunners(context, applicationArguments);
} catch (Throwable var10) {
this.handleRunFailure(context, var10, exceptionReporters, listeners);
throw new IllegalStateException(var10);
}
try {
listeners.running(context);
return context;
} catch (Throwable var9) {
this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var9);
}
}
阶段一:回调支持应用启动的listenters
1,getRunListeners()方法详解
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
//getSpringFactoriesInstances:从spring.factory中获取key为SpringApplicationRunListener的key-value对,并对value进行实例化
return new SpringApplicationRunListeners(logger,
getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}
上面的getSpringFactoriesInstances会实例化下面这个类:
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
private final SpringApplication application;
private final String[] args;
private final SimpleApplicationEventMulticaster initialMulticaster;
//通过构造方法实例化该类
public EventPublishingRunListener(SpringApplication application, String[] args) {
//传入之前构造流程中的生成的:SpringApplication对象
this.application = application;
this.args = args;
this.initialMulticaster = new SimpleApplicationEventMulticaster();
//将之前加载的11个listeners放入到initialMulticaster缓存中
for (ApplicationListener<?> listener : application.getListeners()) {
//initialMulticaster实际上是个set集合
this.initialMulticaster.addApplicationListener(listener);
}
}
starting()方法详解
由于扫描spring.properties加载出来只有一个EventPublishingRunListener
所有下面会走EventPublishingRunListener的starting方法
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
................
@Override
public int getOrder() {
return 0;
}
//在上一个步骤中,已经将构造阶段初始化的11个listener保存到initialMulticaster的set集合中了
//新建ApplicationStartingEvent应用的启动事件
@Override
public void starting() {
this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}
...........
multicastEvent()方法详解
//ApplicationEvent:上一步新建的对象,保存了构造阶段的SpringApplication对象
//这个方法的功能是:从构造阶段中获取到11个listenes中招到支持应用启动事件的4个listeners,并逐个做回调,
public void multicastEvent(ApplicationEvent event) {
this.multicastEvent(event, this.resolveDefaultEventType(event));
}
public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event);
Executor executor = this.getTaskExecutor();
//获取支持应用启动事件的的listeners,经过这个方法之后,会从构建阶段中的11个listeners中获取到4个listeners
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);
}
}
}
阶段二:准备环境,回调在构建阶段涉及到环境准备的listeners,并完成环境变量的加载
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// Create and configure the environment
//获取或者创建一个环境,获取一些系统的环境变量和属性,例如:javahome,os标识等等
ConfigurableEnvironment environment = getOrCreateEnvironment();
//配置一些信息,比如支持命令行的属性信息(java调优中会在启动的命令行中添加一些调优命令)
configureEnvironment(environment, applicationArguments.getSourceArgs());
//下面这个方法不重要
ConfigurationPropertySources.attach(environment);
//从之前构造函数中拿到的11个listeners里面找到响应环境准备好之后的listeners事件,并触发对这个事件的处理
listeners.environmentPrepared(environment);
bindToSpringApplication(environment);
//截止到这里,所有涉及到环境准备的listeners已经回调完毕
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
deduceEnvironmentClass());
}
ConfigurationPropertySources.attach(environment);
//环境准备完毕
return environment;
}
getOrCreateEnvironment()接口详解:
private ConfigurableEnvironment getOrCreateEnvironment() {
//根据环境的不同,实例化不同的环境
if (this.environment != null) {
return this.environment;
}
switch (this.webApplicationType) {
case SERVLET:
return new StandardServletEnvironment();
case REACTIVE:
return new StandardReactiveWebEnvironment();
default:
return new StandardEnvironment();
}
}
上面方法会一层层调用父类的构造方法,直到调用到下面这个类的构造方法
public class StandardServletEnvironment extends StandardEnvironment implements ConfigurableWebEnvironment {
public static final String SERVLET_CONTEXT_PROPERTY_SOURCE_NAME = "servletContextInitParams";
public static final String SERVLET_CONFIG_PROPERTY_SOURCE_NAME = "servletConfigInitParams";
public static final String JNDI_PROPERTY_SOURCE_NAME = "jndiProperties";
public StandardServletEnvironment() {
}
protected void customizePropertySources(MutablePropertySources propertySources) {
propertySources.addLast(new StubPropertySource("servletConfigInitParams"));
propertySources.addLast(new StubPropertySource("servletContextInitParams"));
if (JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) {
propertySources.addLast(new JndiPropertySource("jndiProperties"));
}
super.customizePropertySources(propertySources);
}
下面重点就是这个方法:customizePropertySources()
protected void customizePropertySources(MutablePropertySources propertySources) {
//获取系统的一些属性信息,比如虚拟机版本,os标识等等
propertySources.addLast(new PropertiesPropertySource("systemProperties", this.getSystemProperties()));
//获取系统的一些环境变量:java_home.....
propertySources.addLast(new SystemEnvironmentPropertySource("systemEnvironment", this.getSystemEnvironment()));
}
阶段三:创建容器(类似于spring的ioc容器)
这块代码比较复杂,总结来讲就是:
- 基本属性赋值,重点是beanFactory、reader、scanner和environment这四个属性
- reader的创建过程中给beanFactory中的beanDefinitionMap、beanDefintionNames这两个属性设置5个值,并且自己的registry属性引用了应用上下文对象,scanner的registry也引用了应用上下文对象
- 应用上下文中的environment是创建应用上下文过程中新创建的环境,并不是我们之前run方法创建好的环境。
//根据webApplicationType推断并实例化 ioc容器类型,此处是实例化的SERVLET容器
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
switch (this.webApplicationType) {
case SERVLET:
contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
break;
case REACTIVE:
contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
break;
default:
contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
}
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
}
}
return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
}
阶段四:应用上下文创建和准备上下文
准备ioc容器
spring上下文前置处理,
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
postProcessApplicationContext(context);
//应用上下文的初始化器,执行一些初始化操作
applyInitializers(context);
listeners.contextPrepared(context);
//打印启动日志信息
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans注册两个特殊的单例
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
// Load the sources
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[0]));
listeners.contextLoaded(context);
}
总结 一下:
详细流程:
## Spring启动流程分为构造流程和运行流程
构造阶段
1. 主要是扫描所有spring.factory文件中的key为ApplicationContextInitializer和ApplicationListener,并进行实例化
运行阶段
2. 启动计时器
3. 初始化异常报告的集合
4. 准备环境
4.1 获取ConfigurationEnvironment:获取系统属性,javaHome,OS标识,系统的一些属性.....
4.2 回调在构造阶段中加载的监听器中支持环境准备阶段的监听器
5,设置忽略的Bean:spring.beaninfo,ignore
6,打印banner信息
7,创建容器:根据环境不同,选择不同的容器,并设置一些基本属性,reader,scanner,environment....
8,准备IOC容器,初始化上下文
9,刷新容器
10,刷新容器后的扩展接口
简单流程:
第一步:获取并启动监听器
第二步:构造容器环境
第三步:创建容器
第四步:实例化SpringBootExceptionReporter.class,用来支持报告关于启动的错误
第五步:准备容器
第六步:刷新容器
第七步:刷新容器后的扩展接口