SpringBoot启动流程及当中的扩展点分析

SpringBoot作为Javer最常使用的框架,了解其启动流程有利于我们日常开发工作者排查问题,进行自定义扩展等。本文将详细介绍SpringBoot的启动流程,并分析其启动中我们可以利用的扩展点。文章较长,请耐心阅读。文中参杂了很多源代码,建议一边看一边进行调试追踪源码。

先来一段经典的SpringBoot启动代码

@SpringBootApplication
public class SpringbootDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootDemoApplication.classargs);
    }
}

SpringBoot应用程序的启动是调用SpringApplication的静态run方法开始的,我们看一下其源代码

public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
    return run(new Class<?>[] { primarySource }, args);
}

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

可以看到,启动程序是先将启动类,即示例代码中的SpringbootDemoApplication类作为参数,构造出一个SpringApplication实例,再调用这个SpringApplication实例的run方法进行启动

getSpringFactoriesInstances

这里我们先了解一下SpringBoot中很常见的getSpringFactoriesInstances方法

// 从各个jar包中的spring.factories中获取到类型为type的类,并将其实例化
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
    return getSpringFactoriesInstances(type, new Class<?>[] {});
}

/**
 * 从各个jar包中的spring.factories中获取到类型为type的类,并调用其构造函数参数类型为parameterTypes的函数进行初始化
 * type: 从各个jar包中的spring.factories中获取到类型为type的类
 * parameterTypes: 构造函数的参数类型列表
 * args: 构造函数的参数列表
 */

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
    ClassLoader classLoader = getClassLoader();
    // 调用SpringFactoriesLoader,找到其中类型为type的类,返回这些类的全限定名
    Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
    // 构造上面这些类的实例
    List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
    // 按照注解排个序,即@Order
    AnnotationAwareOrderComparator.sort(instances);
    // 返回这些实例
    return instances;
}

上面代码中,通过SpringFactoriesLoader加载类型为type的类。这里我们不深入分析了,简单来说,SpringFactoriesLoader就是加载类路径下,所有的META-INF/spring.factories文件,这些文件中是一个properties文件,其中定义了各个类型(即type)及其实现子类,以下是一个文件实例
key就是type的全限定名,value就是我们返回的类名的集合
SpringBoot启动流程及当中的扩展点分析

SpringApplication构造方法

public SpringApplication(Class<?>... primarySources) {
    this(null, primarySources);
}

/**
* resourceLoader 资源加载器,默认为空
* primarySources 我们的启动类的class
*/

@SuppressWarnings({ "unchecked""rawtypes" })
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    // 资源加载器,默认为空
    this.resourceLoader = resourceLoader;
    Assert.notNull(primarySources, "PrimarySources must not be null");
    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    // 1. 检测Web应用程序类型
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    // 2. 加载引导上下文的初始化器,引导上下文也是一个容器,主要应用在SpringBoot启动阶段引导应用程序上下文启动
    this.bootstrapRegistryInitializers = new ArrayList<>(
            getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
    // 3. 加载应用程序初始化器
    setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    // 4. 加载监听器
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    // 5. 设置主启动类
    this.mainApplicationClass = deduceMainApplicationClass();
}

我们来挨个分析其中的代码

检测Web应用程序类型

检测Web应用程序类型是由WebApplicationType完成的,以下是WebApplicationType的源代码

public enum WebApplicationType {
 // 说明不是Web应用程序,不应该启动Web服务器
 NONE,
 // 说明应用程序是基于Servlet启动的,会启动内嵌的Web服务器
 SERVLET,
 // 说明应用程序时基于响应式的web应用程序,会启动内嵌的响应式Web服务器
 REACTIVE;

 private static final String[] SERVLET_INDICATOR_CLASSES = { "javax.servlet.Servlet",
   "org.springframework.web.context.ConfigurableWebApplicationContext" };

 private static final String WEBMVC_INDICATOR_CLASS = "org.springframework.web.servlet.DispatcherServlet";

 private static final String WEBFLUX_INDICATOR_CLASS = "org.springframework.web.reactive.DispatcherHandler";

 private static final String JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer";

 static WebApplicationType deduceFromClasspath() {
        // 如果类路径下有DispatcherHandler并且没有DispatcherServlet,也没有ServletContainer,说明是响应式Web应用程序
  if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
    && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
   return WebApplicationType.REACTIVE;
  }
        // 如果类路径下没有Setvlet相关类,则说明不是Web应用程序
  for (String className : SERVLET_INDICATOR_CLASSES) {
   if (!ClassUtils.isPresent(className, null)) {
    return WebApplicationType.NONE;
   }
  }
        // 其余情况表示是普通的Servlet的Web应用程序
  return WebApplicationType.SERVLET;
 }
}

加载引导上下文的初始化器

接下来是加载引导上下文的初始化器,即BootstrapRegistryInitializer的实例,我们可以看一下BootstrapRegistryInitializer的源代码

// BootstrapRegistry的回调接口,在BootstrapRegistry使用之前对BootstrapRegistry进行处理
@FunctionalInterface
public interface BootstrapRegistryInitializer {

 void initialize(BootstrapRegistry registry);

}

在这里就不得不先提到引导上下文BootstrapContext,它是一个小容器,专门在SpringBoot启动过程中引导应用程序容器启动,而BootstrapContext目前只有唯一一个实现类DefaultBootstrapContext,而它同时实现了BootstrapRegistry。BootsstrapRegistryInitializer就是对这个DefaultBootstrapContext做处理的
SpringBoot启动流程及当中的扩展点分析而默认情况下,SpringBoot并没有定义任何的BootstrapRegistryInitializer

加载应用程序初始化器

应用程序初始化器,对应用程序上下文进行初始化处理的

/**
 * ConfigurableApplicationContext的回调接口,会在refresh方法调用之前对ApplicationContext进行处理
 * 一般用于对ApplicationContext进行一些初始化工作,比如注册一个属性源或者激活某个profile
 *
 * ApplicationContextInitializer会按照Ordered接口或者@Order注解定义的优先级进行排序
 */

@FunctionalInterface
public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext{

 void initialize(C applicationContext);

}

以下是SpringBoot默认提供的应用程序上下文的初始化器
SpringBoot启动流程及当中的扩展点分析

加载监听器

// 应用程序监听器,监听ApplicationEvent接口。是基于观察者模式创建的接口
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEventextends EventListener {

 void onApplicationEvent(E event);

 /**
     * 静态方法,为消息类型T创建一个监听器
  */

 static <T> ApplicationListener<PayloadApplicationEvent<T>> forPayload(Consumer<T> consumer) {
  return event -> consumer.accept(event.getPayload());
 }
}

我们再看看SpringBoot默认提供了哪些应用监听器
SpringBoot启动流程及当中的扩展点分析

设置主启动类

private Class<?> deduceMainApplicationClass() {
    try {
        StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
        for (StackTraceElement stackTraceElement : stackTrace) {
            if ("main".equals(stackTraceElement.getMethodName())) {
                return Class.forName(stackTraceElement.getClassName());
            }
        }
    }
    catch (ClassNotFoundException ex) {
        // Swallow and continue
    }
    return null;
}

这个代码非常有意思,它是手动创建了一个异常,然后追踪异常堆栈信息,找到main方法所在的类,它就是启动类

run方法解析

看完了SpringApplication的构造方法逻辑,我们接下来看看run方法的实现

// 创建应用程序的ApplicationContext,并进行刷新启动
public ConfigurableApplicationContext run(String... args) {
    long startTime = System.nanoTime();
    // 1. 创建引导上下文
    DefaultBootstrapContext bootstrapContext = createBootstrapContext();
    ConfigurableApplicationContext context = null;
    // 配置无头模式参数,不做分析
    configureHeadlessProperty(); 
    // 2. 创建SpringBootRunListeners,即启动过程中的监听器。在启动过程中会触发这些监听器
    SpringApplicationRunListeners listeners = getRunListeners(args);
    // 触发应用程序开始启动的事件
    listeners.starting(bootstrapContext, this.mainApplicationClass);
    try {
        // 解析命令行参数,封装到ApplicationArguments
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        // 3. 准备好Environment
        ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
        configureIgnoreBeanInfo(environment);
        // 输出banner,不重要,忽略
        Banner printedBanner = printBanner(environment);
        // 4. 创建应用程序上下文
        context = createApplicationContext();
        context.setApplicationStartup(this.applicationStartup);
        // 5. 准备好应用程序上下文
        prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
        // 6. 刷新应用程序上下文
        refreshContext(context);
        // 刷新后的处理,默认没有实现,这个是交给子类实现的
        afterRefresh(context, applicationArguments);
        Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
        if (this.logStartupInfo) {
            new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
        }
        // 触发启动完毕的事件
        listeners.started(context, timeTakenToStartup);
        // 7. 调用SpringRunner
        callRunners(context, applicationArguments);
    }
    catch (Throwable ex) {
        // 处理启动失败
        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;
}


创建引导上下文createBootstrapContext

SpringApplication会调用createBootstrapContext方法创建引导上下文

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

这里就可以看到,在SpringApplication构造方法中的BootstrapRegistryInitializers就会应用到DefaultBootstrapContext中。这也是SpringBoot提供的扩展点之一

当前扩展点图谱

SpringBoot启动流程及当中的扩展点分析

创建SpringApplicationRunListeners

private SpringApplicationRunListeners getRunListeners(String[] args) {
    Class<?>[] types = new Class<?>[] { SpringApplication.classString[].class };
    return new SpringApplicationRunListeners(logger,
            getSpringFactoriesInstances(SpringApplicationRunListener.classtypesthisargs),
            this.applicationStartup)
;
}

SpringApplicationRunListener

SpringApplicationRunListener监听run方法的各个阶段,在不同的阶段监听不同的事件

// 对run方法中的各个阶段进行监听触发,其实现类必须有一个公共构造参数,其接受的参数为
// SpringApplication和[]String,前者为SpringApplication的实例,后者为启动应用程序输入的参数
public interface SpringApplicationRunListener {

 /**
  * 在run方法开始启动时触发
  * @param bootstrapContext 引导上下文
  */

 default void starting(ConfigurableBootstrapContext bootstrapContext) {
 }

 /**
     * 当Environment准备完毕时触发,此时应用程序上下文ApplicationContext还没有被创建
     * 触发方法为prepareEnvironment
  * @param bootstrapContext 引导上下文
  * @param environment Environment实例
  */

 default void environmentPrepared(ConfigurableBootstrapContext bootstrapContext,
   ConfigurableEnvironment environment)
 
{
 }

 /**
     * 在应用程序上下文ApplicationContext创建并准备完成时触发
     * 触发方法为prepareContext
  * @param context 应用程序上下文
  */

 default void contextPrepared(ConfigurableApplicationContext context) {
 }

 /**
     * 在应用程序上下文ApplicationContext载入初始化bean之后触发,此时还未触发上下文的refresh方法
  * 触发方法文prepareContext
  * @param context 应用程序上下文
  */

 default void contextLoaded(ConfigurableApplicationContext context) {
 }

 /**
     * 在应用程序上下文刷新并启动完成之后触发,此时CommandLineRunner和ApplicationRunner还未触发
     * 在run方法内触发
  * @param context 应用程序上下文
  * @param timeTaken 从应用程序启动至触发started事件触发花费的时间,可能为null
  * @since 2.6.0
  */

 default void started(ConfigurableApplicationContext context, Duration timeTaken) {
  started(context);
 }

 /**
  * 早期的started方法,已弃用
  */

 @Deprecated
 default void started(ConfigurableApplicationContext context) {
 }

 /**
     * 在应用程序启动并刷新完成,并且所有的CommandLineRunner和ApplicationRunner都运行完成之后触发
     * 在run方法内触发
  * @param context 应用程序上下文
  * @param timeTaken 从应用程序启动至触发ready事件触发花费的事件,可能为null
  * @since 2.6.0
  */

 default void ready(ConfigurableApplicationContext context, Duration timeTaken) {
  running(context);
 }

 /**
     * 早期的ready方法,已弃用
  */

 @Deprecated
 default void running(ConfigurableApplicationContext context) {
 }

 /**
  * 当启动应用失败时触发
  * @param context 应用程序上下文,可能为null
  * @param exception 导致启动失败的异常
  * @since 2.0.0
  */

 default void failed(ConfigurableApplicationContext context, Throwable exception) {
 }
}

接下来看看SpringBoot默认提供的SpringApplicationRunListener
SpringBoot启动流程及当中的扩展点分析

SpringApplicationRunListeners

SpringApplicationRunListeners是一个封装类,其中封装了一个SpringApplicationRunListener的列表,当触发某个事件是,就挨个调用其中的SpringApplicationRunListener的对应方法

class SpringApplicationRunListeners {

 private final Log log;

 private final List<SpringApplicationRunListener> listeners;

 private final ApplicationStartup applicationStartup;

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

 void starting(ConfigurableBootstrapContext bootstrapContext, Class<?> mainApplicationClass) {
  doWithListeners("spring.boot.application.starting", (listener) -> listener.starting(bootstrapContext),
    (step) -> {
     if (mainApplicationClass != null) {
      step.tag("mainApplicationClass", mainApplicationClass.getName());
     }
    });
 }

 void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
  doWithListeners("spring.boot.application.environment-prepared",
    (listener) -> listener.environmentPrepared(bootstrapContext, environment));
 }

 void contextPrepared(ConfigurableApplicationContext context) {
  doWithListeners("spring.boot.application.context-prepared", (listener) -> listener.contextPrepared(context));
 }

 void contextLoaded(ConfigurableApplicationContext context) {
  doWithListeners("spring.boot.application.context-loaded", (listener) -> listener.contextLoaded(context));
 }

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

 void ready(ConfigurableApplicationContext context, Duration timeTaken) {
  doWithListeners("spring.boot.application.ready", (listener) -> listener.ready(context, timeTaken));
 }

 void failed(ConfigurableApplicationContext context, Throwable exception) {
  doWithListeners("spring.boot.application.failed",
    (listener) -> callFailedListener(listener, context, exception), (step) -> {
     step.tag("exception", exception.getClass().toString());
     step.tag("message", exception.getMessage());
    });
 }

 private void callFailedListener(SpringApplicationRunListener listener, ConfigurableApplicationContext context,
   Throwable exception)
 
{
  try {
   listener.failed(context, exception);
  }
  catch (Throwable ex) {
   if (exception == null) {
    ReflectionUtils.rethrowRuntimeException(ex);
   }
   if (this.log.isDebugEnabled()) {
    this.log.error("Error handling failed", ex);
   }
   else {
    String message = ex.getMessage();
    message = (message != null) ? message : "no error message";
    this.log.warn("Error handling failed (" + message + ")");
   }
  }
 }

 private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction) {
  doWithListeners(stepName, listenerAction, null);
 }

 private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction,
   Consumer<StartupStep> stepAction)
 
{
  StartupStep step = this.applicationStartup.start(stepName);
        // 调用每个方法
  this.listeners.forEach(listenerAction);
  if (stepAction != null) {
   stepAction.accept(step);
  }
  step.end();
 }

}

EventPublishingRunListener

SpringBoot默认使用EventPublishingRunListener作为run方法的监听者,我们来看看其源代码

/**
 * SpringApplicationRunListener 的实现类,它主要是依赖Spring的事件分发机制来触发事件
 */

public class EventPublishingRunListener implements SpringApplicationRunListenerOrdered {

 private final SpringApplication application;

 private final String[] args;

 private final SimpleApplicationEventMulticaster initialMulticaster;

 public EventPublishingRunListener(SpringApplication application, String[] args) {
  this.application = application;
  this.args = args;
  this.initialMulticaster = new SimpleApplicationEventMulticaster();
  for (ApplicationListener<?> listener : application.getListeners()) {
   this.initialMulticaster.addApplicationListener(listener);
  }
 }

 @Override
 public int getOrder() {
  return 0;
 }

 @Override
 public void starting(ConfigurableBootstrapContext bootstrapContext) {
  this.initialMulticaster
    .multicastEvent(new ApplicationStartingEvent(bootstrapContext, this.application, this.args));
 }

 @Override
 public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext,
   ConfigurableEnvironment environment)
 
{
  this.initialMulticaster.multicastEvent(
    new ApplicationEnvironmentPreparedEvent(bootstrapContext, this.application, this.args, environment));
 }

 @Override
 public void contextPrepared(ConfigurableApplicationContext context) {
  this.initialMulticaster
    .multicastEvent(new ApplicationContextInitializedEvent(this.application, this.args, context));
 }

 @Override
 public void contextLoaded(ConfigurableApplicationContext context) {
  for (ApplicationListener<?> listener : this.application.getListeners()) {
   if (listener instanceof ApplicationContextAware) {
    ((ApplicationContextAware) listener).setApplicationContext(context);
   }
   context.addApplicationListener(listener);
  }
  this.initialMulticaster.multicastEvent(new ApplicationPreparedEvent(this.application, this.args, context));
 }

 @Override
 public void started(ConfigurableApplicationContext context, Duration timeTaken) {
  context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context, timeTaken));
  AvailabilityChangeEvent.publish(context, LivenessState.CORRECT);
 }

 @Override
 public void ready(ConfigurableApplicationContext context, Duration timeTaken) {
  context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context, timeTaken));
  AvailabilityChangeEvent.publish(context, ReadinessState.ACCEPTING_TRAFFIC);
 }

 @Override
 public void failed(ConfigurableApplicationContext context, Throwable exception) {
  ApplicationFailedEvent event = new ApplicationFailedEvent(this.application, this.args, context, exception);
  if (context != null && context.isActive()) {
   // Listeners have been registered to the application context so we should
   // use it at this point if we can
   context.publishEvent(event);
  }
  else {
   // An inactive context may not have a multicaster so we use our multicaster to
   // call all the context's listeners instead
   if (context instanceof AbstractApplicationContext) {
    for (ApplicationListener<?> listener : ((AbstractApplicationContext) context)
      .getApplicationListeners()) {
     this.initialMulticaster.addApplicationListener(listener);
    }
   }
   this.initialMulticaster.setErrorHandler(new LoggingErrorHandler());
   this.initialMulticaster.multicastEvent(event);
  }
 }

 private static class LoggingErrorHandler implements ErrorHandler {

  private static final Log logger = LogFactory.getLog(EventPublishingRunListener.class);

  @Override
  public void handleError(Throwable throwable) {
   logger.warn("Error calling ApplicationEventListener", throwable);
  }

 }

}

从代码中可以看到,EventPublishingRunListener会从SpringApplication中获取其Listener,即前面我们在构造方法中看到的ApplicationListener实例,在触发事件时,就是利用Spring的事件机制发布事件,触发ApplicationListener进行触发
这里需要注意的是,ApplicationListener的来源是spring.factories,而不是我们平时使用的@EventListener,也就是说,如果不写入到spring.factories,那么ApplicationListener就不会出现在这里的EventPublishingRunListener中

当前扩展点图谱

SpringBoot启动流程及当中的扩展点分析

准备好Environment  prepareEnvironment

先看源码

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
        DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments)
 
{
    // 1. 创建一个Environment实例
    ConfigurableEnvironment environment = getOrCreateEnvironment();
    // 2. 对Environment进行配置
    configureEnvironment(environment, applicationArguments.getSourceArgs());
    // 对environment增加configurationProperty的属性源
    ConfigurationPropertySources.attach(environment);
    // 3. 触发监听SpringApplicationRunListener的environmentPrepared事件
    listeners.environmentPrepared(bootstrapContext, environment);
    // 将名为defaultProperties的属性源移动到最后
    DefaultPropertiesPropertySource.moveToEnd(environment);
    Assert.state(!environment.containsProperty("spring.main.environment-prefix"),
            "Environment prefix cannot be set via properties.");
    // 将environment的属性设置到SpringApplication中
    bindToSpringApplication(environment);
    // 根据情况对Environment进行一次转换
    if (!this.isCustomEnvironment) {
        EnvironmentConverter environmentConverter = new EnvironmentConverter(getClassLoader());
        environment = environmentConverter.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
    }
    ConfigurationPropertySources.attach(environment);
    return environment;
}

创建Environment实例,getOrCreateEnvironment

private ConfigurableEnvironment getOrCreateEnvironment() {
    // 如果当前environment不为空,直接返回
    if (this.environment != null) {
        return this.environment;
    }
    // 根据应用类型创建Environment
    ConfigurableEnvironment environment = this.applicationContextFactory.createEnvironment(this.webApplicationType);
    // 如果用户自己通过编程方式定制了applicationContextFactory,且其自定义的applicationContextFactory没有成功创建Environment
    // 则采用默认的方式创建一个environment
    if (environment == null && this.applicationContextFactory != ApplicationContextFactory.DEFAULT) {
        environment = ApplicationContextFactory.DEFAULT.createEnvironment(this.webApplicationType);
    }
    // 反正最后肯定会返回一个不为空的Environment
    return (environment != null) ? environment : new ApplicationEnvironment();
}

这里会使用成员属性applicationContextFactory创建Environment,其是一个ApplicationContextFactory接口类型。默认情况下SpringApplication中applicationContextFactory是DefaultApplicationContextFactory类型的

// SpringApplication中对applicationContextFactory的定义
private ApplicationContextFactory applicationContextFactory = ApplicationContextFactory.DEFAULT;

// ApplicationContextFactory 中对DEFAULT的定义
ApplicationContextFactory DEFAULT = new DefaultApplicationContextFactory();
ApplicationContextFactory

我们先来看看ApplicationContextFactory是做啥的

// 是提供给SpringApplication用来创建ConfigurableApplicationContext的策略接口
// 创建上下文时不应该改变其初始的内容,而是交给SpringApplication负责进行配置和刷新
@FunctionalInterface
public interface ApplicationContextFactory {

    // 定义了ApplicationContextFactory的默认实现DEFAULT
 ApplicationContextFactory DEFAULT = new DefaultApplicationContextFactory();

 /**
     * 根据传入的应用类型WebApplicationType返回其期望的Environment的类型
     * 该方法主要用在转换已有的Environment
  * @param webApplicationType 应用类型
  * @since 2.6.14
  */

 default Class<? extends ConfigurableEnvironment> getEnvironmentType(WebApplicationType webApplicationType) {
  return null;
 }

 /**
     * 根据应用类型WebApplicationType创建Environment,这个Environment随后会被设置到应用程序上下文中
     * 请注意,这个方法的返回值必须和getEnvironmentType方法的保持一致
  * @param webApplicationType 应用类型
  * @since 2.6.14
  */

 default ConfigurableEnvironment createEnvironment(WebApplicationType webApplicationType) {
  return null;
 }

 /**
     * 创建应用程序上下文
  * @param webApplicationType 应用类型
  */

 ConfigurableApplicationContext create(WebApplicationType webApplicationType);

 /**
     * 传入一个应用程序上下文类型,创建一个会使用该类型创建上下文的ApplicationContextFactory
  * @param contextClass 应用程序上下文类型
  * @return the factory that will instantiate the context class
  * @see BeanUtils#instantiateClass(Class)
  */

 static ApplicationContextFactory ofContextClass(Class<? extends ConfigurableApplicationContext> contextClass) {
  return of(() -> BeanUtils.instantiateClass(contextClass));
 }

 //工具方法,与ofContextClass配套使用
 static ApplicationContextFactory of(Supplier<ConfigurableApplicationContext> supplier) {
  return (webApplicationType) -> supplier.get();
 }

}

总的来说,ApplicationContextFactory正如其名,主要负责创建应用程序上下文,附带会创建所需的Environment

DefaultApplicationContextFactory

因此,接下来我们看一下默认的DefaultApplicationContextFactory是如何创建Environment的

class DefaultApplicationContextFactory implements ApplicationContextFactory {
 // 省略无关代码

    @Override
 public Class<? extends ConfigurableEnvironment> getEnvironmentType(WebApplicationType webApplicationType) {
  return getFromSpringFactories(webApplicationType, ApplicationContextFactory::getEnvironmentType, null);
 }
    
    @Override
    public ConfigurableEnvironment createEnvironment(WebApplicationType webApplicationType) {
        return getFromSpringFactories(webApplicationType, ApplicationContextFactory::createEnvironment, null);
    }

    @Override
 public ConfigurableApplicationContext create(WebApplicationType webApplicationType) {
  try {
   return getFromSpringFactories(webApplicationType, ApplicationContextFactory::create,
     AnnotationConfigApplicationContext::new);
  }
  catch (Exception ex) {
   throw new IllegalStateException("Unable create a default ApplicationContext instance, "
     + "you may need a custom ApplicationContextFactory", ex);
  }
 }

    /**
     * 从spring.factories中获取ApplicationContextFactory类型的实例,遍历这些实例创建Environment
     * @param webApplicationType 应用类型,即前面提到的NONE,SERLVET,REACTIVE
     * @param action 函数,定义对每个ApplicationContextFactory调用哪个方法进行处理
     * @param defaultResult 定义默认值
     */

    private <T> getFromSpringFactories(WebApplicationType webApplicationType,
            BiFunction<ApplicationContextFactory, WebApplicationType, T> action, Supplier<T> defaultResult)
 
{
        for (ApplicationContextFactory candidate : SpringFactoriesLoader.loadFactories(ApplicationContextFactory.class,
                getClass().getClassLoader())) 
{
            T result = action.apply(candidate, webApplicationType);
            if (result != null) {
                return result;
            }
        }
        return (defaultResult != null) ? defaultResult.get() : null;
    }
}

DefaultApplicationContextFactory的设计采用了组合模式,它本身没有太多逻辑,它的职责是通过SpringFactoriesLoader加载spring.factories中定义的ApplicationContextFactory,然后将相关逻辑交给这些spring.factories中的ApplicationContextFactory进行处理

其他ApplicationContextFactory

这里又看到了熟悉的SpringFactoriesLoader,因此我们继续看看默认情况下SpringBoot提供了哪些ApplicationContextFactory
SpringBoot启动流程及当中的扩展点分析
简单看看SpringBoot默认提供的这些ApplicationContextFactory

// 对应响应式应用程序
public class AnnotationConfigReactiveWebServerApplicationContext extends ReactiveWebServerApplicationContext
  implements AnnotationConfigRegistry 
{
    // 省略无关代码
            
 static class Factory implements ApplicationContextFactory {

  @Override
  public Class<? extends ConfigurableEnvironment> getEnvironmentType(WebApplicationType webApplicationType) {
   return (webApplicationType != WebApplicationType.REACTIVE) ? null : ApplicationReactiveWebEnvironment.class;
  }

  @Override
  public ConfigurableEnvironment createEnvironment(WebApplicationType webApplicationType) {
   return (webApplicationType != WebApplicationType.REACTIVE) ? null : new ApplicationReactiveWebEnvironment();
  }

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

 }
}

// 对应普通Web应用程序
public class AnnotationConfigServletWebServerApplicationContext extends ServletWebServerApplicationContext
  implements AnnotationConfigRegistry 
{
    // 省略无关代码

    static class Factory implements ApplicationContextFactory {

  @Override
  public Class<? extends ConfigurableEnvironment> getEnvironmentType(WebApplicationType webApplicationType) {
   return (webApplicationType != WebApplicationType.SERVLET) ? null : ApplicationServletEnvironment.class;
  }

  @Override
  public ConfigurableEnvironment createEnvironment(WebApplicationType webApplicationType) {
   return (webApplicationType != WebApplicationType.SERVLET) ? null : new ApplicationServletEnvironment();
  }

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

 }
}

这里两个ApplicationContextFactory就分别对应SERVLET和REACTIVE两种应用类型。
我们经常使用SpringBoot开发Web应用程序,基本上都是SERVLET类型的,所以,在创建Environment时就是ApplicationServletEnvironment。本文的重点不是Environment,因此不做深入的解析了


对Environment进行配置,configureEnvironment

/**
 * 模板方法,主要逻辑委托给configurePropertySources和configureProfiles进行处理
 * 可以覆写本方法实现对environment的完全控制
 * 或者覆写configurePropertySources和configureProfiles实现局部的控制
 * @param environment 应用程序的Environment
 * @param args 传递给run方法的参数列表
 */

protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
    // 1. 为environment设置上转换服务ConversionService
    if (this.addConversionService) {
        environment.setConversionService(new ApplicationConversionService());
    }
    // 2. 配置属性源
    configurePropertySources(environment, args);
    // 3. 配置profiles
    configureProfiles(environment, args);
}


设置转换服务ConversionService

这里我们简单看一下ConversionService是做啥的

/**
 * 用于类型转换的服务接口,ConversionService是Spring类型转换系统的入口
 * 调用convert(Object, class)可以进行一个线程安全的转换
 * @since 3.0
 */

public interface ConversionService {

 /**
     * 判断类型sourceType是否可以转换为targetType类型
     * 如果返回true,说明可以通过convert(Object, Class)进行转换
     * 
     * 对于集合,数组,map这些容器类型需要特别注意:
     * 对于这几个类型之间的相互转换,这个方法将总是返回true,即使其元素类型的转换会产生异常,也会返回true
     * 这就需要调用者自行处理ConversionException异常了
  * @param sourceType 源类型,如果source本身就是null,则传入null
  * @param targetType 目标类型
  * @throws 如果targetType为空,则会抛出非法参数异常
  */

 boolean canConvert(@Nullable Class<?> sourceType, Class<?> targetType);

 // 和前一个函数功能一样,只是参数不一样了
 boolean canConvert(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType);

 /**
     * 将指定的source转换为目标类型target
  * @param source 数据源,可为null
  * @param targetType 目标类型,不可为null
  * @return 转换结果,targetType的实例
  * @throws ConversionException 转换异常
  * @throws IllegalArgumentException 如果targetType为null,抛出该异常
  */

 @Nullable
 <T> convert(@Nullable Object source, Class<T> targetType);

 // 和前一个函数功能一样,只是参数不一样了
 @Nullable
 Object convert(@Nullable Object source, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType);

}

简单来说,ConversionService负责转换类型,将某个source转成目标类型。因为Environment接口实现了PropertyResolver,其中有一个方法为

// 获取key的属性值,并按照targetType进行返回
@Nullable
<T> getProperty(String key, Class<T> targetType);

因此,Environment借助了ConversionService来实现将属性值转换成targetType的功能

配置属性源 configurePropertySources
/**
 * 添加,删除或者重排序environment中的PropertySource的顺序
 * @param environment 应用程序的Environment实例
 * @param args 传递给run方法的参数
 */

protected void configurePropertySources(ConfigurableEnvironment environment, String[] args) {
    MutablePropertySources sources = environment.getPropertySources();
    if (!CollectionUtils.isEmpty(this.defaultProperties)) {
        DefaultPropertiesPropertySource.addOrMerge(this.defaultProperties, sources);
    }
    // addConmandLineProperties: 是否要将命令行参数作为属性源添加到Environment中,默认为true
    if (this.addCommandLineProperties && args.length > 0) {
        // 将命令行参数作为属性源添加到Environment中
        String name = CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME;
        if (sources.contains(name)) {
            // 如果Environment中已经包含了同名的属性源,则将这两个属性源合并后替换到原来的
            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));
        }
    }
}


配置profiles  configureProfiles
/**
 * 可以在这里配置激活哪个profile,这和spring.profiles.active并不冲突。默认不激活任何profile
 * @param environment Environment实例
 * @param args 传递给run方法的参数
 */

protected void configureProfiles(ConfigurableEnvironment environment, String[] args) {
}


触发监听SpringApplicationRunListener的environmentPrepared事件

这里对environmentPrepared事件需要特殊介绍的原因是这里面还包括一个扩展点,我们来分析一下
前面分析中提到,ApplicationListener也是SpringBoot提供的一个特殊扩展点,他是由默认的EventPublishingRunListener(SpringApplicationRunListener的实现)并结合事件机制完成的。而SpringBoot默认提供的ApplicationListener中有一个EnvironmentPostProcessorApplicationListener,我们来分析这个EnvironmentPostProcessorApplicationListener
SpringBoot启动流程及当中的扩展点分析

EnvironmentPostProcessorApplicationListener
public class EnvironmentPostProcessorApplicationListener implements SmartApplicationListenerOrdered {
 public static final int DEFAULT_ORDER = Ordered.HIGHEST_PRECEDENCE + 10;

 private final DeferredLogs deferredLogs;

 private int order = DEFAULT_ORDER;

 private final Function<ClassLoader, EnvironmentPostProcessorsFactory> postProcessorsFactory;

    // 可以回到前面的章节,在SpringApplication构造函数中创建ApplicationListener时,调用的是无参构造方法
 public EnvironmentPostProcessorApplicationListener() {
  this(EnvironmentPostProcessorsFactory::fromSpringFactories, new DeferredLogs());
 }
 public EnvironmentPostProcessorApplicationListener(EnvironmentPostProcessorsFactory postProcessorsFactory) {
  this((classloader) -> postProcessorsFactory, new DeferredLogs());
 }
 EnvironmentPostProcessorApplicationListener(
   Function<ClassLoader, EnvironmentPostProcessorsFactory> postProcessorsFactory, DeferredLogs deferredLogs) {
  this.postProcessorsFactory = postProcessorsFactory;
  this.deferredLogs = deferredLogs;
 }

    // 返回监听的事件类型,主要有三类事件
    // 1. ApplicationEnvironmentPreparedEvent
    // 2. ApplicationPreparedEvent
    // 3. ApplicationFailedEvent
 @Override
 public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
  return ApplicationEnvironmentPreparedEvent.class.isAssignableFrom(eventType)
    || ApplicationPreparedEvent.class.isAssignableFrom(eventType)
    || ApplicationFailedEvent.class.isAssignableFrom(eventType)
;
 }

    // 监听入口,可以看到最后会调用onApplicationEnvironmentPreparedEvent进行处理
 @Override
 public void onApplicationEvent(ApplicationEvent event) {
  if (event instanceof ApplicationEnvironmentPreparedEvent) {
   onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event);
  }
  if (event instanceof ApplicationPreparedEvent) {
   onApplicationPreparedEvent();
  }
  if (event instanceof ApplicationFailedEvent) {
   onApplicationFailedEvent();
  }
 }

    // 最后是遍历成员属性postProcessorsFactory获取到EnvironmentPostProcessor
 private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
  ConfigurableEnvironment environment = event.getEnvironment();
  SpringApplication application = event.getSpringApplication();
  for (EnvironmentPostProcessor postProcessor : getEnvironmentPostProcessors(application.getResourceLoader(),
    event.getBootstrapContext())) {
   postProcessor.postProcessEnvironment(environment, application);
  }
 }

 private void onApplicationPreparedEvent() {
  finish();
 }

 private void onApplicationFailedEvent() {
  finish();
 }

 private void finish() {
  this.deferredLogs.switchOverAll();
 }

 List<EnvironmentPostProcessor> getEnvironmentPostProcessors(ResourceLoader resourceLoader,
   ConfigurableBootstrapContext bootstrapContext)
 
{
  ClassLoader classLoader = (resourceLoader != null) ? resourceLoader.getClassLoader() : null;
  EnvironmentPostProcessorsFactory postProcessorsFactory = this.postProcessorsFactory.apply(classLoader);
  return postProcessorsFactory.getEnvironmentPostProcessors(this.deferredLogs, bootstrapContext);
 }

 @Override
 public int getOrder() {
  return this.order;
 }

 public void setOrder(int order) {
  this.order = order;
 }

}

这里可以看到EnvironmentPostProcessorApplicationListener的事件处理逻辑是调用内部的EnvironmentPostProcessor进行处理,而EnvironmentPostProcessor则是通过成员属性postProcessorsFactory获取到的。默认情况下,SpringBoot会调用EnvironmentPostProcessorApplicationListener的无参构造方法创建对应的监听请,而其无参构造方法中则是通过EnvironmentPostProcessorsFactory静态方法fromSpringFactories获取,对应源代码为:

static EnvironmentPostProcessorsFactory fromSpringFactories(ClassLoader classLoader) {
    return new ReflectionEnvironmentPostProcessorsFactory(classLoader,
            SpringFactoriesLoader.loadFactoryNames(EnvironmentPostProcessor.classclassLoader));
}

该代码会返回一个ReflectionEnvironmentPostProcessorsFactory,同时这里也看到了熟悉的SpringFactoriesLoader
我们挨个来分析

ReflectionEnvironmentPostProcessorsFactory
class ReflectionEnvironmentPostProcessorsFactory implements EnvironmentPostProcessorsFactory {

 private final List<Class<?>> classes;

 private ClassLoader classLoader;

 private final List<String> classNames;

 ReflectionEnvironmentPostProcessorsFactory(Class<?>... classes) {
  this.classes = new ArrayList<>(Arrays.asList(classes));
  this.classNames = null;
 }

 ReflectionEnvironmentPostProcessorsFactory(ClassLoader classLoader, String... classNames) {
  this(classLoader, Arrays.asList(classNames));
 }

    // EnvironmentPostProcessorsFactory.fromSpringFactories调用的构造函数
 ReflectionEnvironmentPostProcessorsFactory(ClassLoader classLoader, List<String> classNames) {
  this.classes = null;
  this.classLoader = classLoader;
  this.classNames = classNames;
 }

    // 核心代码,EnvironmentPostProcessorApplicationListener 会调用这个方法来获取到
    // EnvironmentPostProcessor
 @Override
 public List<EnvironmentPostProcessor> getEnvironmentPostProcessors(DeferredLogFactory logFactory,
   ConfigurableBootstrapContext bootstrapContext)
 
{
  Instantiator<EnvironmentPostProcessor> instantiator = new Instantiator<>(EnvironmentPostProcessor.class,
    (parameters) -> 
{
     parameters.add(DeferredLogFactory.classlogFactory);
     parameters.add(Log.classlogFactory::getLog);
     parameters.add(ConfigurableBootstrapContext.classbootstrapContext);
     parameters.add(BootstrapContext.classbootstrapContext);
     parameters.add(BootstrapRegistry.classbootstrapContext);
    });
  return (this.classes != null) ? instantiator.instantiateTypes(this.classes)
    : instantiator.instantiate(this.classLoader, this.classNames);
 }

}

可以看到,ReflectionEnvironmentPostProcessorsFactory的功能就是接收spring.factories中指定的EnvironmentPostProcessor类型,并实例化后交给EnvironmentPostProcessorApplicationListener来触发

关系图

下面是整理的关系图,可以帮助理清相关关系

SpringBoot启动流程及当中的扩展点分析


扩展点

SpringBoot启动流程及当中的扩展点分析

创建应用程序上下文  createApplicationContext

protected ConfigurableApplicationContext createApplicationContext() {
    return this.applicationContextFactory.create(this.webApplicationType);
}

这里就是调用ApplicationContextFactory进行创建Context
根据前文的源码分析我们可以知道,对于我们常用的Web应用程序来说,其ApplicationContextFactory是AnnotationConfigServletWebServerApplicationContext.Factory。其相关源码在前文可以查阅

准备应用程序上下文  preparedContext

private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
        ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
        ApplicationArguments applicationArguments, Banner printedBanner)
 
{
    // 设置Environment
    context.setEnvironment(environment);
    // 1. 对context进行后置处理
    postProcessApplicationContext(context);
    // 2. 应用初始化器
    applyInitializers(context);
    // 触发ContextPreparedEvent事件
    listeners.contextPrepared(context);
    // 在引导上下文中触发BootstrapContextClosedEvent事件
    bootstrapContext.close(context);
    if (this.logStartupInfo) {
        logStartupInfo(context.getParent() == null);
        logStartupProfileInfo(context);
    }
    // 添加SpringBoot特有的一些单例bean到应用程序上下文中
    ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
    beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
    if (printedBanner != null) {
        beanFactory.registerSingleton("springBootBanner", printedBanner);
    }
    if (beanFactory instanceof AbstractAutowireCapableBeanFactory) {
        ((AbstractAutowireCapableBeanFactory) beanFactory).setAllowCircularReferences(this.allowCircularReferences);
        if (beanFactory instanceof DefaultListableBeanFactory) {
            ((DefaultListableBeanFactory) beanFactory)
                    .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
        }
    }
    // 添加懒加载相关的BeanFactoryPostProcessor
    if (this.lazyInitialization) {
        context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
    }
    context.addBeanFactoryPostProcessor(new PropertySourceOrderingBeanFactoryPostProcessor(context));
    // 3. 对source进行处理,在这里我们可以提前注册一些bean到应用程序上下文中
    Set<Object> sources = getAllSources();
    Assert.notEmpty(sources, "Sources must not be empty");
    load(context, sources.toArray(new Object[0]));
    listeners.contextLoaded(context);
}


对context进行后置处理  postProcessApplicationContext

protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
    // 注册单例的beanNameGenerator,它的功能是生成bean的名称
 if (this.beanNameGenerator != null) {
        context.getBeanFactory().registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
                this.beanNameGenerator);
    }
 // 设置资源加载器
    if (this.resourceLoader != null) {
        if (context instanceof GenericApplicationContext) {
            ((GenericApplicationContext) context).setResourceLoader(this.resourceLoader);
        }
        if (context instanceof DefaultResourceLoader) {
            ((DefaultResourceLoader) context).setClassLoader(this.resourceLoader.getClassLoader());
        }
    }
 // 设置转换服务
    if (this.addConversionService) {
        context.getBeanFactory().setConversionService(context.getEnvironment().getConversionService());
    }
}

这个后置处理就是增加一些bean,设置一些字段到context中

应用初始化器  applyInitializers

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);
    }
}

可以看到,这里是获取了SpringApplication内部的初始化器,对context进行初始化操作。而这里的initializers是在SpringApplication构造函数中完成加载的,可以回到前面看一下,它也是从spring.factories中获取的

对source进行处理

source是SpringBoot提供的一种注册bean的方式,souce可以是一个class,可以是一个包Package,可以是一个XML文件或者Groovy脚本的Resource,可以是上述三种的字符串描述
SpringApplication中用成员属性sources来保存这些资源

protected void load(ApplicationContext context, Object[] sources) {
    if (logger.isDebugEnabled()) {
        logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
    }
    // 构造一个BeanDefinitionLoader,用于从sources中加载BeanDefinition,将其注册到context中去
    BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);
    if (this.beanNameGenerator != null) {
        loader.setBeanNameGenerator(this.beanNameGenerator);
    }
    if (this.resourceLoader != null) {
        loader.setResourceLoader(this.resourceLoader);
    }
    if (this.environment != null) {
        loader.setEnvironment(this.environment);
    }
    // 进行加载
    loader.load();
}

这里就不进行深入的源码解析了,总结一下source情况

  • 如果source是一个Class类型,或者其是一个Class的全限定名字符串,则会将其对应的类注册到context中,特殊情况是Groovy脚本(这种情况没见到过,但是BeanDefinitionLoader确实会进行特殊处理)
  • 如果source是一个Package类型,或者其是一个包名的字符串,则会进行扫描,类似于ComponentScan
  • 如果source是一个Resource类型,或者是一个资源的字符串表达,则会尝试将其作为XML配置文件,或者Groovy脚本文件进行加载注册

扩展点

某种意义上,source也是一个扩展点,但考虑到很少用,暂不加入
SpringBoot启动流程及当中的扩展点分析

刷新应用程序上下文  refreshContext

private void refreshContext(ConfigurableApplicationContext context) {
    if (this.registerShutdownHook) {
        shutdownHook.registerApplicationContext(context);
    }
    refresh(context);
}

protected void refresh(ConfigurableApplicationContext applicationContext) {
    applicationContext.refresh();
}

这里的代码比较简单,仅仅是调用applicationContext的刷新函数refresh即可。其内部是AbastactApplicationContext的刷新流程,本文暂不涉略其中

调用SpringRunner   callRunners

private void callRunners(ApplicationContext context, ApplicationArguments args) {
    List<Object> runners = new ArrayList<>();
    // 从应用程序上下文中获取所有ApplicationRunner的实例
    runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
    // 从应用程序上下文中获取所有CommandLineRunner的实例
    runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
    // 按照Ordered接口或者Order注解排序
    AnnotationAwareOrderComparator.sort(runners);
    // 遍历,调用方法
    for (Object runner : new LinkedHashSet<>(runners)) {
        if (runner instanceof ApplicationRunner) {
            callRunner((ApplicationRunner) runner, args);
        }
        if (runner instanceof CommandLineRunner) {
            callRunner((CommandLineRunner) runner, args);
        }
    }
}

private void callRunner(ApplicationRunner runner, ApplicationArguments args) {
    try {
        (runner).run(args);
    }
    catch (Exception ex) {
        throw new IllegalStateException("Failed to execute ApplicationRunner", ex);
    }
}

private void callRunner(CommandLineRunner runner, ApplicationArguments args) {
    try {
        (runner).run(args.getSourceArgs());
    }
    catch (Exception ex) {
        throw new IllegalStateException("Failed to execute CommandLineRunner", ex);
    }
}

callRunners的方法比较简单,就是从容器中获取到ApplicationRunner和CommandLineRunner,调用其run方法
这也算一个扩展点

扩展点

SpringBoot启动流程及当中的扩展点分析

总结

SpringBoot的启动是一个非常复杂的流程,本文仅仅对SpringBoot的启动做了一些简要的梳理,同时总结了一些比较常见的SpringBoot的扩展点


原文始发于微信公众号(嘟嘟是只兔兔):SpringBoot启动流程及当中的扩展点分析

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/207198.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!