本文用一个空的Spring Boot项目演示,从main方法开始顺着源码大概过一遍启动流程。

1 新建项目

spring initializr下载一个demo。我这里选的是java11,maven,spring boot2.4.5,dependencies里面选Spring Web。 启动项目以后在Demo文件夹内新建一个HelloController

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
package com.example.demo;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {
    @GetMapping("/")
    public String hello(){
        return "hello";
    }
}

启动项目,打开http://localhost:8080/,看到hello说明成功。

2 分析源码

首先,main方法里只有一个调用SpringApplication.run(DemoApplication.class, args),这里调用SpringApplication类的run方法,,run是一个静态方法,会触发SpringApplication类的初始化,具体初始化的内容后面用到的部分再说,run方法传入两个参数:

  • DemoApplication.class,当前类的Class对象
  • argsmain方法传递的参数,这里是空

查看run方法,内部调用的最终形式为:
new SpringApplication(primarySources).run(args);
这可以分成两步,第一步是实例化SpringApplication,第二步调用对象的run方法,这里的两个参数分别是:

  • primarySources:new Class[]{DemoApplication.class},把当前启动类的Class传入一个 Class[]数组
  • args:null,我们的demo里没有传入参数

2.1 实例化SpringApplication

我们先来看SpringApplication的实例化,最终执行实例化的是下面这段代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    this.resourceLoader = resourceLoader;//null
    Assert.notNull(primarySources, "PrimarySources must not be null");//检查变量确保不为空

    //把传入的参数放入一个Set<Class<?>>,Set中只有一个值:DemoApplication.class
    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));

    this.webApplicationType = WebApplicationType.deduceFromClasspath();//2.1.1
    
    this.bootstrapRegistryInitializers = getBootstrapRegistryInitializersFromSpringFactories();//2.1.2
    setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));//2.1.3
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));//2.1.4
    this.mainApplicationClass = deduceMainApplicationClass();//2.1.5
}

实例化的过程中初始化了几个属性:

2.1.1 webApplicationType

WebApplicatonType是一个Enum类型,有三个值:REACTIVE,SERVLET,NONE,通过deduceFromClasspath()方法推断类型。

  • deduceFromClasspath()引用ClassUtils类的isPresent(String className, @Nullable ClassLoader classLoader)方法来判断className对应的类是否存在,className是预定义的几个静态常量之一,这些常量的值是类的全限定名,WebApplicatonType通过判断这几个常量对应的类是否存在来推断WebApplicatonType的类型,具体逻辑看源码。 我们这里的结果是WebApplicatonType.SERVLET

2.1.2 bootstrapRegistryInitializers

先看一下调用的方法:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
private List<BootstrapRegistryInitializer> getBootstrapRegistryInitializersFromSpringFactories() {
  //创建一个ArrayList用来保存结果
  ArrayList<BootstrapRegistryInitializer> initializers = new ArrayList<>();

  getSpringFactoriesInstances(Bootstrapper.class).stream()
      .map((bootstrapper) -> ((BootstrapRegistryInitializer) bootstrapper::initialize))
      .forEach(initializers::add);
  initializers.addAll(getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
  return initializers;
}

getSpringFactoriesInstances(Bootstrapper.class)这个方法,会尝试去项目的classpath下查找所有在spring.factoires文件中指定的Bootstrapper.class的实现类,后面的链式操作会根据结果获取对应的BootstrapRegistryInitializer并添加到返回值initializers中,Bootstrapper在springboot2.4.4以后标记为deprecated,并计划在2.6移除,由后面的BootstrapRegistryInitializer取代。

我们的demo中,下面的两个包内有META-INF/spring.factories这个文件:

  • spring-boot-2.4.5.jar
  • spring-boot-autoconfigure-2.4.5.jar

这一步并没有查找到相应的BootstrapRegistryInitializer,返回值为一个空的ArrayList

2.1.3 setInitializers

这一步设置的是private List<ApplicationContextInitializer<?>> initializers这个字段,方法跟前面一样,通过查找spring.factories文件来取得相应的实现类,上面提到的两个文件中都有ApplicationContextInitializer.class的信息,分别是:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#spring-boot-2.4.5.jar/META-INF/spring.factories
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

#spring-boot-autoconfigure-2.4.5.jar/META-INF/spring.factories
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener

所以这一步初始化了initializers,其列表包含7个实现类的信息。

2.1.4 setListeners

setInitializers类似,这一步初始化了private List<ApplicationListener<?>> listeners这个字段,列表包含9个实现类的信息。

2.1.5 mainApplicationClass

通过StackTraceElement的反射信息来推判主启动类,这里是com.example.demo.DemoApplication.class

2.2 运行run方法

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
public ConfigurableApplicationContext run(String... args) {
  StopWatch stopWatch = new StopWatch();//实例化一个计时器
  stopWatch.start();//启动计时器

  DefaultBootstrapContext bootstrapContext = createBootstrapContext();//2.2.1
  ConfigurableApplicationContext context = null;//初始化context
  configureHeadlessProperty();//2.2.2
  SpringApplicationRunListeners listeners = getRunListeners(args);//2.2.3
  listeners.starting(bootstrapContext, this.mainApplicationClass);//2.2.3
  try {
    ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);//2.2.4
    ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);//2.2.5
    configureIgnoreBeanInfo(environment); // 2.2.6
    Banner printedBanner = printBanner(environment); //获取banner
    context = createApplicationContext(); // 2.2.7
    context.setApplicationStartup(this.applicationStartup); // 2.2.8
    prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner); //2.2.9
    refreshContext(context); // 2.2.10
    afterRefresh(context, applicationArguments); // 示例中为空
    stopWatch.stop(); // 停止计时器
    // 在控制台打印计时器的启动时间信息
    if (this.logStartupInfo) {
      new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
    }

    // 通知对应的监听器,表明context已经启动,示例中ApplicationStartedEvent事件对应的监听器没有操作,只触发了AvailabilityChangeEvent事件,表明context正确运行,并在ApplicationAvailabilityBean的events属性中记录相应信息,状态:事件的AMP
    listeners.started(context); 
    callRunners(context, applicationArguments); // 示例中这一步为空。调用ApplicationRunner和CommandLineRunner类型的run方法
  }
  catch (Throwable ex) {
    handleRunFailure(context, ex, listeners);
    throw new IllegalStateException(ex);
  }

  try {
    listeners.running(context); // 通知对应的监听器,表明context已经在运行,跟前面的started类似,这里ApplicationReadyEvent事件对应的监听器没有操作,更新了context的状态ReadinessState.ACCEPTING_TRAFFIC
  }
  catch (Throwable ex) {
    handleRunFailure(context, ex, null);
    throw new IllegalStateException(ex);
  }
  return context; // 2.2.11
}

方法的返回值是ConfigurableApplicationContext,也就是我们的spring容器,方法中的所有步骤都是为这个结果做准备的。上面不重要的步骤用注释带过,复杂点的分别说明。

2.2.1 bootstrapContext

这个变量的类型是DefaultBootstrapContext,它跟ApplicationContext不是同一个分支,只是实现了BootstrapRegistryBootstrapContext这两个接口,里面的功能很相对较少。

变量的值来自方法createBootstrapContext(),实现如下:

1
2
3
4
5
private DefaultBootstrapContext createBootstrapContext() {
  DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();
  this.bootstrapRegistryInitializers.forEach((initializer) -> initializer.initialize(bootstrapContext));
  return bootstrapContext;
}

这个方法先是实例化一个DefaultBootstrapContext对象,然后再尝试用2.1.2描述过的bootstrapRegistryInitializers变量内的实现类去挨个的尝试初始化这个context,但是由前面的分析得知,变量是空的列表,所以这一步被跳过。

方法返回一个默认构造函数构造的DefaultBootstrapContext对象。

2.2.2 configureHeadlessProperty()

尝试设置系统属性java.awt.headless,从而打开headless模式。看方法代码:

1
2
3
4
private void configureHeadlessProperty() {
  System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS,
      System.getProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
}

SYSTEM_PROPERTY_JAVA_AWT_HEADLESS是常量字符串"java.awt.headless"headless的初始化值是true

从上面的代码可以看出来,方法会首先从系统属性中获取java.awt.headless的值,如果已经被设置,就不会去覆盖,只有在没有设置的情况下才会设置成true

为什么 spring boot 要设置headless模式呢?
首先,headless模式的好处在于,如果你的代码需要调用图形界面,那么当运行这段代码的时候,就会直接抛出java.awt.HeadlessException这个异常,headless模式不允许代码去尝试调用图形界面相关功能。
spring boot程序通常都运行在服务器上,服务器没有图形显示功能很正常。如果没有headless模式,可能我们的代码里出现了调用图形界面的情况,然后在PC上调试没有问题,打包到服务器运行的时候,服务器会尝试去调用图形界面功能,发现没有,然后报出相应的错误。

可以用docker模拟服务器环境,Dockerfile内容如下,放在jar包同目录:

1
2
3
4
5
FROM openjdk:11.0.11-oracle
WORKDIR /
ADD demo-0.0.1-SNAPSHOT.jar demo.jar
EXPOSE 8080
CMD ["java", "-Djava.awt.headless=false", "-jar", "demo.jar"]

-Djava.awt.headless=false这个参数可以在启动时(显然在spring boot前)设置java.awt.headless属性,避免被覆盖。

运行docker build ./ -t demo生成镜像,然后运行docker run -p 8080:8080 demo启动测试。

PS:这里可以用JOptionPane.showMessageDialog(new Frame(),“showMessage”);这行代码去测试,它会弹出一个窗口,并且只有点击这个窗口的OK键程序才会继续执行(有时候弹出的窗口并没有在最顶层,用alt+tab键在所有窗口中找一下)。把这行代码分别放在SpringApplication.run(DemoApplication.class, args);之前,和放HelloController的return语句之前,也就是在spring 容器外和容器内分别测试,后者的报错信息量大且没有前者提示明显,也就是不开启headless模式更容易出现的情况。

2.2.3 listeners

注意:这是run方法内的局部变量,虽然名称跟前面SpringApplication对象的字段一样(2.1.4 setListeners)

这里的listeners声明为SpringApplicationRunListeners类型,这个类型封装了一组SpringApplicationRunListener监听器(针对SpringApplicationrun方法的监听器)。

2.2.3-1 声明并初始化listeners变量

SpringApplicationRunListeners listeners = getRunListeners(args)
getRunListeners方法来初始化,方法实现如下:

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

实际上就是调用构造函数,logger是在SpringApplication进于类初始化的时候设置好的字段: private static final Log logger = LogFactory.getLog(SpringApplication.class);,日志主要是记录失败相关的信息

getSpringFactoriesInstances方法中的参数是为了匹配类的构造函数,这里只有一个监听器实现类org.springframework.boot.context.event.EventPublishingRunListener,匹配到public EventPublishingRunListener(SpringApplication application, String[] args)这个构造函数进行实例化

2.2.3-2 listeners.starting(bootstrapContext, this.mainApplicationClass)

调用SpringApplicationRunListenersstarting方法:

1
2
3
4
5
6
7
8
void starting(ConfigurableBootstrapContext bootstrapContext, Class<?> mainApplicationClass) {
  doWithListeners("spring.boot.application.starting", (listener) -> listener.starting(bootstrapContext),
      (step) -> {
        if (mainApplicationClass != null) {
          step.tag("mainApplicationClass", mainApplicationClass.getName());
        }
      });
}

doWithListeners会遍历每一个SpringApplicationRunListeners的实现类,调用其starting方法, 上面提到只有一个实现类EventPublishingRunListener,它的starting方法如下:

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

initialMulticaster.multicastEvent的作用就是把ApplicationStartingEvent这个启动事件传播给所有的支持这个事件的监听器,这些监听器是从前面SpringApplication实例化时得到的9个监听器中筛选出来的(筛选过程就是判断监听器是否支持事件本身以及其source的类型),筛选后的监听器会去判断自身是否含有处理这个事件的代码,如果有,则执行相应的逻辑,在这个例子中只有org.springframework.boot.context.logging.LoggingApplicationListener有相应的逻辑。

2.2.4 ApplicationArguments applicationArguments = new DefaultApplicationArguments(args)

args参数包装在ApplicationArguments里面,这里args的值是空的Sttring[]

2.2.5 prepareEnvironment

ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments)

3个参数在前面都介绍过,看一下方法主体:

 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 ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
    DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
  // Create and configure the environment
  ConfigurableEnvironment environment = getOrCreateEnvironment();
  configureEnvironment(environment, applicationArguments.getSourceArgs());
  ConfigurationPropertySources.attach(environment);

  listeners.environmentPrepared(bootstrapContext, environment);

  DefaultPropertiesPropertySource.moveToEnd(environment);//尝试移动defaultproperties,我们这里是null,所以无操作

  configureAdditionalProfiles(environment);//配置additionalProfiles,这里是空的集合,所以无操作

  bindToSpringApplication(environment);

  // 确保enviroment类型正确
  if (!this.isCustomEnvironment) {
    environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
        deduceEnvironmentClass());
  }

  //从上一次attach之后,enviroment中的propertysources已经发生变化,这里重新attach一次
  ConfigurationPropertySources.attach(environment);
  return environment;
}

先初始化一个enviroment对象,getOrCreateEnvironment会根据前面的webApplicationType来获取一个初始值,我们的例子中是new StandardServletEnvironment(),在实例化这个对象的过程中,它会调用祖先类AbstractEnvironment的构造函数来执行自身的customizePropertySources方法,从而设置几个PropertySource

然后调用configureEnvironment方法,这一步主要是给enviroment设置conversionService,祖先类AbstractEnvironment的构造函数中初始化了一个字段propertyResolver,类型是PropertySourcesPropertyResolverconversionService就是设置在propertyResolver上的

attach方法把enviroment里面的propertysource封装到ConfigurationPropertySourcesPropertySource内,并把封装后的元素添加到propertysource的第1个位置,看下面这行代码:

1
2
sources.addFirst(new ConfigurationPropertySourcesPropertySource(ATTACHED_PROPERTY_SOURCE_NAME,
    new SpringConfigurationPropertySources(sources)));

被封装的sources是一个引用对象,也就是说,当sources.addFirst这个操作完成后,被封装的sources也发生了变化,sources可以在自身包含的元素中看到对自身的引用,如果在调试时查看source内容,可以"无限展开",如下图:

显示图片

图片

listeners.environmentPrepared(bootstrapContext, environment);“这一行触发事件environmentPrepared,通知所有符合条件的监听器执行操作,spring boot的application.properties配置文件就是在这时候被读取并解析的,在org.springframework.boot.env.PropertiesPropertySourceLoader这个类的load方法打个断点,就能反向的看到整个过程。

bindToSpringApplication(environment);把配置文件中的spring.main前缀的属性绑定到SpringApplication实例(配置文件中的信息已经在上一步操作中绑定到了enviroment变量中),比如我们在application.properties配置文件中设置了spring.main.banner-mode=off(默认值是console),在bind这一步完成后,值就变成了off。spring.main对应的都是SpringApplication中的字段(但不是所有字段都开放修改),可以在配置文件中覆盖默认值。

2.2.6 configureIgnoreBeanInfo(environment)

设置spring.beaninfo.ignore这个系统变量的值,如果之前已经设置,则跳过,如果没有设置,则设为true

2.2.7 createApplicationContext()

给context赋值,根据webApplicationType的值返回对应的实例,我们的例子是SERVLET,返回new AnnotationConfigServletWebServerApplicationContext(),相当于一个基准容器。

这个方法调用的是ApplicationContextFactorycreate方法,而实现ApplicationContextFactory接口的实例DEFAULT是通过lambda表达式给出的。

2.2.8 context.setApplicationStartup(this.applicationStartup)

设置applicationStartup这个字段,值是ApplicationStartup.DEFAULT,这里调用的是当前context的祖先类GenericApplicationContext里的setApplicationStartup方法,如下:

1
2
3
4
5
@Override
public void setApplicationStartup(ApplicationStartup applicationStartup) {
  super.setApplicationStartup(applicationStartup);
  this.beanFactory.setApplicationStartup(applicationStartup);
}

分两步,首先设置它的父类AbstractApplicationContext的字段applicationStartup,然后设置它的字段beanFactory内的字段applicationStartupbeanFactory的类型是DefaultListableBeanFactory,实际上这两处设置的字段,本身的初始化值就是ApplicationStartup.DEFAULT

2.2.9 prepareContext

传入前面设置好的多个变量,给容器作调整,方法如下:

 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
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
  context.setEnvironment(environment);
  postProcessApplicationContext(context);
  applyInitializers(context);
  listeners.contextPrepared(context); // 触发contextPrepared事件,让对应的监听器处理,这里有两个监听器符合条件,但无处理操作

  bootstrapContext.close(context); // 关闭bootstrapContext并触发相关事件,此处无对应监听器

  if (this.logStartupInfo) { // 是否打印启动信息
    logStartupInfo(context.getParent() == null); // 对应启动信息里的第一行
    logStartupProfileInfo(context); // // 对应启动信息里的第f二行
  }

  // Add boot specific singleton beans
  ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); // 获取beanfactory,值是`new DefaultListableBeanFactory()`
  beanFactory.registerSingleton("springApplicationArguments", applicationArguments); //注册applicationArguments

  if (printedBanner != null) { //如果application.properties里设置了spring.main.banner-mode=off,这里就跳过
    beanFactory.registerSingleton("springBootBanner", printedBanner); // 注册Banner
  }

  if (beanFactory instanceof DefaultListableBeanFactory) { // true

    // 给beanFactory设置是否允许BeanDefinitionOverriding,值是false
    ((DefaultListableBeanFactory) beanFactory)
        .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
  }
  if (this.lazyInitialization) { // false
    context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
  }
  // Load the sources
  Set<Object> sources = getAllSources();
  Assert.notEmpty(sources, "Sources must not be empty"); // 检查sources不为空
  load(context, sources.toArray(new Object[0])); 
  listeners.contextLoaded(context); 
}
  • context.setEnvironment(environment):把环境变量设置到context的对应字段上,分别是其祖先类AbstractApplicationenviroment字段,及readerscanner的相关字段

  • postProcessApplicationContext(context):对context作一些补充设置,判断beanNameGeneratorresourceLoaderaddConversionService这3个字段是否被设置,如果是,则对context作相应的设置,这里前面2个都是Null,第3个设置到context的祖先类AbstractBeanFactory的字段上

  • applyInitializers(context):用2.1.3设置的initializer挨个对context执行初始化。

  • Set<Object> sources = getAllSources():获取this.primarySource(见2.1,值是com.example.demo.DemoApplication.class)和this.sources的值(空集合)

  • load(context, sources.toArray(new Object[0])):把主启动类注册到context

  • listeners.contextLoaded(context):发出contextLoaded事件,在EventPublishingRunListener中用ApplicationPreparedEvent包装。主要是LoggingApplicationListener注册了两个log相关的singletonbean,及EnvironmentPostProcessorApplicationListenerlog进行一些处理。

2.2.10 refreshContext

首先确保registerShutdownHook存在,不存在的话创建一个。这个勾子函数的作用是在JVM关闭的时候,先关闭context,但是如果JVM是非正常退出,比如被系统中止进程,内存访问出错等,那勾子函数不一定生效。

实现的方法在AbstractApplicationContextrefresh,如下:

 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
69
70
71
72
73
74
75
76
77
78
@Override
public void refresh() throws BeansException, IllegalStateException {
  synchronized (this.startupShutdownMonitor) {
    StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

    // Prepare this context for refreshing.
    prepareRefresh(); // 初始化一些属性,判断this.earlyApplicationListeners是否有值,有的话把这些值传入this.applicationListeners(先清空),如果没有,则反过来,把this.applicationListeners的值传给this.earlyApplicationListeners

    // Tell the subclass to refresh the internal bean factory.
    ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // 获取beanFactory,类型是DefaultListableBeanFactory,设置了serializableId=application

    // Prepare the bean factory for use in this context.
    prepareBeanFactory(beanFactory);

    try {

      // 添加一个WebApplicationContextServletContextAwareProcessor类型的postProcessor,及把ServletContextAware.class接口添加到ignoreDependencyInterface列表内
      // Allows post-processing of the bean factory in context subclasses.
      postProcessBeanFactory(beanFactory);

      // 启动一个步骤,步骤可以记录它开始到结束的数据,或者步骤耗时等,这里用处不大
      StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
      
      // Invoke factory processors registered as beans in the context.
      invokeBeanFactoryPostProcessors(beanFactory);

      // Register bean processors that intercept bean creation.
      registerBeanPostProcessors(beanFactory);
      // 结束步骤
      beanPostProcess.end();

      // Initialize message source for this context.
      // 初始化MessageSource,这里是空,并且步骤中会记录trace级别的log,如果在application.properties中开启的话,就可以看到
      initMessageSource();

      // Initialize event multicaster for this context.
      // 初始化applicationEventMulticaster属性,示例中用的是SimpleApplicationEventMulticaster类型
      initApplicationEventMulticaster();

      // Initialize other special beans in specific context subclasses.
      // 启动内嵌的tomcat容器,console输出相关5条INFO级别信息
      onRefresh();

      // Check for listener beans and register them.
      // 找到context中直接存在的listener以及bean中属于ApplicationListener类型的bean,注册到ApplicationEventMulticaster中(示例实现类是SimpleApplicationEventMulticaster)
      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();
      contextRefresh.end();
    }
  }
}
  • prepareBeanFactory:对beanFactory进行各种设置,方法如下,用注释说明。
 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
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
  // Tell the internal bean factory to use the context's class loader etc.
  beanFactory.setBeanClassLoader(getClassLoader());

  if (!shouldIgnoreSpel) { // 是否忽略SpEL(Spring Expression Language),这里是不忽略,所以设置相应的解析器
    beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
  }

  // 添加一个propertyEditor的注册器,用来注册各种editor
  beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

  // Configure the bean factory with context callbacks.
  beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); // 添加一个beanPostProcessor,类型是ApplicationContextAwareProcessor,如果原先存在,则先删除再添加,添加在AbstractBeanFactory的beanPostProcessors属性上

  // 添加下面的几个类到ignoredDependencyInterfaces属性(从DefaultListableBeanFactory的父类AbstractAutowireCapableBeanFactory中继承),后面的一些操作会根据这个set属性中的接口来判断是否要过滤相应的属性(判断属性的setter方法是否源于实现相应的接口方法)
  // BeanFactoryAware.class是默认添加的
  beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
  beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
  beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
  beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
  beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
  beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
  beanFactory.ignoreDependencyInterface(ApplicationStartupAware.class);

  // 这一步类似于手动装配,第1个参数是类型,第2个参数是这个类型返回的实例,如果第2个参数实现了第1个参数的子接口,那么这个子接口也会被装配
  // BeanFactory interface not registered as resolvable type in a plain factory.
  // MessageSource registered (and found for autowiring) as a bean.
  beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
  beanFactory.registerResolvableDependency(ResourceLoader.class, this);
  beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
  beanFactory.registerResolvableDependency(ApplicationContext.class, this);

  // 添加一个针对ApplictionListener后处器
  // Register early post-processor for detecting inner beans as ApplicationListeners.
  beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

  // 跳过,loadTimeWeaver在JVM加载类之前通过transformer对类其进行处理,这里没有这个bean
  // Detect a LoadTimeWeaver and prepare for weaving, if found.
  if (!NativeDetector.inNativeImage() && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
    beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
    // Set a temporary ClassLoader for type matching.
    beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
  }

  // 确保下面几个类型的bean都注册了,如果没注册,就设置为当前context相关的实例
  // Register default environment beans.
  if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
    beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
  }
  if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
    beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
  }
  if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
    beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
  }
  if (!beanFactory.containsLocalBean(APPLICATION_STARTUP_BEAN_NAME)) {
    beanFactory.registerSingleton(APPLICATION_STARTUP_BEAN_NAME, getApplicationStartup());
  }
}
  • invokeBeanFactoryPostProcessors(beanFactory):从context中获取beanFactoryPostProcessors对当前的beanFactory进行处理,实现这个功能的方法是PostProcessorRegistrationDelegateinvokeBeanFactoryPostProcessors,方法内容很多,方法中涉及的内容只用注释说明,不再继续展开,方法如下:
展开内容
  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
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
public static void invokeBeanFactoryPostProcessors(
			ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

		// Invoke BeanDefinitionRegistryPostProcessors first, if any.
		Set<String> processedBeans = new HashSet<>();

		if (beanFactory instanceof BeanDefinitionRegistry) {
			BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
			List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
			List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();

     // 先对beanFactory这个bean自身的definition的注册进行处理
     // 在我们的例子中有两个`beanFactoryPostProcessor`,都是嵌套类,分别是
     // `SharedMetadataReaderFactoryContextInitializer.CachingMetadataReaderFactoryPostProcessor`
     // 和`ConfigurationWarningsApplicationContextInitializer.ComponentScanPackageCheck`,
     // 第1个给名字为`org.springframework.context.annotation.internalConfigurationAnnotationProcessor`
     // 的`beanDefination`(对应的`Class`是`ConfigurationClassPostProcessor`)添加一个`propertyValue`,键值对是`metadataReaderFactory`:
     // `<org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory>`。
     // 第2个扫描所有的`beanDefinition`,判断`@ComponentScan`注解是否可以正常运行。
			for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
        // 这一步两个都是
				if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
					BeanDefinitionRegistryPostProcessor registryProcessor =
							(BeanDefinitionRegistryPostProcessor) postProcessor;
					registryProcessor.postProcessBeanDefinitionRegistry(registry);
					registryProcessors.add(registryProcessor);
				}
				else {
					regularPostProcessors.add(postProcessor);
				}
			}

			// Do not initialize FactoryBeans here: We need to leave all regular beans
			// uninitialized to let the bean factory post-processors apply to them!
			// Separate between BeanDefinitionRegistryPostProcessors that implement
			// PriorityOrdered, Ordered, and the rest.
			List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

			// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
      // 先调用实现了PriorityOrdered接口的处理器
      // 从beanFactory中获取处理bean注册的类的beanName,本例中只有1个:org.springframework.context.annotation.internalConfigurationAnnotationProcessor,对应ConfigurationClassPostProcessor
			String[] postProcessorNames =
					beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
      // 只添加实现了PriorityOrdered接口的postProcessor
			for (String ppName : postProcessorNames) {
				if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					processedBeans.add(ppName);
				}
			}
      // 排序
			sortPostProcessors(currentRegistryProcessors, beanFactory);
      // 添加registryProcessors中,加上第1步的2个,总共3个
			registryProcessors.addAll(currentRegistryProcessors);
      // 这一步对已经注册的bean进行处理,包括主启动类demo,解析它的@SpringbootApplication注解,并解析其子注解,是Springboot注解驱动的重要实现,示例中的130多个bean在这里被注册
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
			currentRegistryProcessors.clear(); // 清空列表

			// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
      // 在调用了实现Priority接口的处理器后,接着调用实现了Ordered接口的处理器
      //这里获取到org.springframework.context.annotation.internalConfigurationAnnotationProcessorp这个名字,不过在前面的for循环中已经被处理过,所以跳过了
			postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			for (String ppName : postProcessorNames) {
				if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					processedBeans.add(ppName);
				}
			}
      // currentRegistryProcessors已经被清空,所以下面几步都没有实际作
			sortPostProcessors(currentRegistryProcessors, beanFactory);
			registryProcessors.addAll(currentRegistryProcessors);
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
			currentRegistryProcessors.clear();

			// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
      // while循环的内容跟上面是一样的,现在处理剩下的没有实现PriorityOrdered和Ordered接口的bean,也只有internalConfigurationAnnotationProcessorp这个在processedBeans中已经存在的bean,所以while循环内也没有实际操作
			boolean reiterate = true;
			while (reiterate) {
				reiterate = false;
				postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
				for (String ppName : postProcessorNames) {
					if (!processedBeans.contains(ppName)) {
						currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
						processedBeans.add(ppName);
						reiterate = true;
					}
				}
				sortPostProcessors(currentRegistryProcessors, beanFactory);
				registryProcessors.addAll(currentRegistryProcessors);
				invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
				currentRegistryProcessors.clear();
			}

			// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
      // 调用registryProcessors中的后处理器去处理beanFactory中的所有bean,这里有效处理器只有ConfigurationClassPostProcessor这一个,遍历的bean有130多个
			invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);.
      // 参数1是空,所以跳过
			invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
		}

		else {
			// Invoke factory processors registered with the context instance.
			invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
		}



    // 从当前的beanFactory取出所有BeanFactoryPostProcessor类型的bean,然后按照上面一样的流程,先分3类:PriorityOrdered,Ordered,nonOrdered3类,再按照这个顺序依次处理
		// Do not initialize FactoryBeans here: We need to leave all regular beans
		// uninitialized to let the bean factory post-processors apply to them!
		String[] postProcessorNames =
				beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

		// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
		// Ordered, and the rest.
		List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
		List<String> orderedPostProcessorNames = new ArrayList<>();
		List<String> nonOrderedPostProcessorNames = new ArrayList<>();
		for (String ppName : postProcessorNames) {
			if (processedBeans.contains(ppName)) {
				// skip - already processed in first phase above
			}
			else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
				priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
			}
			else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
				orderedPostProcessorNames.add(ppName);
			}
			else {
				nonOrderedPostProcessorNames.add(ppName);
			}
		}

		// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
		sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
		invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

		// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
		List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
		for (String postProcessorName : orderedPostProcessorNames) {
			orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
		}
		sortPostProcessors(orderedPostProcessors, beanFactory);
		invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

		// Finally, invoke all other BeanFactoryPostProcessors.
		List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
		for (String postProcessorName : nonOrderedPostProcessorNames) {
			nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
		}
		invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

		// Clear cached merged bean definitions since the post-processors might have
		// modified the original metadata, e.g. replacing placeholders in values...
		beanFactory.clearMetadataCache();
	}
  • registerBeanPostProcessors:注册beanPostProcessors,先从beanFactory中获取BeanPostProcessor类型的相关信息,再生成对应的bean,最后注册到beanFactorybeanPostProcessors这个字段中。

  • finishBeanFactoryInitialization:把beanNames里面所有还没有生成的bean全部生成,注册到singletonObjects并在registeredSingletons中添加名称,如果bean实现了SmartInitializingSingleton接口,则再调用其afterSingletonsInstantiated方法对bean进行一些额外的处理。在这一步控制台输出一条跟ExecutorService有关的信息。

  • finishRefresh:释放一些资源,初始化跟LifeCycle有关的处理器(示例中是default的处理器),然后调用这个处理器的onRefresh方法,这里启动了Tomcat,可以在控制台看到相关信息。接着发布了ContextRefreshedEvent类型的事件,去触发相应的操作。

3 总结

spring boot框架非常庞大,本文只是简单的跟着run方法走了一遍启动流程,源码中的一些实现细节也没法全部展开,可以在需要的时候打断点分析,而且示例中没有包含AOP的内容,所以后续流程中也没有涉及。
总的来说,整个启动流程就是为了配置好context这个容器,其中包含了大量的监听器和事件的内容,在特定的步骤通过分发阶段性事件的方式来启动相应的工作。