SpringBoot源码解析一

启动流程

1
2
3
4
5
6
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}

首先从启动类开始看起,main() 方法很简单,调用 SpringApplication 的静态方法run()。

1
2
3
4
public static ConfigurableApplicationContext run(Class<?>[] primarySources, 
String[] args) {
return new SpringApplication(primarySources).run(args);
}

实例化一个 SpringApplication 对象

1
2
3
public SpringApplication(Class<?>... primarySources) {
this(null, primarySources);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
//用Set<>保存传入的 DemoApplication.class(因为启动类可以传入多个class)
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
//应用类型:REACTIVE/NONE/SERVLET
this.webApplicationType = deduceWebApplicationType();
//设置初始化器
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
//设置监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 找到 main 函数所在的类,并设置到 SpringApplication
this.mainApplicationClass = deduceMainApplicationClass();
}

应用类型

看下 deduceWebApplicationType() 方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
private WebApplicationType deduceWebApplicationType() {
if (ClassUtils.isPresent(REACTIVE_WEB_ENVIRONMENT_CLASS, null)
&& !ClassUtils.isPresent(MVC_WEB_ENVIRONMENT_CLASS, null)
&& !ClassUtils.isPresent(JERSEY_WEB_ENVIRONMENT_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
for (String className : WEB_ENVIRONMENT_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
return WebApplicationType.SERVLET;
}

web 应用的类型有三个:

  1. REACTIVE

    当类路径包含 REACTIVE_WEB_ENVIRONMENT_CLASS 且不包含 MVC_WEB_ENVIRONMENT_CLASS 和 JERSEY_WEB_ENVIRONMENT_CLASS 相关的类时返回

  2. NONE

    当类路径不存在 WEB_ENVIRONMENT_CLASSES 相关的类时返回

  3. SERVLET

    当类路径存在 WEB_ENVIRONMENT_CLASSES 相关的类时返回

设置初始化器和监听器

1
2
3
4
5
//设置初始化器
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
//设置监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
1
2
3
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
return getSpringFactoriesInstances(type, new Class<?>[] {});
}

getSpringFactoriesInstances(type) 方法一层层调用,目的是从 “META-INF/spring.factories”文件读取 key 为 type 的 value 名称集合,然后创建对象,返回对象集合。这里从文件中获取的是如下部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 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.web.context.ServerPortInfoApplicationContextInitializer

# 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.ConfigFileApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener

然后调用 setInitializers 和 setListeners 方法设置 SpringApplication 的 变量 initializers 和 listeners

1
2
3
4
5
6
7
8
9
10
11
12
13
private List<ApplicationContextInitializer<?>> initializers;
private List<ApplicationListener<?>> listeners;

public void setInitializers(
Collection<? extends ApplicationContextInitializer<?>> initializers) {
this.initializers = new ArrayList<>();
this.initializers.addAll(initializers);
}

public void setListeners(Collection<? extends ApplicationListener<?>> listeners) {
this.listeners = new ArrayList<>();
this.listeners.addAll(listeners);
}

springApplication.run()

该方法创建并刷新一个新的 ApplicationContext,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
//会在 spring.factories 文件中寻找 SpringApplicationRunListener 对应的实现类的名字,并且利用反射构造实例 EventPublishingRunListener。
SpringApplicationRunListeners listeners = getRunListeners(args);
//会遍历 listeners 容器(ArrayList)里面所有的 SpringApplicationRunListener 对象的starting方法,其实就是调用 EventPublishingRunListener 的 starting() 方法。然后广播出去,让监听了 ApplicationStartingEvent 事件的监听器做相应处理。
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
//准备环境,然后广播出去,让监听了 ApplicationEnvironmentPreparedEvent 事件的监听器做相应处理。
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
//创建上下文,此时还未刷新。
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
//准备上下文,让监听了 ApplicationPreparedEvent 事件的监听器做相应处理。
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
//刷新上下文
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
//广播出去,让监听了 ApplicationStartedEvent 事件的监听器做相应处理。
listeners.started(context);
//执行各个自定义的 ApplicationRunner 和 CommandLineRunner
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
//广播出去,让监听了 ApplicationReadyEvent 事件的监听器做相应处理。
listeners.running(context);
}
catch (Throwable ex) {
//让监听了 ApplicationFailedEvent 事件的监听器做相应处理。
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}

我们依次来看下上面比较重要的几个地方:

获取 SpringApplicationRunListeners

1
SpringApplicationRunListeners listeners = getRunListeners(args);
1
2
3
4
5
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) 方法从 spring.factories 文件中找到 key 为 SpringApplicationRunListener 的 value集合,这里只有 EventPublishingRunListener 一个。然后实例化 EventPublishingRunListener 对象:

1
2
3
4
5
6
7
8
9
public EventPublishingRunListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
this.initialMulticaster = new SimpleApplicationEventMulticaster();
//遍历上面 setListeners 方法设置到 application 的变量 listeners 中的监听器
for (ApplicationListener<?> listener : application.getListeners()) {
this.initialMulticaster.addApplicationListener(listener);
}
}

然后据此实例化一个 SpringApplicationRunListeners 对象:

1
2
3
4
5
6
7
8
9
private final Log log;

private final List<SpringApplicationRunListener> listeners;

SpringApplicationRunListeners(Log log,
Collection<? extends SpringApplicationRunListener> listeners) {
this.log = log;
this.listeners = new ArrayList<>(listeners);
}

listeners.starting()

SpringApplicationRunListeners 的 starting 方法如下:

1
2
3
4
5
6
public void starting() {
//此处 listeners 中只有一个 EventPublishingRunListener 对象
for (SpringApplicationRunListener listener : this.listeners) {
listener.starting();
}
}

我们再看 EventPublishingRunListener 的 starting 方法:

1
2
3
4
public void starting() {
this.initialMulticaster.multicastEvent(
new ApplicationStartingEvent(this.application, this.args));
}

这个我们后面详细说,先知道这里广播一个 ApplicationStartingEvent 事件出去,让监听了该事件的监听器能够做相应的处理。后面的 environmentPrepared 方法、started 方法、running 方法也是类似。

创建 ConfigurableEnvironment 对象并配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// Create and configure the environment
ConfigurableEnvironment environment = getOrCreateEnvironment();
configureEnvironment(environment, applicationArguments.getSourceArgs());
//这里也是广播一个事件出去,让相关监听器做处理
listeners.environmentPrepared(environment);
//Bind the environment to the SpringApplication
bindToSpringApplication(environment);
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader())
.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
}
ConfigurationPropertySources.attach(environment);
return environment;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
private ConfigurableEnvironment getOrCreateEnvironment() {
if (this.environment != null) {
return this.environment;
}
//根据 webApplicationType 创建一个 ConfigurableEnvironment 对象
switch (this.webApplicationType) {
case SERVLET:
return new StandardServletEnvironment();
case REACTIVE:
return new StandardReactiveWebEnvironment();
default:
return new StandardEnvironment();
}
}
1
2
3
4
5
6
7
protected void configureEnvironment(ConfigurableEnvironment environment,
String[] args) {
//配置属性源
configurePropertySources(environment, args);
//配置Profiles
configureProfiles(environment, args);
}

创建上下文 ApplicationContext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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);
}

相关常量定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* The class name of application context that will be used by default for non-web
* environments.
*/
public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context."
+ "annotation.AnnotationConfigApplicationContext";

/**
* The class name of application context that will be used by default for web
* environments.
*/
public static final String DEFAULT_WEB_CONTEXT_CLASS = "org.springframework.boot."
+ "web.servlet.context.AnnotationConfigServletWebServerApplicationContext";

/**
* The class name of application context that will be used by default for reactive web
* environments.
*/
public static final String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework."
+ "boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext";

准备上下文

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
//将 environment 设置到上下文 context
context.setEnvironment(environment);
//设置上下文的beanNameGenerator和resourceLoader(如果SpringApplication有的话)
postProcessApplicationContext(context);
//拿到之前实例化 SpringApplication 对象的时候设置的 ApplicationContextInitializer,调用它们的 initialize 方法,对上下文做初始化
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");
//注册启动类的bean定义
load(context, sources.toArray(new Object[0]));
//广播 ApplicationPreparedEvent 事件
listeners.contextLoaded(context);
}

刷新上下文

1
2
3
4
5
6
7
8
9
10
11
private void refreshContext(ConfigurableApplicationContext context) {
refresh(context);
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
}
catch (AccessControlException ex) {
// Not allowed in some environments.
}
}
}
1
2
3
4
protected void refresh(ApplicationContext applicationContext) {
Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
((AbstractApplicationContext) applicationContext).refresh();
}

AbstractApplicationContext 的 refresh 方法我们就不看了,前面介绍 SpringIOC 容器的时候看过了。。。

初始化器 ApplicationContextInitializer

在实例化 SpringApplication 对象的时候设置了相关的初始化器和监听器。这一部分我们先看下几个初始化器。

具体有从 spring-boot 的 META-INF/spring.factories 文件中获取到的四个:

1
2
3
4
5
6
# 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.web.context.ServerPortInfoApplicationContextInitializer

从 spring-boot-autoconfigure 的 META-INF/spring.factories 文件中获取到的两个:

1
2
3
4
# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener

然后会在 SpringApplication 调用 prepareContext() 方法中 applyInitializers(context) 的时候,依次执行各个初始化器的 initialize(context) 方法。

1
2
3
4
5
6
7
8
protected void applyInitializers(ConfigurableApplicationContext context) {
for (ApplicationContextInitializer initializer : getInitializers()) {
Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(
initializer.getClass(), ApplicationContextInitializer.class);
Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
initializer.initialize(context);
}
}

ConfigurationWarningsApplicationContextInitializer

其 initialize(context) 方法代码如下:

1
2
3
4
public void initialize(ConfigurableApplicationContext context) {
context.addBeanFactoryPostProcessor(
new ConfigurationWarningsPostProcessor(getChecks()));
}

在实例化 ConfigurationWarningsPostProcessor 时首先会调用 getChecks 获得 Check[],传入到 ConfigurationWarningsPostProcessor 的构造器中.代码如下:

1
2
3
protected Check[] getChecks() {
return new Check[] { new ComponentScanPackageCheck() };
}

其返回了一个 ComponentScanPackageCheck. 其代码如下:

1
2
3
4
5
6
7
8
9
10
11
protected static class ComponentScanPackageCheck implements Check {

private static final Set<String> PROBLEM_PACKAGES;

static {
Set<String> packages = new HashSet<>();
packages.add("org.springframework");
packages.add("org");
PROBLEM_PACKAGES = Collections.unmodifiableSet(packages);
}
}

将 org.springframework , org 加入到了PROBLEM_PACKAGES 中.

ConfigurationWarningsPostProcessor 构造器如下:

1
2
3
public ConfigurationWarningsPostProcessor(Check[] checks) {
this.checks = checks;
}

这样 ConfigurationWarningsPostProcessor 就持有了 ComponentScanPackageCheck。然后将 ConfigurationWarningsPostProcessor 添加到 context 的 beanFactoryPostProcessors变量当中。

1
2
/** BeanFactoryPostProcessors to apply on refresh */
private final List<BeanFactoryPostProcessor> beanFactoryPostProcessors = new ArrayList<>();

ContextIdApplicationContextInitializer

其 initialize(context) 方法代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public void initialize(ConfigurableApplicationContext applicationContext) {
ContextId contextId = getContextId(applicationContext);
applicationContext.setId(contextId.getId());
applicationContext.getBeanFactory().registerSingleton(ContextId.class.getName(),
contextId);
}

private ContextId getContextId(ConfigurableApplicationContext applicationContext) {
ApplicationContext parent = applicationContext.getParent();
if (parent != null && parent.containsBean(ContextId.class.getName())) {
return parent.getBean(ContextId.class).createChildId();
}
return new ContextId(getApplicationId(applicationContext.getEnvironment()));
}

private String getApplicationId(ConfigurableEnvironment environment) {
String name = environment.getProperty("spring.application.name");
return StringUtils.hasText(name) ? name : "application";
}

这里主要是给 context 设置唯一 id,如果有父上下文,则根据父上下文的 ContextId 生成一个新的 ContextId,否则创建一个新的ContextId:从 environment 中读取 “spring.application.name” 变量的值,没有则设置 id 为 application。

DelegatingApplicationContextInitializer

其 initialize(context) 方法代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
private static final String PROPERTY_NAME = "context.initializer.classes";

public void initialize(ConfigurableApplicationContext context) {
ConfigurableEnvironment environment = context.getEnvironment();
List<Class<?>> initializerClasses = getInitializerClasses(environment);
if (!initializerClasses.isEmpty()) {
applyInitializerClasses(context, initializerClasses);
}
}

private List<Class<?>> getInitializerClasses(ConfigurableEnvironment env) {
String classNames = env.getProperty(PROPERTY_NAME);
List<Class<?>> classes = new ArrayList<>();
if (StringUtils.hasLength(classNames)) {
for (String className : StringUtils.tokenizeToStringArray(classNames, ",")) {
classes.add(getInitializerClass(className));
}
}
return classes;
}

private void applyInitializers(ConfigurableApplicationContext context,
List<ApplicationContextInitializer<?>> initializers) {
initializers.sort(new AnnotationAwareOrderComparator());
for (ApplicationContextInitializer initializer : initializers) {
//依次调用配置的初始化器的 initialize 方法
initializer.initialize(context);
}
}

该初始化器的作用是:读取配置的 “context.initializer.classes” 值,也就是我们自定义的初始化类(实现ApplicationContextInitializer),然后实例化后依次调用其 initialize(context) 方法。

ServerPortInfoApplicationContextInitializer

其 initialize(context) 方法代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class ServerPortInfoApplicationContextInitializer
implements ApplicationContextInitializer<ConfigurableApplicationContext>,
ApplicationListener<WebServerInitializedEvent> {

@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
applicationContext.addApplicationListener(this);
}

@Override
public void onApplicationEvent(WebServerInitializedEvent event) {
String propertyName = "local." + getName(event.getApplicationContext()) + ".port";
setPortProperty(event.getApplicationContext(), propertyName,
event.getWebServer().getPort());
}
}

将其添加的 context 的监听器集合中,监听到 WebServerInitializedEvent 事件时执行 onApplicationEvent() 方法

SharedMetadataReaderFactoryContextInitializer

其 initialize(context) 方法代码如下:

1
2
3
4
public void initialize(ConfigurableApplicationContext applicationContext) {
applicationContext.addBeanFactoryPostProcessor(
new CachingMetadataReaderFactoryPostProcessor());
}

将 CachingMetadataReaderFactoryPostProcessor 添加到 context 的 beanFactoryPostProcessors变量当中。

ConditionEvaluationReportLoggingListener

其 initialize(context) 方法代码如下:

1
2
3
4
5
6
7
8
9
10
public void initialize(ConfigurableApplicationContext applicationContext) {
this.applicationContext = applicationContext;
applicationContext
.addApplicationListener(new ConditionEvaluationReportListener());
if (applicationContext instanceof GenericApplicationContext) {
// Get the report early in case the context fails to load
this.report = ConditionEvaluationReport
.get(this.applicationContext.getBeanFactory());
}
}

将其添加的 context 的监听器集合中。

自定义初始化器

  1. 使用spring.factories方式:

    首先我们自定义个类实现了ApplicationContextInitializer,然后在resource下面新建/META-INF/spring.factories文件。

    1
    2
    org.springframework.context.ApplicationContextInitializer=\
    org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
  2. application.yml 添加配置方式:

    1
    2
    org.springframework.context.ApplicationContextInitializer=\
    org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
  3. 启动类直接添加方式:

    1
    2
    3
    application.addInitializers((ApplicationContextInitializer<ConfigurableApplicationContext>) applicationContext -> {
    System.out.println("======MyApplicationContextInitializer======");
    });

监听器 ApplicationListener

在实例化 SpringApplication 对象的时候设置了相关的初始化器和监听器。这一部分我们看下几个监听器。

具体有从 spring-boot 的 META-INF/spring.factories 文件中获取到的九个:

1
2
3
4
5
6
7
8
9
10
11
# 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.ConfigFileApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener

从 spring-boot-autoconfigure 的 META-INF/spring.factories 文件中获取到的一个:

1
2
3
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer

SpringApplicationRunListeners

我们先来看下 SpringApplicationRunListeners,该对象是 SpringApplication.run() 方法执行一开始的时候创建的:

1
SpringApplicationRunListeners listeners = getRunListeners(args);
1
2
3
4
5
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
SpringApplicationRunListener.class, types, this, args));
}

SpringApplicationRunListeners 内部持有 SpringApplicationRunListener 集合(也是从 spring.factories 文件中获取,只有一个 EventPublishingRunListener 对象)和1个 Log 日志类。用于SpringApplicationRunListener 监听器的批量执行。

1
2
3
4
5
6
7
8
9
private final Log log;

private final List<SpringApplicationRunListener> listeners;

SpringApplicationRunListeners(Log log,
Collection<? extends SpringApplicationRunListener> listeners) {
this.log = log;
this.listeners = new ArrayList<>(listeners);
}

SpringApplicationRunListener 看名字也知道用于监听 SpringApplication 的 run 方法的执行。run 方法中有几个步骤会出发对应的事件监听器:

  1. starting

    run方法执行后立即执行,对应事件 ApplicationStartingEvent

  2. environmentPrepared

    上下文 ApplicationContext 创建之前并且环境信息 ConfigurableEnvironment 准备好的时候调用;对应事件的类型是 ApplicationEnvironmentPreparedEvent

  3. contextPrepared

    上下文 ApplicationContext 创建之后并设置了环境并调用了各个初始化器的 initialize 方法之后调用;没有对应事件

  4. contextLoaded

    上下文 ApplicationContext 创建并加载之后并在refresh之前调用;对应事件的类型是ApplicationPreparedEvent

  5. started

    上下文 ApplicationContext 刷新之后调用;对应事件的类型是 ApplicationStartedEvent

  6. running

    run 方法结束之前调用;对应事件的类型是 ApplicationReadyEvent

  7. failure

    run 方法捕获异常的时候调用;对应事件的类型是 ApplicationFailedEvent

SpringApplicationRunListener

SpringApplicationRunListener 接口只有一个实现类 EventPublishingRunListener,其构造方法如下:

1
2
3
4
5
6
7
8
9
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);
}
}

在实例化 EventPublishingRunListener 对象的时候,创建一个事件广播器 SimpleApplicationEventMulticaster,

并将所有的事件监听器保存起来:

1
2
3
4
5
6
7
8
9
10
11
12
13
public void addApplicationListener(ApplicationListener<?> listener) {
synchronized (this.retrievalMutex) {
// Explicitly remove target for a proxy, if registered already,
// in order to avoid double invocations of the same listener.
// 避免重复监听
Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
if (singletonTarget instanceof ApplicationListener) {
this.defaultRetriever.applicationListeners.remove(singletonTarget);
}
this.defaultRetriever.applicationListeners.add(listener);
this.retrieverCache.clear();
}
}

我们以 listeners.starting() 为例, 会调用 EventPublishingRunListener 对象的 starting 方法:

1
2
3
4
public void starting() {
this.initialMulticaster.multicastEvent(
new ApplicationStartingEvent(this.application, this.args));
}

这里创建一个 ApplicationStartingEvent 对象作为调用事件广播器的 multicastEvent() 方法的参数,multicastEvent() 方法相关代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public void multicastEvent(ApplicationEvent event) {
multicastEvent(event, resolveDefaultEventType(event));
}

public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
//获取匹配的事件监听器,遍历后通过 Executor 执行一个子线程去完成监听器listener.onApplicationEvent(event)方法。
for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
Executor executor = getTaskExecutor();
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}

我们先看下 getApplicationListeners 方法怎么根据事件类型获取匹配的事件监听器的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
protected Collection<ApplicationListener<?>> getApplicationListeners(
ApplicationEvent event, ResolvableType eventType) {

Object source = event.getSource();
Class<?> sourceType = (source != null ? source.getClass() : null);
ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);

// Quick check for existing entry on ConcurrentHashMap...
ListenerRetriever retriever = this.retrieverCache.get(cacheKey);
if (retriever != null) {
return retriever.getApplicationListeners();
}

if (this.beanClassLoader == null ||
(ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
(sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
// Fully synchronized building and caching of a ListenerRetriever
synchronized (this.retrievalMutex) {
retriever = this.retrieverCache.get(cacheKey);
if (retriever != null) {
return retriever.getApplicationListeners();
}
retriever = new ListenerRetriever(true);
Collection<ApplicationListener<?>> listeners =
retrieveApplicationListeners(eventType, sourceType, retriever);
this.retrieverCache.put(cacheKey, retriever);
return listeners;
}
}
else {
// No ListenerRetriever caching -> no synchronization necessary
return retrieveApplicationListeners(eventType, sourceType, null);
}
}

缓存部分我们不看,主要看 retrieveApplicationListeners 方法就行,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
private Collection<ApplicationListener<?>> retrieveApplicationListeners(
ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable ListenerRetriever retriever) {

List<ApplicationListener<?>> allListeners = new ArrayList<>();
Set<ApplicationListener<?>> listeners;
Set<String> listenerBeans;
synchronized (this.retrievalMutex) {
listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);
// 这个里面在刷新上下文之前是不存在东西的
listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);
}
for (ApplicationListener<?> listener : listeners) {
// 查看监听器是否支持该事件,支持的话则保存到 allListeners 待返回
if (supportsEvent(listener, eventType, sourceType)) {
if (retriever != null) {
//缓存起来
retriever.applicationListeners.add(listener);
}
allListeners.add(listener);
}
}
if (!listenerBeans.isEmpty()) {
BeanFactory beanFactory = getBeanFactory();
for (String listenerBeanName : listenerBeans) {
try {
Class<?> listenerType = beanFactory.getType(listenerBeanName);
if (listenerType == null || supportsEvent(listenerType, eventType)) {
ApplicationListener<?> listener =
beanFactory.getBean(listenerBeanName, ApplicationListener.class);
if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {
if (retriever != null) {
retriever.applicationListenerBeans.add(listenerBeanName);
}
allListeners.add(listener);
}
}
}
catch (NoSuchBeanDefinitionException ex) {
// Singleton listener instance (without backing bean definition) disappeared -
// probably in the middle of the destruction phase
}
}
}
AnnotationAwareOrderComparator.sort(allListeners);
return allListeners;
}

一个监听器支不支持该事件我们看 supportsEvent 方法:

1
2
3
4
5
6
7
protected boolean supportsEvent(
ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType) {

GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ?
(GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener));
return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));
}

这里可以看出 listener 不是 GenericApplicationListener 的话,则创建一个适配器对象GenericApplicationListenerAdapter。然后调用 smartListener.supportsEventType() 检查事件类型和事件源类型。如果是我们自定义的事件,则调用的是 GenericApplicationListenerAdapter 对象的 supportsEventType() 方法。代码如下:

1
2
3
4
5
6
7
8
9
public boolean supportsEventType(ResolvableType eventType) {
if (this.delegate instanceof SmartApplicationListener) {
Class<? extends ApplicationEvent> eventClass = (Class<? extends ApplicationEvent>) eventType.resolve();
return (eventClass != null && ((SmartApplicationListener) this.delegate).supportsEventType(eventClass));
}
else {
return (this.declaredEventType == null || this.declaredEventType.isAssignableFrom(eventType));
}
}

这里判断事件监听器是不是 SmartApplicationListener 的实现类:

  1. 是则调用他们自己的 supportsEventType 方法。SmartApplicationListener 的实现类有三个:ConfigFileApplicationListener、GenericApplicationListenerAdapter、SourceFilteringListener。这里我们以 ConfigFileApplicationListener 为例,其 supportsEventType 方法如下:

    1
    2
    3
    4
    public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
    return ApplicationEnvironmentPreparedEvent.class.isAssignableFrom(eventType)
    || ApplicationPreparedEvent.class.isAssignableFrom(eventType);
    }

    很明显可以看出 ConfigFileApplicationListener 只支持 ApplicationEnvironmentPreparedEvent 和 ApplicationPreparedEvent。

  2. 不是则用监听器实现 ApplicationListener 接口时传递的泛型类型和该事件类型比较。

ConfigFileApplicationListener

ConfigFileApplicationListener 对事件的监听代码如下:

1
2
3
4
5
6
7
8
9
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ApplicationEnvironmentPreparedEvent) {
onApplicationEnvironmentPreparedEvent(
(ApplicationEnvironmentPreparedEvent) event);
}
if (event instanceof ApplicationPreparedEvent) {
onApplicationPreparedEvent(event);
}
}

监听两个事件:ApplicationEnvironmentPreparedEvent 和 ApplicationPreparedEvent。

加载配置文件

监听到 ApplicationEnvironmentPreparedEvent 时的处理代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
private void onApplicationEnvironmentPreparedEvent(
ApplicationEnvironmentPreparedEvent event) {
// 从 spring.factories 文件中获取环境后置处理器
List<EnvironmentPostProcessor> postProcessors = loadPostProcessors();
// 同时添加 ConfigFileApplicationListener 自身
postProcessors.add(this);
// 利用 order 进行优先级排序
AnnotationAwareOrderComparator.sort(postProcessors);
// 遍历后置处理器,调用其 postProcessEnvironment 方法
for (EnvironmentPostProcessor postProcessor : postProcessors) {
postProcessor.postProcessEnvironment(event.getEnvironment(),
event.getSpringApplication());
}
}

这里我们主要看 ConfigFileApplicationListener 自身的 postProcessEnvironment 方法:

1
2
3
4
public void postProcessEnvironment(ConfigurableEnvironment environment,
SpringApplication application) {
addPropertySources(environment, application.getResourceLoader());
}
1
2
3
4
5
6
7
protected void addPropertySources(ConfigurableEnvironment environment,
ResourceLoader resourceLoader) {
// 将随机值属性源添加到环境
RandomValuePropertySource.addToEnvironment(environment);
// 这里的 resourceLoader 在构建 SpringApplication 的时候可以穿入,我们这里为 null
new Loader(environment, resourceLoader).load();
}

这里创建了一个 Loader 对象并调用 load() 方法。

Loader 是 ConfigFileApplicationListener 的一个内部类,其作用是加载候选属性源并配置活动配置文件。其相关代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
Loader(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
this.environment = environment;
this.resourceLoader = (resourceLoader != null) ? resourceLoader
: new DefaultResourceLoader();
// 从 spring.factories 文件中获取 PropertySourceLoader
// 1.PropertiesPropertySourceLoader 2.YamlPropertySourceLoader
this.propertySourceLoaders = SpringFactoriesLoader.loadFactories(
PropertySourceLoader.class, getClass().getClassLoader());
}

public void load() {
this.profiles = new LinkedList<>();
this.processedProfiles = new LinkedList<>();
this.activatedProfiles = false;
this.loaded = new LinkedHashMap<>();
// 初始化配置文件信息 添加到 deque 中
initializeProfiles();
while (!this.profiles.isEmpty()) {
Profile profile = this.profiles.poll();
if (profile != null && !profile.isDefaultProfile()) {
addProfileToEnvironment(profile.getName());
}
load(profile, this::getPositiveProfileFilter,
addToLoaded(MutablePropertySources::addLast, false));
this.processedProfiles.add(profile);
}
resetEnvironmentProfiles(this.processedProfiles);
// 加载配置文件
load(null, this::getNegativeProfileFilter,
addToLoaded(MutablePropertySources::addFirst, true));
// 添加已加载的属性源
addLoadedPropertySources();
}

加载配置文件信息的代码在 load() 方法里:

1
2
3
4
5
6
7
8
9
private void load(Profile profile, DocumentFilterFactory filterFactory,
DocumentConsumer consumer) {
getSearchLocations().forEach((location) -> {
boolean isFolder = location.endsWith("/");
Set<String> names = isFolder ? getSearchNames() : NO_SEARCH_NAMES;
names.forEach(
(name) -> load(location, name, profile, filterFactory, consumer));
});
}

getSearchLocations() 方法默认返回:classpath:/,classpath:/config/,file:./,file:./config/

getSearchNames() 方法默认返回:application

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
private void load(String location, String name, Profile profile,
DocumentFilterFactory filterFactory, DocumentConsumer consumer) {
if (!StringUtils.hasText(name)) {
for (PropertySourceLoader loader : this.propertySourceLoaders) {
if (canLoadFileExtension(loader, location)) {
load(loader, location, profile,
filterFactory.getDocumentFilter(profile), consumer);
return;
}
}
}
Set<String> processed = new HashSet<>();
// this.propertySourceLoaders:
// 1.PropertiesPropertySourceLoader (getFileExtensions: "properties", "xml")
// 2.YamlPropertySourceLoader (getFileExtensions: "yml", "yaml")
for (PropertySourceLoader loader : this.propertySourceLoaders) {
for (String fileExtension : loader.getFileExtensions()) {
if (processed.add(fileExtension)) {
// 遍历每一种可能查找配置文件并加载 具体加载细节这里不看了
loadForFileExtension(loader, location + name, "." + fileExtension,
profile, filterFactory, consumer);
}
}
}
}

监听 ApplicationPreparedEvent

ApplicationPreparedEvent 发生在准备好上下文但是刷新之前。

ConfigFileApplicationListener 监听到该事件的时候做了什么呢?

1
2
3
4
5
6
7
8
9
private void onApplicationPreparedEvent(ApplicationEvent event) {
this.logger.replayTo(ConfigFileApplicationListener.class);
addPostProcessors(((ApplicationPreparedEvent) event).getApplicationContext());
}

protected void addPostProcessors(ConfigurableApplicationContext context) {
context.addBeanFactoryPostProcessor(
new PropertySourceOrderingPostProcessor(context));
}

从代码可以看出来只做了一件事情:添加了一个叫 PropertySourceOrderingPostProcessor 的 BeanFactoryPostProcessor。

BeanFactoryPostProcessor 在刷新上下文的 invokeBeanFactoryPostProcessors(beanFactory) 时候会实例化并调用。

自定义监听器

1
2
3
4
5
6
7
8
9
10
public class MyApplicationStartedEventListener implements ApplicationListener<ApplicationStartedEvent> {

private static final Logger LOGGER = LoggerFactory.getLogger(MyApplicationStartedEventListener.class);

@Override
public void onApplicationEvent(ApplicationStartedEvent event) {
LOGGER.info("======MyApplicationStartedEventListener======");
}

}

创建一个监听器类实现 ApplicationListener 并写明感兴趣的事件,然后在启动类中添加到 SpringApplication

1
2
SpringApplication application = new SpringApplication(DemoApplication.class);
application.addListeners(new MyApplicationStartedEventListener());

总结

这一部分介绍了启动流程 springApplication.run() 中做了哪些事情,以及其中涉及到的一些初始化器和事件监听器等。。。