Spring Boot SpringApplication启动类(二) - SpringApplicationRunListener 、ConfigurableEnvironment 、Configu

前言

        最近在学习Spring Boot相关的课程,过程当中以笔记的形式记录下来,方便之后回忆,同时也在这里和你们探讨探讨,文章中有漏的或者有补充的、错误的都但愿你们可以及时提出来,本人在此先谢谢了!java

开始以前呢,但愿你们带着几个问题去学习:
一、Spring Boot SpringApplication 是什么?
二、总体流程或结构是怎样的?
三、重点内容或者核心部分是什么?
四、怎么实现的?
五、是怎么和 Spring 关联起来的?
这是对自个人提问,我认为带着问题去学习,是一种更好的学习方式,有利于加深理解。好了,接下来进入主题。react

一、起源

        上篇文章咱们讲了 SpringApplication 的准备阶段,在这个阶段,完成了运行时所须要准备的资源,如:initializerslisteners等。而这篇文章咱们就来说讲 SpringApplication 的运行阶段,在这个阶段,它是如何启动 Spring 应用上下文的,且如何与 Spring 事件结合起来,造成完整的 SpringApplication生命周期的。web

注:本篇文章所用到的 Spring Boot版本是 2.1.6.BUILD-SNAPSHOTspring

二、SpringApplication 运行阶段

        上篇文章咱们讲了 SpringApplication 的构造方法,这里咱们就来说讲 SpringApplication 的核心,也就是run方法,代码以下:编程

public class SpringApplication {

    ...
        
    public ConfigurableApplicationContext run(String... args) {
        // 这是 Spring 的一个计时器,计算代码的执行时间(ms级别)
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        
        // 这俩变量在后面赋值处进行说明
        ConfigurableApplicationContext context = null;
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
        
        // 用来设置java.awt.headless属性值
        configureHeadlessProperty();
        
        // 该对象属于组合模式的实现,核心是内部关联的 SpringApplicationRunListener 集合,SpringApplicationRunListener 是 Spring Boot 的运行时监听器
        SpringApplicationRunListeners listeners = getRunListeners(args);
        // 会在不一样的阶段调用对应的方法,这里表示启动run方法被调用
        listeners.starting();
        
        try {
        
            // 用来获取 SpringApplication.run(args)传入的参数
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            
            // 获取 properties 配置文件
            ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
            
            // 设置 spring.beaninfo.ignore 的属性值,判断是否跳过搜索BeanInfo类
            configureIgnoreBeanInfo(environment);
            
            // 这里是项目启动时,控制台打印的 Banner
            Banner printedBanner = printBanner(environment);
            
            // 这里就是建立 Spring 应用上下文
            context = createApplicationContext();
            
            // 获取 spring.factories 中key为 SpringBootExceptionReporter 的类名集合
            exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
                    new Class[] { ConfigurableApplicationContext.class }, context);
                    
            // 这里是准备 Spring 应用上下文
            prepareContext(context, environment, listeners, applicationArguments, printedBanner);
            
            // 这里是启动 Spring 应用上下文,底层调用的是 ApplicationContext 的 refresh() 方法,到这里就正式进入了 Spring 的生命周期,同时,SpringBoot的自动装配特性也随之启动
            refreshContext(context);
            
            // 里面是空的,猜想应该是交由开发人员自行扩展
            afterRefresh(context, applicationArguments);
            stopWatch.stop();
            
            // 这里打印启动信息
            if (this.logStartupInfo) {
                new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
            }
            
            // ApplicationContext 启动时,调用该方法
            listeners.started(context);
            
            // 项目启动后,作的一些操做,开发人员可自行扩展
            callRunners(context, applicationArguments);
        }
        catch (Throwable ex) {
            handleRunFailure(context, ex, exceptionReporters, listeners);
            throw new IllegalStateException(ex);
        }
    
        try {
        
            // ApplicationContext 启动完成时,调用该方法
            listeners.running(context);
        }
        catch (Throwable ex) {
            handleRunFailure(context, ex, exceptionReporters, null);
            throw new IllegalStateException(ex);
        }
        return context;
    }
    
    ...
}

上面就是整个过程的概览,能够看到,在运行阶段执行的操做比较多,虽然看起来杂乱无章,但其实仍是有规律可循的。好比,执行的 SpringApplicationRunListeners 中的阶段方法,刚启动阶段的 starting 、已启动阶段的 started 、启动完成阶段的 running 等。还有对应的 Spring 应用上下文的建立、准备、启动操做等。接下来,就对里面的几个核心对象进行讨论。springboot

2.1 SpringApplicationRunListeners 结构

咱们先来看看 SpringApplicationRunListeners 对象,从代码能够看出该对象是由 getRunListeners 方法建立的:app

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

能够看到,经过传入的 getSpringFactoriesInstances 方法的返回值,执行 SpringApplicationRunListeners 的构造方法,进行对象的建立。接着看 getSpringFactoriesInstances 方法:less

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
    ClassLoader classLoader = getClassLoader();
    // Use names and ensure unique to protect against duplicates
    Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
    List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
    AnnotationAwareOrderComparator.sort(instances);
    return instances;
}

看到这你们应该比较熟悉了,经过前面几篇文章的讨论咱们知道,该方法经过 SpringFactoriesLoader.loadFactoryNames 返回全部 classpass 下的 spring.factories 文件中 key 为 SpringApplicationRunListener 的实现类集合。如 Spring Boot 的内建实现:异步

# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener

最后,就是将该集合传入 SpringApplicationRunListeners 的构造方法:

class SpringApplicationRunListeners {

    ...

    private final List<SpringApplicationRunListener> listeners;

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

    public void starting() {
        for (SpringApplicationRunListener listener : this.listeners) {
            listener.starting();
        }
    }

    ...

}

里面是将集合赋值到 listeners 属性,能够看到 SpringApplicationRunListeners 属于组合模式的实现,核心实际上是内部关联的 SpringApplicationRunListener 对象集合,当外部调用该阶段方法时,就会迭代执行集合中 SpringApplicationRunListener 对应的方法。因此接下来咱们就来讨论 SpringApplicationRunListener

2.1.1 SpringApplicationRunListener 事件和监听机制

SpringApplicationRunListener 负责在 SpringBoot 的不一样阶段广播相应的事件,而后调用实际的 ApplicationListener 类,在该类的 onApplicationEvent 方法中,根据不一样的 Spring Boot 事件执行相应操做。整个过程大概如此,接下来进行详细讨论,先来看看 SpringApplicationRunListener 定义:

public interface SpringApplicationRunListener {

    // 在run()方法开始执行时被调用,表示应用刚刚启动,对应的 Spring Boot 事件为 ApplicationStartingEvent
    void starting();

    // ConfigurableEnvironment 构建完成时调用,对应的 Spring Boot 事件为 ApplicationEnvironmentPreparedEvent
    void environmentPrepared(ConfigurableEnvironment environment);

    // ApplicationContext 构建完成时调用,对应的 Spring Boot 事件为 ApplicationContextInitializedEvent
    void contextPrepared(ConfigurableApplicationContext context);

    // ApplicationContext 完成加载但还未启动时调用,对应的 Spring Boot 事件为 ApplicationPreparedEvent
    void contextLoaded(ConfigurableApplicationContext context);

    // ApplicationContext 已启动,但 callRunners 还未执行时调用,对应的 Spring Boot 事件为 ApplicationStartedEvent
    void started(ConfigurableApplicationContext context);

    // ApplicationContext 启动完毕被调用,对应的 Spring Boot 事件为 ApplicationReadyEvent
    void running(ConfigurableApplicationContext context);

    // 应用出错时被调用,对应的 Spring Boot 事件为 ApplicationFailedEvent
    void failed(ConfigurableApplicationContext context, Throwable exception);

}

咱们来看看它的实现类,也就是上面加载的 spring.factories 文件中的 EventPublishingRunListener 类,该类也是 Spring Boot 内建的惟一实现类,具体广播事件的操做在该类中进行,代码以下:

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 void starting() {
        this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
    }

    ...

}

能够看到,经过构造方法建立 EventPublishingRunListener 实例的过程当中,调用了 getListeners 方法,将 SpringApplication 中全部 ApplicationListener 监听器关联到了 initialMulticaster 属性中。没错,这里的 ApplicationListener 监听器就是上篇文章中在 SpringApplication 准备阶段从 spring.factories 文件加载的 key 为 ApplicationListener 的实现类集合,该实现类集合所有重写了 onApplicationEvent 方法。

2.1.2 SimpleApplicationEventMulticaster 广播器

这里又引出了另外一个类, 也就是 SimpleApplicationEventMulticaster ,该类是 Spring 的事件广播器,也就是经过它来广播各类事件。接着,当外部迭代的执行到 EventPublishingRunListenerstarting 方法时,会经过 SimpleApplicationEventMulticastermulticastEvent 方法进行事件的广播,这里广播的是 ApplicationStartingEvent 事件,咱们进入 multicastEvent 方法:

public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {

    ...
    
    @Override
    public void multicastEvent(ApplicationEvent event) {
        multicastEvent(event, resolveDefaultEventType(event));
    }

    @Override
    public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
        ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
        Executor executor = getTaskExecutor();
        for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
            if (executor != null) {
                executor.execute(() -> invokeListener(listener, event));
            }
            else {
                invokeListener(listener, event);
            }
        }
    }
}

经过 getApplicationListeners 方法,根据事件类型返回从上面关联的 ApplicationListener 集合中筛选出匹配的 ApplicationListener 集合,根据 Spring Boot 版本的不一样,在这个阶段获取到的监听器也有可能不一样,如 2.1.6.BUILD-SNAPSHOT 版本返回的是:
image

而后依次遍历这些监听器,同步或异步的调用 invokeListener 方法:

protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
        ErrorHandler errorHandler = getErrorHandler();
    if (errorHandler != null) {
        try {
            doInvokeListener(listener, event);
        }
        catch (Throwable err) {
            errorHandler.handleError(err);
        }
    }
    else {
        doInvokeListener(listener, event);
    }
}

...

private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
        try {
            listener.onApplicationEvent(event);
        }
        catch (ClassCastException ex) {
            String msg = ex.getMessage();
            if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
                // Possibly a lambda-defined listener which we could not resolve the generic event type for
                // -> let's suppress the exception and just log a debug message.
                Log logger = LogFactory.getLog(getClass());
                if (logger.isTraceEnabled()) {
                    logger.trace("Non-matching event type for listener: " + listener, ex);
                }
            }
            else {
                throw ex;
            }
        }
    }

能够看到,最终调用的是 doInvokeListener 方法,在该方法中执行了 ApplicationListeneronApplicationEvent 方法,入参为广播的事件对象。咱们就拿其中一个的监听器来看看 onApplicationEvent 中的实现,如 BackgroundPreinitializer 类:

public class BackgroundPreinitializer implements ApplicationListener<SpringApplicationEvent> {

    ...
    
    @Override
    public void onApplicationEvent(SpringApplicationEvent event) {
        if (!Boolean.getBoolean(IGNORE_BACKGROUNDPREINITIALIZER_PROPERTY_NAME)
                && event instanceof ApplicationStartingEvent && preinitializationStarted.compareAndSet(false, true)) {
            performPreinitialization();
        }
        if ((event instanceof ApplicationReadyEvent || event instanceof ApplicationFailedEvent)
                && preinitializationStarted.get()) {
            try {
                preinitializationComplete.await();
            }
            catch (InterruptedException ex) {
                Thread.currentThread().interrupt();
            }
        }
    }
    
    ...
}

在该方法中,经过 instanceof 判断事件的类型,从而进行相应的操做。该监听器主要的操做是新建一个后台线程去执行那些耗时的初始化工做,包括验证器、消息转换器等。LoggingApplicationListener 监听器则是对 Spring Boot 的日志系统作一些初始化的前置操做。另外两个监听器在该阶段无任何操做。

至此,SpringBoot 事件机制的总体流程大概如此,咱们简要回顾一下几个核心组件:

  • SpringApplicationRunListeners:首先,在 run 方法的执行过程当中,经过该类在 SpringBoot 不一样的阶段调用不一样的阶段方法,如在刚启动阶段调用的 starting 方法。

  • SpringApplicationRunListener:而 SpringApplicationRunListeners 属于组合模式的实现,它里面关联了 SpringApplicationRunListener 实现类集合,当外部调用阶段方法时,会迭代执行该集合中的阶段方法。实现类集合是 spring.factories 文件中定义好的类。这里是一个扩展点,详细的后面述说。

  • EventPublishingRunListener:该类是 Spring Boot 内置的 SpringApplicationRunListener 惟一实现类,因此,当外部调用各阶段的方法时,真正执行的是该类中的方法。

  • SimpleApplicationEventMulticaster:在阶段方法中,会经过 SpringSimpleApplicationEventMulticaster 事件广播器,广播各个阶段对应的事件,如这里的 starting 方法广播的事件是 ApplicationStartingEvent

  • ApplicationListener:最后 ApplicationListener 的实现类也就是 Spring Boot 监听器会监听到广播的事件,根据不一样的事件,进行相应的操做。这里的 Spring Boot 监听器是也是在 spring.factories 中定义好的,这里咱们也可自行扩展。

到这里 Spring Boot 事件监听机制差很少就结束了,值得注意的是 Spring Boot 监听器实现的是 SpringApplicationListener 类,事件类最终继承的也是 SpringApplicationEvent 类,因此,Spring Boot 的事件和监听机制都基于 Spring 而实现的。

2.2 ApplicationArguments 加载启动参数

        当执行完 listeners.starting 方法后,接着进入构造 ApplicationArguments 阶段:

public class SpringApplication {

    ...
    
    public ConfigurableApplicationContext run(String... args) {
        
        ...
        
        SpringApplicationRunListeners listeners = getRunListeners(args);
        listeners.starting();
        try {
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            
            ...
        }
    }
    
    ...
}

该类是用于简化 Spring Boot 应用启动参数的封装接口,咱们启动项目时输入的命令参数会封装在该类中。一种是经过 IDEA 输入的参数,以下:
image

另外一种是 springboot jar包运行时传递的参数:cmd中运行java -jar xxx.jar name=张三 pwa=123

而后,能够经过 @Autowired 注入 ApplicationArguments 的方式进行使用:

public class Test {

    @Autowired
    private ApplicationArguments applicationArguments;

    public void getArgs() {
        // 获取 args 中的全部 non option 参数
        applicationArguments.getNonOptionArgs();

        // 获取 args 中全部的 option 参数的 name
        applicationArguments.getOptionNames();

        // 获取传递给应用程序的原始未处理参数
        applicationArguments.getSourceArgs();

        // 获取 args 中指定 name 的 option 参数的值
        applicationArguments.getOptionValues("nmae");

        // 判断从参数中解析的 option 参数是否包含指定名称的选项
        applicationArguments.containsOption("name");
    }
}

2.3 ConfigurableEnvironment 加载外部化配置

        接着进入构造 ConfigurableEnvironment 的阶段,该类是用来处理咱们外部化配置的,如 propertiesYAML 等,提供对配置文件的基础操做。固然,它能处理的外部配置可不只仅如此,详细的在下篇文章讨论,这里咱们进行简要了解便可,进入建立该类的 prepareEnvironment 方法:

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
            ApplicationArguments applicationArguments) {
    // Create and configure the environment
    ConfigurableEnvironment environment = getOrCreateEnvironment();
    configureEnvironment(environment, applicationArguments.getSourceArgs());
    listeners.environmentPrepared(environment);
    bindToSpringApplication(environment);
    if (!this.isCustomEnvironment) {
        environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
                deduceEnvironmentClass());
    }
    ConfigurationPropertySources.attach(environment);
    return environment;
}

这里经过 getOrCreateEnvironment 方法返回具体的 Environment

private ConfigurableEnvironment getOrCreateEnvironment() {
        if (this.environment != null) {
            return this.environment;
        }
        switch (this.webApplicationType) {
        case SERVLET:
            return new StandardServletEnvironment();
        case REACTIVE:
            return new StandardReactiveWebEnvironment();
        default:
            return new StandardEnvironment();
        }
    }

能够看到,这里经过 webApplicationType 属性来判断当前应用的类型,有 ServletReactive 、 非Web 3种类型,该属性也是在上篇文章中 SpringApplication 准备阶段肯定的,这里咱们一般都是 Servlet 类型,返回的是 StandardServletEnvironment 实例。

以后,还调用了 SpringApplicationRunListenersenvironmentPrepared 阶段方法,表示 ConfigurableEnvironment 构建完成,同时向 Spring Boot 监听器发布 ApplicationEnvironmentPreparedEvent 事件。监听该事件的监听器有:
image

2.4 ConfigurableApplicationContext 建立 Spring 应用上下文

        这里经过 createApplicationContext 方法建立 Spring 应用上下文,实际上 Spring 的应用上下文才是驱动 Spring Boot 的核心引擎:

public class SpringApplication {

    ...

    public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context."
            + "annotation.AnnotationConfigApplicationContext";

    public static final String DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot."
            + "web.servlet.context.AnnotationConfigServletWebServerApplicationContext";

    public static final String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework."
            + "boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext";

    ...

    protected ConfigurableApplicationContext createApplicationContext() {
        Class<?> contextClass = this.applicationContextClass;
        if (contextClass == null) {
            try {
                switch (this.webApplicationType) {
                case SERVLET:
                    contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
                    break;
                case REACTIVE:
                    contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
                    break;
                default:
                    contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
                }
            }
            catch (ClassNotFoundException ex) {
                throw new IllegalStateException(
                        "Unable create a default ApplicationContext, " + "please specify an ApplicationContextClass",
                        ex);
            }
        }
        return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
    }
    
    ...
}

这里也是经过 webApplicationType 属性来肯定应用类型从而建立 String 上下文,上篇文章说到该属性值是在 Spring Boot 准备阶段推导出来的。这里咱们的应用类型是 Servlet ,因此建立的是 AnnotationConfigServletWebServerApplicationContext 对象。建立完 Spring 应用上下文以后,执行 prepareContext 方法进入准备上下文阶段:

private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
            SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
    context.setEnvironment(environment);
    postProcessApplicationContext(context);
    applyInitializers(context);
    listeners.contextPrepared(context);
    if (this.logStartupInfo) {
        logStartupInfo(context.getParent() == null);
        logStartupProfileInfo(context);
    }
    // Add boot specific singleton beans
    ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
    beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
    if (printedBanner != null) {
        beanFactory.registerSingleton("springBootBanner", printedBanner);
    }
    if (beanFactory instanceof DefaultListableBeanFactory) {
        ((DefaultListableBeanFactory) beanFactory)
                .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
    }
    // Load the sources
    Set<Object> sources = getAllSources();
    Assert.notEmpty(sources, "Sources must not be empty");
    load(context, sources.toArray(new Object[0]));
    listeners.contextLoaded(context);
}

咱们来看看主要作了哪些操做:

  1. 设置了 Spring 应用上下文的 ApplicationArguments,上面说过是处理外部化配置的,具体类型为 StandardServletEnvironment

  2. Spring 应用上下文后置处理,主要是覆盖当前 Spring 应用上下文默认所关联的 ResourceLoaderClassLoader

  3. 执行 Spring 的初始化器,上篇文章说过在 Spring Boot 准备阶段初始化了一批在 spring.factories 文件中定义好的 ApplicationContextInitializer ,这里就是执行它们的 initialize 方法,同时这里也是一个扩展点,后面详细讨论。

  4. 执行 SpringApplicationRunListenerscontextPrepared 阶段方法,表示 ApplicationContext 准备完成,同时向 Spring Boot 监听器发布 ApplicationContextInitializedEvent 事件 。

  5. springApplicationArgumentsspringBootBanner 注册为 Bean

  6. 加载 Spring 应用上下文的配置源,也是在上篇文章 Spring Boot 准备阶段获取的 primarySourcessourcesprimarySources 来源于 SpringApplication 构造器参数,sources 则来源于自定义配置的 setSources 方法。

  7. 最后执行 SpringApplicationRunListenerscontextLoaded 阶段方法,表示 ApplicationContext 完成加载但还未启动,同时向 Spring Boot 监听器发布 ApplicationPreparedEvent 事件 。

接下来就是真正启动阶段,执行的是 refreshContext 方法:

private void refreshContext(ConfigurableApplicationContext context) {
    refresh(context);
    if (this.registerShutdownHook) {
        try {
            context.registerShutdownHook();
        }
        catch (AccessControlException ex) {
            // Not allowed in some environments.
        }
    }
}
protected void refresh(ApplicationContext applicationContext) {
        Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
    ((AbstractApplicationContext) applicationContext).refresh();
}

能够看到,底层调用的是 AbstractApplicationContextrefresh 方法,到这里 Spring 应用正式启动,Spring Boot 核心特性也随之启动,如自动装配。随后执行 SpringApplicationRunListenersstarted 阶段方法,表示 ApplicationContext 已启动,同时向 Spring Boot 监听器发布 ApplicationStartedEvent 事件 。但还未启动完成,后面还有一个 callRunners 方法,通常来说,里面执行一些咱们自定义的操做。以后 Spring 应用才算启动完成,随后调用 running 方法,发布 ApplicationReadyEvent 事件。至此,SpringApplication 运行阶段结束。

三、总结

        最后来对 SpringApplication 运行阶段作一个总结。这个阶段核心仍是以启动 Spring 应用上下文为主,同时根据应用类型来初始化不一样的上下文对象,但这些对象的基类都是 SpringConfigurableApplicationContext 类。且在启动的各个阶段中,使用 SpringApplicationRunListeners 进行事件广播,回调 Spring Boot 的监听器。同时还初始化了 ApplicationArgumentsConfigurableEnvironment 等几个组件。下篇文章咱们就来讨论 Spring Boot 的外部化配置部分,来看看为何外部的各个组件,如 RedisDubbo 等在 properties 文件中进行相应配置后,就能够正常使用。

以上就是本章的内容,如过文章中有错误或者须要补充的请及时提出,本人感激涕零。



参考:

《Spring Boot 编程思想》 https://www.cnblogs.com/youzhibing/p/9603119.html https://www.jianshu.com/p/b86a7c8b3442 https://www.cnblogs.com/duanxz/p/11243271.html https://www.jianshu.com/p/7a674c59d76e

相关文章
相关标签/搜索