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

相關文章
相關標籤/搜索