参考文献

启动流程

  • 基于SpringBoot 2.7.x

构造函数

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
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
// 设置资源加载器
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
// 初始化加载资源类集合并去重
// 将启动类设置为属性存入primarySources (设置要加载的基础资源)
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// TODO 1 推断应用程序是不是web应用
// 若是普通web应用则this.webApplicationType == WebApplicationType.SERVLET
this.webApplicationType = WebApplicationType.deduceFromClasspath();

this.bootstrapRegistryInitializers = new ArrayList<>(
getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
// TODO 2 加载Spring应用上下文初始化器
// 设置初始化器(Initializer) 设置应用上下文的初始化器 ApplicationContextInitializer,最终会调用这些初始化器
// 就是去spring.factories 中去获取所有key为org.springframework.context.ApplicationContextInitializer
// # 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.rsocket.context.RSocketPortInfoApplicationContextInitializer,\
// org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
// TODO 3 设置监听器
// 就是去spring.factories 中去获取所有key为org.springframework.context.ApplicationListener
// # 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.DelegatingApplicationListener,\
// org.springframework.boot.context.logging.LoggingApplicationListener,\
// org.springframework.boot.env.EnvironmentPostProcessorApplicationListener
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 推断出主应用入口类
this.mainApplicationClass = deduceMainApplicationClass();
}

run

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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
/**
* Run the Spring application, creating and refreshing a new
* {@link ApplicationContext}.
* @param args the application arguments (usually passed from a Java main method)
* @return a running {@link ApplicationContext}
*/
public ConfigurableApplicationContext run(String... args) {
// 创建并启动计时器
long startTime = System.nanoTime();
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
ConfigurableApplicationContext context = null;
// 配置系统属性 java.awt.headless
configureHeadlessProperty();
// TODO 1 获取并启动监听器
// 创建运行监听器组,先根据spring.factories中的配置创建要使用的运行监听实例,再把这些运行监听实例封装为运行监听器组
SpringApplicationRunListeners listeners = getRunListeners(args);
// 执行运行监听器的starting()回调方法
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
// 构建应用参数
// 应用参数指的是传给main()方法的参数arg 这一步会将main()方法的参数封装为ApplicationArguments
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// TODO 2 根据SpringApplicationRunListeners 以及参数来准备环境
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
// 配置spring.beaninfo.ignore属性
configureIgnoreBeanInfo(environment);
// 准备Banner打印器 -SpringBoot启动的时候打印在console上的内容
Banner printedBanner = printBanner(environment);
// TODO 3 创建Spring应用上下文
// 一般web应用,最终会执行 new AnnotationConfigServletWebServerApplicationContext()来创建context
context = createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
// TODO 4 Spring上下文前置处理
// (准备上下文,主要对上一步创建好的上下文进行配置、完善,这一步会加载所有的bean定义)
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
// TODO 5 刷新上下文
// (刷新上下文,主要调用高级容器的refresh()刷新上下文,这一步会实例化所有的单例bean,懒加载的除外)
refreshContext(context);
// TODO 6 Spring上下文后置处理
//(执行刷新后处理,这个方法是protected修饰的空方法,作为预留的扩展点可被子类重写,可以在上下文刷新之后做一些自定义的操作)
afterRefresh(context, applicationArguments);
Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
}
// TODO 7 发出结束执行的事件
// (运行监听器的started()回调方法)
listeners.started(context, timeTakenToStartup);
// TODO 8 执行Runners
//(执行Runner回调,这也是一个扩展点,可以在应用启动后,根据main()参数做一些自定义的处理)
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
// 1、执行运行监听器的failed()回调方法;
// 2、使用异常报告器 SpringBootExceptionReporter 打印\记录异常信息
handleRunFailure(context, ex, listeners);
throw new IllegalStateException(ex);
}
try {
Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
listeners.ready(context, timeTakenToReady);
}
catch (Throwable ex) {
handleRunFailure(context, ex, null);
throw new IllegalStateException(ex);
}
return context;
}
  • 第一步: 获取并启动监听器
  • 第二步: 根据SpringApplicationRunListeners以及参数来准备环境
  • 第三步: 创建Spring容器(创建应用上下文),一般web应用,最终会执行new AnnotationConfigServletWebServerApplicationContext()来创建上下文
  • 第四步: Spring容器前置处理(准备上下文,主要对上一步创建好的上下文进行配置、完善,这一步会加载所有的bean定义)
  • 第五步: 刷新容器(刷新上下文,主要调用高级容器的refresh()刷新上下文,这一步会实例化所有的单例bean,懒加载的除外)
  • 第六步: Spring容器后置处理(执行刷新后处理,这个方法是protected修饰的空方法,作为预留的扩展点可被子类重写,可以在上下文刷新之后做一些自定义的操作)
  • 第七步: 发出结束执行的事件(运行监听器的started()回调方法)
  • 第八步: 执行Runners(执行Runner回调,这也是一个扩展点,可以在应用启动后,根据main()参数做一些自定义的处理)

获取运行监听器

1
2
3
4
5
6
7
8
9
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
// # Run Listeners
// org.springframework.boot.SpringApplicationRunListener=\
// org.springframework.boot.context.event.EventPublishingRunListener
return new SpringApplicationRunListeners(logger,
getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args),
this.applicationStartup);
}
SpringApplicationRunListener
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
public interface SpringApplicationRunListener {

//在run()方法开始执行时,该方法就立即被调用,可用于在初始化早期时做一些工作
default void starting() {
}
//当environment构建完成,ApplicationContext创建之前,该方法被调用
default void environmentPrepared(ConfigurableEnvironment environment) {
}
//当ApplicatonContext构建完成时,该方法被调用
default void contextPrepared(ConfigurableApplicationContext context) {
}
//在ApplicationContext完成加载,但没有被刷新前,该方法被调用
default void contextLoaded(ConfigurableApplicationContext context) {
}
// 在ApplicationContext刷新并启动后,CommandLineRunners和ApplicationRunner未被调用前,该方法被调用
default void started(ConfigurableApplicationContext context) {
}
// 在run()方法执行完成前该方法被调用
default void running(ConfigurableApplicationContext context) {
}
// 当应用运行出错时该方法被调用
default void failed(ConfigurableApplicationContext context, Throwable exception) {
}

}
  • 在Spring中具体的实现为org.springframework.boot.context.event.EventPublishingRunListener
    • EventPublishingRunListener中包含一个SimpleApplicationEventMulticaster事件广播器,广播器中包含多个ApplicationListener事件监听器
监听方法 运行阶段说明 SpringBoot事件
starting() Spring应用刚启动 ApplicationStartingEvent
environmentPrepared(ConfigurableEnvironment environment) ConfigurationEnvironment准备妥当,允许将其调整 ApplicationEnvironmentPreparedEvent
contextPrepared(ConfigurableApplicationContext context) ConfigurableApplicationContext准备妥当,运行将其调整 ApplicationContextInitializedEvent
contextLoaded(ConfigurableApplicationContext context) ConfigurableApplicationContext已装载,但仍未启动 ApplicationPreparedEvent
started(ConfigurableApplicationContext context) ConfigurableApplicationContext已启动,此时Spring Bean已初始化完成 ApplicationStartedEvent
running(ConfigurableApplicationContext context) Spring应用正在运行 ApplicationReadyEvent
failed(ConfigurableApplicationContext context, Throwable exception) Spring应用运行失败 ApplicationFailedEvent
ApplicationListenerSpringApplicationRunListener的区别
  • 它们的主要区别在于它们监听的时间点和处理的事件类型不同.

  • ApplicationListener

    • ApplicationListener是Spring框架中的通用事件监听器接口,用于监听Spring应用程序中的各种事件,如上下文刷新事件、上下文关闭事件、Web请求处理事件等.它可以监听所有Spring事件,而不仅仅是Spring Boot事件.

    • ApplicationListener的实现类需要实现onApplicationEvent()方法,该方法在监听到事件时被调用.例如,下面的代码演示了如何实现一个ApplicationListener,以监听上下文刷新事件:

      1
      2
      3
      4
      5
      6
      7
      8
      @Component
      public class MyApplicationListener implements ApplicationListener<ContextRefreshedEvent> {

      @Override
      public void onApplicationEvent(ContextRefreshedEvent event) {
      // 处理上下文刷新事件
      }
      }
  • SpringApplicationRunListener

    • SpringApplicationRunListener是Spring Boot中的特定类型的监听器,它用于监听Spring Boot应用程序的生命周期事件,如应用程序启动事件、应用程序关闭事件等

    • 需要注意的是,SpringApplicationRunListener的实现类需要在META-INF/spring.factories文件中进行声明,例如:

      1
      2
      org.springframework.boot.SpringApplicationRunListener=\
      com.example.MyRunListener

根据SpringApplicationRunListeners以及参数来准备环境

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
	private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
// Create and configure the environment
// 获取或创建环境,已现成的环境就直接使用,没有则调用构造方法new一个
ConfigurableEnvironment environment = getOrCreateEnvironment();
// 配置环境: 上一步调用无参构造器创建了Environment实例,这一步对创建好的Environment实例进行配置
configureEnvironment(environment, applicationArguments.getSourceArgs());
// 绑定配置属性源、环境
ConfigurationPropertySources.attach(environment);
// 至此环境已配置好,出发SpringApplicationRunListener的 environmentPrepared()回调方法
// 发布环境已准备事件,这是第二次发布事件
listeners.environmentPrepared(bootstrapContext, environment);
DefaultPropertiesPropertySource.moveToEnd(environment);
Assert.state(!environment.containsProperty("spring.main.environment-prefix"),
"Environment prefix cannot be set via properties.");
// 将配置好的环境绑定到SpringApplication上
bindToSpringApplication(environment);
// 如果不是自定义的环境,则根据情况确定是否需要转换环境
if (!this.isCustomEnvironment) {
EnvironmentConverter environmentConverter = new EnvironmentConverter(getClassLoader());
environment = environmentConverter.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;
}
switch (this.webApplicationType) {
case SERVLET:
// web应用
return new ApplicationServletEnvironment();
case REACTIVE:
return new ApplicationReactiveWebEnvironment();
default:
return new ApplicationEnvironment();
}
}
1
2
3
4
5
6
7
8
9
10
11
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
// 处理ConversionService配置
// ConversionService是Spring的一个线程安全的类型转换接口,convert(Object,Class)可以将对象转换为指定类型,关键在于是线程安全的.
if (this.addConversionService) {
environment.setConversionService(new ApplicationConversionService());
}
// 配置属性源
configurePropertySources(environment, args);
// 配置profiles属性: 这一步会把 spring.profiles 激活的配置文件添加到环境中
configureProfiles(environment, args);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
protected void configurePropertySources(ConfigurableEnvironment environment, String[] args) {
// 配置默认属性
MutablePropertySources sources = environment.getPropertySources();
if (!CollectionUtils.isEmpty(this.defaultProperties)) {
DefaultPropertiesPropertySource.addOrMerge(this.defaultProperties, sources);
}
// 配置命令行属性: 如果给main()方法传递了命令行参数,则添加到Environment实例中.
if (this.addCommandLineProperties && args.length > 0) {
String name = CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME;
if (sources.contains(name)) {
PropertySource<?> source = sources.get(name);
CompositePropertySource composite = new CompositePropertySource(name);
composite.addPropertySource(
new SimpleCommandLinePropertySource("springApplicationCommandLineArgs", args));
composite.addPropertySource(source);
sources.replace(name, composite);
}
else {
sources.addFirst(new SimpleCommandLinePropertySource(args));
}
}
}

创建Spring应用上下文

  • 通过Web的类型判断执行ApplicationContextFactorycreate方法
  • 具体为AnnotationConfigReactiveWebServerApplicationContextAnnotationConfigServletWebServerApplicationContext
1
2
3
4
protected ConfigurableApplicationContext createApplicationContext() {
// 根据推断的Type来创建上下文
return this.applicationContextFactory.create(this.webApplicationType);
}
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
@FunctionalInterface
public interface ApplicationContextFactory {

/**
* A default {@link ApplicationContextFactory} implementation that will create an
* appropriate context for the {@link WebApplicationType}.
*/
ApplicationContextFactory DEFAULT = (webApplicationType) -> {
try {
// 此处从META-INF/spring.factories文件中加载ApplicationContextFactory的实现类
for (ApplicationContextFactory candidate : SpringFactoriesLoader
.loadFactories(ApplicationContextFactory.class, ApplicationContextFactory.class.getClassLoader())) {
// 根据webApplicationType来创建出对应的上下文
ConfigurableApplicationContext context = candidate.create(webApplicationType);
if (context != null) {
return context;
}
}
return new AnnotationConfigApplicationContext();
}
catch (Exception ex) {
throw new IllegalStateException("Unable create a default ApplicationContext instance, "
+ "you may need a custom ApplicationContextFactory", ex);
}
};
// ...略
}
1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* {@link ApplicationContextFactory} registered in {@code spring.factories} to support
* {@link AnnotationConfigServletWebServerApplicationContext}.
*/
static class Factory implements ApplicationContextFactory {

@Override
public ConfigurableApplicationContext create(WebApplicationType webApplicationType) {
return (webApplicationType != WebApplicationType.SERVLET) ? null
: new AnnotationConfigServletWebServerApplicationContext();
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* {@link ApplicationContextFactory} registered in {@code spring.factories} to support
* {@link AnnotationConfigReactiveWebServerApplicationContext}.
*/
static class Factory implements ApplicationContextFactory {

@Override
public ConfigurableApplicationContext create(WebApplicationType webApplicationType) {
return (webApplicationType != WebApplicationType.REACTIVE) ? null
: new AnnotationConfigReactiveWebServerApplicationContext();
}

}
  • 以常用的AnnotationConfigServletWebServerApplicationContext为例
1
2
3
4
5
6
7
8
9
10
public AnnotationConfigServletWebServerApplicationContext() {
// 创建AnnotatedBeanDefinitionReader
// AnnotatedBeanDefinitionReader是Spring框架中一个用于读取注解定义的Bean的工具类.
// 它可以解析Java注解,并根据注解信息生成对应的Bean定义.
this.reader = new AnnotatedBeanDefinitionReader(this);
// 创建ClassPathBeanDefinitionScanner
// ClassPathBeanDefinitionScanner是Spring框架中一个用于扫描指定包路径下的Java类,并将符合条件的类注册为Bean的工具类.
// 它可以根据指定的过滤器,扫描指定包路径下的Java类,将符合条件的Java类注册为Spring容器中的Bean.
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
  • org.springframework.context.annotation.AnnotatedBeanDefinitionReader
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
/**
* Create a new {@code AnnotatedBeanDefinitionReader} for the given registry.
* <p>If the registry is {@link EnvironmentCapable}, e.g. is an {@code ApplicationContext},
* the {@link Environment} will be inherited, otherwise a new
* {@link StandardEnvironment} will be created and used.
* @param registry the {@code BeanFactory} to load bean definitions into,
* in the form of a {@code BeanDefinitionRegistry}
* @see #AnnotatedBeanDefinitionReader(BeanDefinitionRegistry, Environment)
* @see #setEnvironment(Environment)
*/
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
this(registry, getOrCreateEnvironment(registry));
}

/**
* Create a new {@code AnnotatedBeanDefinitionReader} for the given registry,
* using the given {@link Environment}.
* @param registry the {@code BeanFactory} to load bean definitions into,
* in the form of a {@code BeanDefinitionRegistry}
* @param environment the {@code Environment} to use when evaluating bean definition
* profiles.
* @since 3.1
*/
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
Assert.notNull(environment, "Environment must not be null");
this.registry = registry;
// 推断ApplicationContext所需要的BeanFactory,Classloader等
this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
// 注册注释 Annotation的postprocessor
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
  • org.springframework.context.annotation.ClassPathBeanDefinitionScanner
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
/**
* Create a new {@code ClassPathBeanDefinitionScanner} for the given bean factory and
* using the given {@link Environment} when evaluating bean definition profile metadata.
* @param registry the {@code BeanFactory} to load bean definitions into, in the form
* of a {@code BeanDefinitionRegistry}
* @param useDefaultFilters whether to include the default filters for the
* {@link org.springframework.stereotype.Component @Component},
* {@link org.springframework.stereotype.Repository @Repository},
* {@link org.springframework.stereotype.Service @Service}, and
* {@link org.springframework.stereotype.Controller @Controller} stereotype annotations
* @param environment the Spring {@link Environment} to use when evaluating bean
* definition profile metadata
* @param resourceLoader the {@link ResourceLoader} to use
* @since 4.3.6
*/
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
Environment environment, @Nullable ResourceLoader resourceLoader) {

Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
this.registry = registry;
// 定义扫描过滤器
// public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry)
// useDefaultFilters 默认为true
if (useDefaultFilters) {
registerDefaultFilters();
}
// 设置环境
setEnvironment(environment);
// 设置resourceLoader
setResourceLoader(resourceLoader);
}

Spring上下文前置处理

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
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
// 设置容器环境,包括各种变量
context.setEnvironment(environment);
// 执行容器(应用上下文)后置处理,主要设置一些未填充的属性
postProcessApplicationContext(context);
// 执行容器中的ApplicationContextInitializer (包括 spring.factories和自定义的实例)
// 执行应用上下文的各个初始化器 用于对应用上下文进行初始化,这个可以当做扩展点做一些自定义的初始化操作
applyInitializers(context);
// 发送容器已经准备好的事件,通知各监听器,至此上下文准备完毕,执行运行监听器的contextPerpared()回调方法
listeners.contextPrepared(context);
bootstrapContext.close(context);
// 如果允许打印启动信息
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
// 注册启动参数bean,这里将容器指定的参数封装成bean,注入容器
// 获取内置的低级容器,以对内置的低级容器进行一些配置
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
// 注册一些特殊的单例bean:应用参数、banner
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
// 配置是否允许bean定义覆盖
if (beanFactory instanceof AbstractAutowireCapableBeanFactory) {
((AbstractAutowireCapableBeanFactory) beanFactory).setAllowCircularReferences(this.allowCircularReferences);
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
}
// 配置是否运行bean的懒加载,默认false,高级容器启动时就实例化所有单例
if (this.lazyInitialization) {
// 如果允许bean的懒加载,则给内置的低级容器添加懒加载对应的后置处理器
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
context.addBeanFactoryPostProcessor(new PropertySourceOrderingBeanFactoryPostProcessor(context));
// Load the sources
// 获取所有的资源,指的是this.primarySources、this.sources 2个属性指定的资源
// 这个primarySources就是我们在SpringApplication实例初始化的时候存入的HelloWorldMainApplication.class
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
// 加载所有的资源: 使用BeanDefinitionLoader 加载所有的bean定义,完成bean的注册
load(context, sources.toArray(new Object[0]));
// 执行运行监听器的contextLoaded() 回调方法
// 通知监听器,容器已准备就绪,主要是针对一些日志等监听器的响应处理.
listeners.contextLoaded(context);
}

刷新上下文

1
2
3
4
5
6
7
8
private void refreshContext(ConfigurableApplicationContext context) {
if (this.registerShutdownHook) {
// 向jvm注册ShutdownHook关闭钩子,在jvm终止时自动关闭应用上下文
shutdownHook.registerApplicationContext(context);
}
// 刷新上下文
refresh(context);
}
1
2
3
4
5
6
7
8
9
/**
* Refresh the underlying {@link ApplicationContext}.
* @param applicationContext the application context to refresh
*/
protected void refresh(ConfigurableApplicationContext applicationContext) {
// 这里的applicationContext就是AnnotationConfigServletWebServerApplicationContext的对象,
// 由于这个类没有refresh方法,会跳转到它的父类ServletWebServerApplicationContext的方法中去
applicationContext.refresh();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#refresh
@Override
public final void refresh() throws BeansException, IllegalStateException {
try {
// 调用父类的refresh方法
// 即org.springframework.context.support.AbstractApplicationContext#refresh
super.refresh();
}
catch (RuntimeException ex) {
WebServer webServer = this.webServer;
if (webServer != null) {
webServer.stop();
}
throw ex;
}
}
  • org.springframework.context.support.AbstractApplicationContext#refresh分析,参考Spring源码-分析(Spring5.1.x)

  • 其中onRefresh()ServletWebServerApplicationContext来实现

1
2
3
4
5
6
7
8
9
10
11
12
//org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#onRefresh
@Override
protected void onRefresh() {
super.onRefresh();
try {
// 创建web服务
createWebServer();
}
catch (Throwable ex) {
throw new ApplicationContextException("Unable to start web server", ex);
}
}
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 void createWebServer() {
WebServer webServer = this.webServer;
ServletContext servletContext = getServletContext();
// 第一次进来webServer servletContext都是null
if (webServer == null && servletContext == null) {
// 这里只是做个标记
StartupStep createWebServer = this.getApplicationStartup().start("spring.boot.webserver.create");
// 这里就会来查找ServletWebServerFactory,也就是web容器的工厂,
// 具体看下getWebServerFactory()方法,还是ServletWebServerApplicationContext这个类的方法
ServletWebServerFactory factory = getWebServerFactory();
createWebServer.tag("factory", factory.getClass().toString());
//这里就是具体创建tomcat了,这里的入参getSelfInitializer()是个lambda表达式,这个后续很重要
this.webServer = factory.getWebServer(getSelfInitializer());
createWebServer.end();
getBeanFactory().registerSingleton("webServerGracefulShutdown",
new WebServerGracefulShutdownLifecycle(this.webServer));
getBeanFactory().registerSingleton("webServerStartStop",
new WebServerStartStopLifecycle(this, this.webServer));
}
else if (servletContext != null) {
try {
getSelfInitializer().onStartup(servletContext);
}
catch (ServletException ex) {
throw new ApplicationContextException("Cannot initialize servlet context", ex);
}
}
initPropertySources();
}

Spring上下文后置处理

  • 这是一个模板方法设计模式,默认是空的实现,是SpringBoot的一个扩展接口,可以重写该方法自定义一些需求,比如打印一些启动结束log,或者其他的后置处理.
1
2
3
4
5
6
7
/**
* Called after the context has been refreshed.
* @param context the application context
* @param args the application arguments
*/
protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) {
}

发出结束执行的事件

1
2
3
4
void started(ConfigurableApplicationContext context, Duration timeTaken) {
doWithListeners("spring.boot.application.started", (listener) -> listener.started(context, timeTaken));
}

1
2
3
default void started(ConfigurableApplicationContext context, Duration timeTaken) {
started(context);
}
1
2
3
4
5
6
// org.springframework.boot.context.event.EventPublishingRunListener#started
@Override
public void started(ConfigurableApplicationContext context, Duration timeTaken) {
context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context, timeTaken));
AvailabilityChangeEvent.publish(context, LivenessState.CORRECT);
}

执行Runners

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private void callRunners(ApplicationContext context, ApplicationArguments args) {
List<Object> runners = new ArrayList<>();
// 获取容器中所有的ApplicationRunner的Bean实例
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
// 获取容器中所有的CommandLineRunner的Bean实例
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
// 对runner进行排序,支持多个runner,可以用@Order 或者实现Order接口指定这些runner的执行顺序
AnnotationAwareOrderComparator.sort(runners);
for (Object runner : new LinkedHashSet<>(runners)) {
if (runner instanceof ApplicationRunner) {
// 执行ApplicationRunner的run方法.传入的args是ApplicationArguments类型
callRunner((ApplicationRunner) runner, args);
}
if (runner instanceof CommandLineRunner) {
// 执行CommandLineRunner的run方法 ,会通过args.getSourceArgs() 获取String... 类型参数
callRunner((CommandLineRunner) runner, args);
}
}
}

SpringApplication调整应用行为

  • SpringApplication调整应用行为的方法都与SpringApplicationBuilder方法一一对应
SpringApplication方法 SpringApplicationBuilder方法 场景说明 默认值 起始版本
setAddCommandLineProperties addCommandLineProperties 是否添加命令行参数 true 1.0
setAdditionalProfiles additionalProfiles 添加SpringProfile 空Set 1.0
setBanner banner 设置Banner实现 null 1.2
setBannerMode bannerMode 设置Banner.Mode,包括日志(LOG),控制台(CONSOLE)和关闭 CONSOLE 1.3
setBeanNameGenerator beanNameGenerator 设置@Configuration Bean名称的生成器实现 null 1.0
setDefaultProperties properties 多个重载方法,配置默认的配置项 null 1.0
setEnvironment environment 关联当前应用的Environment实现类 null 1.0
setInitializers / 覆盖更新ApplicationContextInitializer集合 所有META-INF/spring.factories资源中声明的ApplicationContextInitializer集合 1.0
addInitializers initializers 追加ApplicationContextInitializer集合 同上 1.0
setListeners / 覆盖更新ApplicationListener 所有META-INF/spring.factories资源中声明的ApplicationListener集合 1.0
addListeners initializers 追加ApplicationListener集合 同上 1.0
setLogStartupInfo logStartupInfo 是否日志输出启动时信息 true 1.0
setMainApplicationClass main 设置Main Class,主要用于调整日志输出 由deduceMainApplicationClass()方法推断 1.0
setRegisterShutdownHook registerShutdownHook 设置是否让ApplicationContext注册ShutdownHook线程 true 1.0
setSources sources 增加SpringApplication配资源 空Set 1.0
setWebApplicationType web 设置WebApplicationType 由deduceMainApplicationClass()方法推断 2.0
addPrimarySources / 添加主配置类 有SpringApplication构造参数决定 2.0