用过 SpringBoot 的同学都知道,其程序的启动类是在一个main
方法中调用SpringApplication.run
方法执行的,如:
@SpringBootApplication
public class SpringApplicationBootstrap {
public static void main(String[] args) {
SpringApplication.run(SpringApplicationBootstrap.class, args);
}
}
那么,这里面到底做了什么呢?本篇文章将深入源码,带你一起探究底层实现。
SpringApplication 初始化阶段
进入到SpringApplication.run
方法,其首先会创建一个SpringApplication
对象,我们看其构造函数:
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
// primarySources 为 run 方法传入的引导类
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 推断web应用类
this.webApplicationType = deduceWebApplicationType();
// 初始化 initializers 属性
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
// 初始化监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 推断应用引导类
this.mainApplicationClass = deduceMainApplicationClass();
}
我们先看推断web应用类的方法deduceWebApplicationType()
:
private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet",
"org.springframework.web.context.ConfigurableWebApplicationContext" };
private static final String REACTIVE_WEB_ENVIRONMENT_CLASS = "org.springframework."
+ "web.reactive.DispatcherHandler";
private static final String MVC_WEB_ENVIRONMENT_CLASS = "org.springframework."
+ "web.servlet.DispatcherServlet";
private WebApplicationType deduceWebApplicationType() {
if (ClassUtils.isPresent(REACTIVE_WEB_ENVIRONMENT_CLASS, null)
&& !ClassUtils.isPresent(MVC_WEB_ENVIRONMENT_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
for (String className : WEB_ENVIRONMENT_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
return WebApplicationType.SERVLET;
}
根据 classpath 下是否存在某个特征类来决定是否应该创建一个为 Web 应用使用的ApplicationContext
类型。具体判断为:
如果仅存在 Reactive 的包,则为
WebApplicationType.REACTIVE
类型;
如果 Servlet 和 Reactive的包都不存在,则为WebApplicationType.NONE
类型;
其他情况都为WebApplicationType.SERVLET
类型。
接下来我们看初始化initializers
属性的过程,其通过getSpringFactoriesInstances(ApplicationContextInitializer.class)
方法获取初始化器:
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
// Use names and ensure unique to protect against duplicates
Set<String> names = new LinkedHashSet<>(
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
该方法流程为:
- 通过
SpringFactoriesLoader.loadFactoryNames(type, classLoader)
方法,在 META-INF/spring.factories 文件下查找ApplicationContextInitializer
类型对应的资源名称。 - 实例化上面的资源信息(初始化器)。
- 对初始化器根据
Ordered
接口或者@Order
注解进行排序。
同理,初始化listeners
监听器也是类似的,这里不再累赘。
SpringApplication 初始化阶段的最后一步是推断引导类deduceMainApplicationClass()
:
private Class<?> deduceMainApplicationClass() {
try {
StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
for (StackTraceElement stackTraceElement : stackTrace) {
if ("main".equals(stackTraceElement.getMethodName())) {
return Class.forName(stackTraceElement.getClassName());
}
}
}
catch (ClassNotFoundException ex) {
// Swallow and continue
}
return null;
}
其将调用栈中main
方法所在的类作为引导类。
SpringApplication 运行阶段
SpringApplication 运行阶段属于核心过程,完全围绕 run(String...) 方法展开。该过程结合初始化阶段完成的状态,进一步完善运行时所需要准备的资源,随后启动 Spring 应用上下文。在此期间伴随着 Spring Boot 和 Spring 事件的触发,形成完整的 SpringApplication 生命周期。因此,下面将围绕以下三个子议题进行讨论。
- SpringApplication 准备阶段
- ApplicationContext 启动阶段
- ApplicationContext 启动后阶段
1. SpringApplication 准备阶段
本阶段属于 ApplicationContext 启动阶段的前一阶段,设计的范围从 run(String...)
方法调用开始,到refreshContext(ConfigurableApplicationContext)
调用前:
public ConfigurableApplicationContext run(String... args) {
//记录程序运行时间
StopWatch stopWatch = new StopWatch();
stopWatch.start();
//Spring 应用的上下文
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
// 获取 SpringApplicationRunListeners
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
// 创建 ApplicationArguments 对象
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
// 加载属性配置
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
// 处理需要忽略的Bean
configureIgnoreBeanInfo(environment);
// 打印 banner
Banner printedBanner = printBanner(environment);
// 创建 Spring 应用上下文
context = createApplicationContext();
// 实例化 SpringBootExceptionReporter,用来报告关于启动过程中的错误
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
// 应用上下文的准备阶段
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
// 刷新应用上下文(自动装配,初始化 IOC 容器)
refreshContext(context);
...
}
}
- getRunListeners(args) 方法:
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
SpringApplicationRunListener.class, types, this, args));
}
该方法会通过getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args)
方法,获取 META-INF/spring.factories 文件下SpringApplicationRunListener
对应的资源,并且实例化这些资源:
# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
我们发现,其有且仅有一个实现类EventPublishingRunListener
:
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
private final SpringApplication application;
private final String[] args;
private final SimpleApplicationEventMulticaster initialMulticaster;
public EventPublishingRunListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
this.initialMulticaster = new SimpleApplicationEventMulticaster();
for (ApplicationListener<?> listener : application.getListeners()) {
this.initialMulticaster.addApplicationListener(listener);
}
}
@Override
public int getOrder() {
return 0;
}
@Override
public void starting() {
this.initialMulticaster.multicastEvent(
new ApplicationStartingEvent(this.application, this.args));
}
@Override
public void environmentPrepared(ConfigurableEnvironment environment) {
this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(
this.application, this.args, environment));
}
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
}
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
for (ApplicationListener<?> listener : this.application.getListeners()) {
if (listener instanceof ApplicationContextAware) {
((ApplicationContextAware) listener).setApplicationContext(context);
}
context.addApplicationListener(listener);
}
this.initialMulticaster.multicastEvent(
new ApplicationPreparedEvent(this.application, this.args, context));
}
@Override
public void started(ConfigurableApplicationContext context) {
context.publishEvent(
new ApplicationStartedEvent(this.application, this.args, context));
}
@Override
public void running(ConfigurableApplicationContext context) {
context.publishEvent(
new ApplicationReadyEvent(this.application, this.args, context));
}
@Override
public void failed(ConfigurableApplicationContext context, Throwable exception) {
ApplicationFailedEvent event = new ApplicationFailedEvent(this.application,
this.args, context, exception);
if (context != null && context.isActive()) {
// Listeners have been registered to the application context so we should
// use it at this point if we can
context.publishEvent(event);
}
else {
// An inactive context may not have a multicaster so we use our multicaster to
// call all of the context's listeners instead
if (context instanceof AbstractApplicationContext) {
for (ApplicationListener<?> listener : ((AbstractApplicationContext) context)
.getApplicationListeners()) {
this.initialMulticaster.addApplicationListener(listener);
}
}
this.initialMulticaster.setErrorHandler(new LoggingErrorHandler());
this.initialMulticaster.multicastEvent(event);
}
}
...
}
在实例化EventPublishingRunListener
的过程中,会给它最重要的属性initialMulticaster
赋值,其类型是SimpleApplicationEventMulticaster
。接着遍历 SpringApplication 初始化阶段的listeners
监听器集合,将监听器存入其关联的ListenerRetriever#applicationListeners
属性中。
了解 Spring 事件监听机制的同学应该对SimpleApplicationEventMulticaster
不陌生,它是ApplicationEvent
事件的发布者。Spring Boot 的事件监听机制也是如出一辙,具体可参考我的另一篇文章 深入理解 Spring 的事件发布监听机制。
于是接下来调用listeners.starting()
方法就会通过其内部的initialMulticaster
属性发布ApplicationStartingEvent
事件。
- prepareEnvironment(listeners,applicationArguments) 方法:
加载属性配置。执行完成后,所有的environment
的属性都会加载进来,包括 application.properties 和外部的属性配置。
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// 创建 ConfigurableEnvironment 对象
ConfigurableEnvironment environment = getOrCreateEnvironment();
// 配置 ConfigurableEnvironment
configureEnvironment(environment, applicationArguments.getSourceArgs());
// 发布 ApplicationEnvironmentPreparedEvent 事件
listeners.environmentPrepared(environment);
// 将 ConfigurableEnvironment 绑定到 SpringApplication 中
bindToSpringApplication(environment);
if (this.webApplicationType == WebApplicationType.NONE) {
environment = new EnvironmentConverter(getClassLoader())
.convertToStandardEnvironmentIfNecessary(environment);
}
ConfigurationPropertySources.attach(environment);
return environment;
}
大致流程为:
- 创建
ConfigurableEnvironment
对象。 - 配置
environment
变量。 - 发布
ApplicationEnvironmentPreparedEvent
事件。
其对应的监听器为ConfigFileApplicationListener
,当接收到上面的事件时,加载并实例化 “META-INF/spring.factories” 文件中EnvironmentPostProcessor
类型的实现类,遍历并执行其postProcessEnvironment
方法。值得注意的是,ConfigFileApplicationListener
自身也是EnvironmentPostProcessor
的实现类,于是也会执行其postProcessEnvironment
方法:
public void postProcessEnvironment(ConfigurableEnvironment environment,
SpringApplication application) {
// 将配置文件信息添加到 environment 中
addPropertySources(environment, application.getResourceLoader());
configureIgnoreBeanInfo(environment);
// 将 environment 绑定到 Spring 应用上下文中
bindToSpringApplication(environment, application);
}
该方法的目的是,加载配置文件信息至enviroment
,并将enviroment
绑定到 Spring 应用上下文中。
当我们需要在配置文件加载完成之后做一些事情的话,我们就可以自定义一个EnvironmentPostProcessor
的实现类,操作逻辑写在postProcessEnvironment
方法中,当然,别忘了在你的 “META-INF/spring.factories” 文件中加上配置。
- 绑定
environment
到SpringApplication
上。
- createApplicationContext 方法
该方法会根据webApplicationType
类型,创建不同的ConfigurableApplicationContext
Spring 应用上下文:
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
switch (this.webApplicationType) {
case SERVLET:
contextClass = Class.forName(DEFAULT_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);
}
我们以 SERVLET 类型为例,它会创建AnnotationConfigServletWebServerApplicationContext
应用上下文实例。
- 获取 Spring 异常报告器
getSpringFactoriesInstances(SpringBootExceptionReporter.class,new Class[] { ConfigurableApplicationContext.class }, context)
方法,获取 META-INF/spring.factories 文件下类型为SpringBootExceptionReporter
的资源实例:
# Error Reporters
org.springframework.boot.SpringBootExceptionReporter=\
org.springframework.boot.diagnostics.FailureAnalyzers
其实现类有且仅有一个,即FailureAnalyzers
。
- prepareContext 方法
Spring 应用上下文启动前的准备工作:
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
//设置 context 的 environment 属性
context.setEnvironment(environment);
// Spring 应用上下文的后置处理
postProcessApplicationContext(context);
// 运用 Spring 应用上下文初始化器
applyInitializers(context);
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
context.getBeanFactory().registerSingleton("springApplicationArguments",
applicationArguments);
if (printedBanner != null) {
context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
}
// Load the sources
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
// 加载 BeanDefinition
load(context, sources.toArray(new Object[0]));
listeners.contextLoaded(context);
}
大致流程为:
- 给
context
的属性做赋值,如设置环境变量,调用初始化器来初始化context
。 - 获取所有配置源信息,包括 Configuration Class、类名、包名及Spring XML 配置资源路径信息。
- 加载 Spring 应用上下文配置源。将
BeanDefinition
加载到context
中。 - 发布上下文已准备事件
ApplicationPreparedEvent
。
这里,我们要着重看第三步load(context, sources.toArray(new Object[0]))
:
protected void load(ApplicationContext context, Object[] sources) {
if (logger.isDebugEnabled()) {
logger.debug(
"Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
}
BeanDefinitionLoader loader = createBeanDefinitionLoader(
getBeanDefinitionRegistry(context), sources);
if (this.beanNameGenerator != null) {
loader.setBeanNameGenerator(this.beanNameGenerator);
}
if (this.resourceLoader != null) {
loader.setResourceLoader(this.resourceLoader);
}
if (this.environment != null) {
loader.setEnvironment(this.environment);
}
loader.load();
}
该方法将 Spring 应用上下文转载的任务交给了BeanDefinitionLoader
:
class BeanDefinitionLoader {
private final Object[] sources;
private final AnnotatedBeanDefinitionReader annotatedReader;
private final XmlBeanDefinitionReader xmlReader;
private BeanDefinitionReader groovyReader;
private final ClassPathBeanDefinitionScanner scanner;
private ResourceLoader resourceLoader;
...
}
BeanDefinitionLoader
组合了多个属性,第一个属性为SpringApplication#getAllSources()
方法返回值,而属性annotatedReader
、xmlReader
、groovyReader
分别为注解驱动实现AnnotatedBeanDefinitionReader
、XML 配置实现XmlBeanDefinitionReader
和 Groovy 实现GroovyBeanDefinitionReader
。其中AnnotatedBeanDefinitionReader
与ClassPathBeanDefinitionScanner
配合,形成AnnotationConfigApplicationContext
扫描和注册配置类的基础,随后这些配置类被解析为 Bean 定义BeanDefinition
:
public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {
private final AnnotatedBeanDefinitionReader reader;
private final ClassPathBeanDefinitionScanner scanner;
/**
* Create a new AnnotationConfigApplicationContext that needs to be populated
* through {@link #register} calls and then manually {@linkplain #refresh refreshed}.
*/
public AnnotationConfigApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
...
public void register(Class<?>... annotatedClasses) {
Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");
this.reader.register(annotatedClasses);
}
public void scan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
this.scanner.scan(basePackages);
}
...
}
不难看出,Spring Boot 中的BeanDefinitionLoader
是以上BeanDefinition
读取的综合实现。当其load()
方法调用时,这些BeanDefinitionReader
类型的属性各司其职,为 Spring 应用上下文从不同的配置源装载 Spring Bean 定义(BeanDefinition)。
需要注意的是,load()
方法仅仅是装载SpringApplication#primarySources
的资源,即启动类的资源,而不会加载其他配置源的BeanDefinition
。
public Set<Object> getAllSources() {
Set<Object> allSources = new LinkedHashSet<>();
if (!CollectionUtils.isEmpty(this.primarySources)) {
allSources.addAll(this.primarySources);
}
if (!CollectionUtils.isEmpty(this.sources)) {
allSources.addAll(this.sources);
}
return Collections.unmodifiableSet(allSources);
}
上面的SpringApplication#sources
是没有值的,于是只会加载启动类的资源,其他配置源的加载操作是在 ApplicationContext 启动阶段的AbstractApplicationContext#invokeBeanFactoryPostProcessors
的方法中执行的,下面会讲到。
装载完启动类的BeanDefinition
到 Spring 应用上下文之后,就调用listeners.contextLoaded(context)
方法,发布 Spring 应用上下文已准备ApplicationPreparedEvent
事件,以结束 SpringApplication 准备阶段。
2. ApplicationContext 启动阶段
本阶段的执行由refreshContext(ConfigurableApplicationContext)
完成,其核心方法是AbstractApplicationContext#refresh
:
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
随着该方法的执行,Spring Boot 核心特性也随之启动,如组件自动装配、嵌入式容器启动。了解过 Spring Boot 自动装配机制的同学应该知道(如不清楚,请参考我的另一篇文章 Spring Boot 自动装配),在根据应用类型创建不同的 Spring 应用上下文的方法createApplicationContext()
中,会实例化AnnotatedBeanDefinitionReader
对象,该对象的构造方法中,会将ConfigurationClassPostProcessor
封装成 Spring Bean 定义(BeanDefinition),并将其注入到 Ioc 容器DefaultListableBeanFactory
(其实现了BeanDefinitionRegistry
,具有注入BeanDefinition
的功能)中。于是,在该阶段的invokeBeanFactoryPostProcessors(beanFactory)
方法中,就会取出ConfigurationClassPostProcessor
对象,随后调用其postProcessBeanFactory(beanFactory)
方法进行装配工作。
- AbstractApplicationContext#postProcessBeanFactory
对于 Web 类型为 Servlet 时,这里的AbstractApplicationContext
为AnnotationConfigServletWebServerApplicationContext
,它除了添加beanPostProcessor
之外,还有加载 Spring Bean 定义(BeanDefinition)到 Spring 上下文的操作。
@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
super.postProcessBeanFactory(beanFactory);
if (this.basePackages != null && this.basePackages.length > 0) {
this.scanner.scan(this.basePackages);
}
if (!this.annotatedClasses.isEmpty()) {
this.reader.register(ClassUtils.toClassArray(this.annotatedClasses));
}
}
这里似乎和我们上文讲的 Spring Bean 的加载操作是在invokeBeanFactoryPostProcessors
有冲突,其实在判断 Web 类型时,生成的AbstractApplicationContext
实例是无参构造,以AnnotationConfigServletWebServerApplicationContext
为例:
public AnnotationConfigServletWebServerApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
故AnnotationConfigServletWebServerApplicationContext#annotatedClasses
和AnnotationConfigServletWebServerApplicationContext#basePackages
的属性值都为null。故不会走postProcessBeanFactory
中的加载 Spring bean 的操作。
- invokeBeanFactoryPostProcessors(beanFactory)
这里才是真正将 Spring Bean 定义BeanDefinition
加载到 Spring 上下文的操作,同时也是激活自动装配的入口。 - registerBeanPostProcessors(beanFactory)
注册 BeanPostProcessor,用来干预 Spring Bean 的初始化操作,在 Spring Bean 的初始化之后,做一些额外的操作。 - finishBeanFactoryInitialization(beanFactory)
实例化容器中未设置懒加载的类。
3. ApplicationContext 启动后阶段
实际上,SpringApplication#afterRefresh
方法并未给 Spring 应用上下文启动后阶段提供实现,而是将其交给开发人员自行扩展:
protected void afterRefresh(ConfigurableApplicationContext context,
ApplicationArguments args) {
}
所有,直接跳过该步,接下来调用listeners.started(context)
方法,发布 Spring 应用上下文已启动ApplicationStartedEvent
事件。
该阶段最后,调用callRunners(context, applicationArguments)
方法,来调用实现了CommandLineRunner
或者ApplicationRunner
接口的类的 run 方法,得以满足需要在 Spring 应用上下文完全准备完毕后,执行一些操作的场景。
private void callRunners(ApplicationContext context, ApplicationArguments args) {
List<Object> runners = new ArrayList<>();
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
AnnotationAwareOrderComparator.sort(runners);
for (Object runner : new LinkedHashSet<>(runners)) {
if (runner instanceof ApplicationRunner) {
callRunner((ApplicationRunner) runner, args);
}
if (runner instanceof CommandLineRunner) {
callRunner((CommandLineRunner) runner, args);
}
}
}
总结
至此,SpringApplciation.run 方法的执行流程已经讲解完毕。下面我们来整理一下大体的步骤:
- 初始化 SpringApplication 实例:决定web应用类型、加载初始化器和监听器、推断 main 方法的定义类。
- 通过 SpringFactoriesLoader 加载的 SpringApplicationRunListener,调用它们的 started 方法。
- 创建并配置当前 Spring Boot 应用将要使用的 Environment,如 applocation.properties 文件和外部配置。
- 根据 Web 服务类型创建不同的 Spring 应用上下文,并将之前准备好的 Environment 设置给 Spring 应用上下文 ApplicationContext 使用。
- 遍历初始化器,对 ApplicationContext 进行初始化操作。
- 初始化上下文 refresh(),在
invokeBeanFactoryPostProcessors
中,加载所有资源,如 Configuration Class、类名、包名以及 Spring XML 配置资源路径,将所有 BeanDefinition 加载至 ApplicationContext,并进行自动装配,初始化 Ioc 容器等操作。 -
寻找当前 ApplicationContext 中是否注册有 CommandLineRunner 或者 ApplicationRunner,如果有,则遍历执行它们。