关于程序员:SpringBoot启动流程及扩展点分析

45次阅读

共计 38701 个字符,预计需要花费 97 分钟才能阅读完成。

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

@SpringBootApplication
public class SpringbootDemoApplication {public static void main(String[] args) {SpringApplication.run(SpringbootDemoApplication.class, args);
    }
}

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 就是咱们返回的类名的汇合

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 并没有定义任何的 BootstrapRegistryInitializer

加载应用程序初始化器

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

/**
 * ConfigurableApplicationContext 的回调接口,会在 refresh 办法调用之前对 ApplicationContext 进行解决
 * 个别用于对 ApplicationContext 进行一些初始化工作,比方注册一个属性源或者激活某个 profile
 *
 * ApplicationContextInitializer 会依照 Ordered 接口或者 @Order 注解定义的优先级进行排序
 */
@FunctionalInterface
public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {void initialize(C applicationContext);

}

以下是 SpringBoot 默认提供的应用程序上下文的初始化器

加载监听器

// 应用程序监听器,监听 ApplicationEvent 接口。是基于观察者模式创立的接口
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {void onApplicationEvent(E event);

    /**
     * 静态方法,为音讯类型 T 创立一个监听器
     */
    static <T> ApplicationListener<PayloadApplicationEvent<T>> forPayload(Consumer<T> consumer) {return event -> consumer.accept(event.getPayload());
    }
}

咱们再看看 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 提供的扩大点之一

以后扩大点图谱

创立 SpringApplicationRunListeners

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

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<br/>

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 SpringApplicationRunListener, Ordered {

    private final SpringApplication application;

    private final String[] args;

    private final SimpleApplicationEventMulticaster initialMulticaster;

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

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

    @Override
    public void starting(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 中

以后扩大点图谱

筹备好 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> 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 默认提供的这些 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> 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> 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

EnvironmentPostProcessorApplicationListener
public class EnvironmentPostProcessorApplicationListener implements SmartApplicationListener, Ordered {
    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.class, classLoader));
}

该代码会返回一个 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.class, logFactory);
                    parameters.add(Log.class, logFactory::getLog);
                    parameters.add(ConfigurableBootstrapContext.class, bootstrapContext);
                    parameters.add(BootstrapContext.class, bootstrapContext);
                    parameters.add(BootstrapRegistry.class, bootstrapContext);
                });
        return (this.classes != null) ? instantiator.instantiateTypes(this.classes)
                : instantiator.instantiate(this.classLoader, this.classNames);
    }

}

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

关系图

上面是整顿的关系图,能够帮忙理清相干关系

扩大点

创立应用程序上下文 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 也是一个扩大点,但思考到很少用,暂不退出

    刷新应用程序上下文 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 的扩大点

本文由 mdnice 多平台公布

正文完
 0