欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

springboot之SpringApplication生命周期和事件機制解讀

 更新時間:2023年06月27日 15:34:13   作者:RachelHwang  
這篇文章主要介紹了springboot之SpringApplication生命周期和事件機制,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

本文將以SpringApplication的啟動流程以及生命周期各時期發(fā)出的Event事件為主線,結(jié)合每個生命周期內(nèi)完成的事件介紹,真正實現(xiàn)一文讓你總覽Spring Boot的全貌,這對讀者深入理解Spring Boot,以及整合進(jìn)Spring Cloud都將非常重要。

接下來我們先看下SpringApplication生命周期事件流程圖,然后再講解各個事件的詳情:

1、SpringApplicationEvent

它是和SpringApplication生命周期有關(guān)的所有事件的父類,@since 1.0.0

public abstract class SpringApplicationEvent extends ApplicationEvent {
	private final String[] args;
	public SpringApplicationEvent(SpringApplication application, String[] args) {
		super(application);
		this.args = args;
	}
	public SpringApplication getSpringApplication() {
		return (SpringApplication) getSource();
	}
	public final String[] getArgs() {
		return this.args;
	}
}

它是抽象類,擴展自Spring Framwork的ApplicationEvent,確保了事件和應(yīng)用實體SpringApplication產(chǎn)生關(guān)聯(lián),它有如下子類,每個事件都代表著SpringApplication不同生命周期所處的位置:

2、ApplicationStartingEvent

調(diào)用getRunListeners()方法, 實例化一個SpringApplicationRunListeners對象, SpringApplicationRunListeners的構(gòu)造參數(shù)通過getSpringFactoriesInstances()方法獲得,這個方法獲取的一個EventPublishingRunListener對象, 所以調(diào)用的是EventPublishingRunListener#starting()方法

ApplicationStartingEvent構(gòu)造方法中傳遞了一個SpringApplication對象和args參數(shù)。

一直傳遞到了父類EventObject,將SpringApplication對象存放在source變量中。

public class SpringApplication {
    //run方法
    public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        ConfigurableApplicationContext context = null;
        Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
        configureHeadlessProperty();
        //本文分析的重點,發(fā)布啟動事件ApplicationStartingEvent
        //獲取SpringApplicationRunListener的子類listener
        SpringApplicationRunListeners listeners = getRunListeners(args);
        //執(zhí)行其starting()方法
        listeners.starting();
        ....
    }
    //獲取SpringApplicationRunListener的子類listener
    private SpringApplicationRunListeners getRunListeners(String[] args) {
        Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
        //調(diào)用getSpringFactoriesInstances方法
        //獲取SpringApplicationRunListener的子類
        //子類只有一個,EventPublishingRunListener
        //實例化了一個SpringApplicationRunListeners對象
        return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
                SpringApplicationRunListener.class, types, this, args));
    }
}

2.1 SpringApplicationRunListeners

SpringApplicationRunListeners是一個比較重要的類, 之后的代碼會經(jīng)常調(diào)用這個方法,內(nèi)部封裝了一個SpringApplicationRunListener的list, 方便以后擴展,目前只有一個EventPublishingRunListener實例,所以spring的事件都是由EventPublishingRunListener發(fā)布的:

//SpringApplicationRunListeners部分源碼
class SpringApplicationRunListeners {
    private final Log log;
    //SpringApplicationRunListener的子類對象列表
    //listener列表擴展點
    private final List<SpringApplicationRunListener> listeners;
    SpringApplicationRunListeners(Log log,
            Collection<? extends SpringApplicationRunListener> listeners) {
        this.log = log;
        this.listeners = new ArrayList<>(listeners);
    }
    //發(fā)布啟動事件
    public void starting() {
        for (SpringApplicationRunListener listener : this.listeners) {
            //目前調(diào)用EventPublishingRunListener#starting方法
            listener.starting();
        }
    }
    //其他事件都是相同的代碼
    //....
}

2.2 EventPublishingRunListener

EventPublishingRunListener是springboot的事件廣播器, 內(nèi)部封裝了一個SimpleApplicationEventMulticaster對象,用來發(fā)布springboot加載過程中的各個事件

  • 事件源SpringApplication對象
  • 事件SpringApplicationEvent對象
  • 事件發(fā)布器是EventPublishingRunListener, 正在的事件發(fā)布器是其內(nèi)部SimpleApplicationEventMulticaster成員變量
  • 事件監(jiān)聽器SpringApplication維護(hù)的listeners, 調(diào)用AbstractApplicationEventMulticaster#getApplicationListeners(ApplicationEvent, ResolvableType)篩選出支持ApplicationEvent的listeners
//EventPublishingRunListener部分源碼
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
    //SpringApplication對象
    private final SpringApplication application;
    //命令函參數(shù)
    private final String[] args;
    //事件廣播器
    private final SimpleApplicationEventMulticaster initialMulticaster;
    public EventPublishingRunListener(SpringApplication application, String[] args) {
        this.application = application;
        this.args = args;
        this.initialMulticaster = new SimpleApplicationEventMulticaster();
        // 通過application.getListeners(),獲取到Listener列表
        // ConfigFileApplicationListener
        // AnsiOutputApplicationListener
        // LoggingApplicationListener
        // ClasspathLoggingApplicationListener
        // BackgroundPreinitializer
        // DelegatingApplicationListener
        // ParentContextCloserApplicationListener
        // ClearCachesApplicationListener
        // FileEncodingApplicationListener
        // LiquibaseServiceLocatorApplicationListener
        for (ApplicationListener<?> listener : application.getListeners()) {
            //將listener添加到事件廣播器initialMulticaster
            this.initialMulticaster.addApplicationListener(listener);
        }
    }
    @Override
    public void starting() {
        // 廣播器廣播ApplicationStartingEvent事件
        this.initialMulticaster.multicastEvent(
                new ApplicationStartingEvent(this.application, this.args));
    }
    //其他事件發(fā)布都是相同的代碼
    //...
}

2.3 SimpleApplicationEventMulticaster

springboot默認(rèn)事件廣播器, 有三個重要方法, 用于發(fā)布spring啟動過程中的各個事件:

  • addApplicationListener() 添加監(jiān)聽器listener
  • multicastEvent() 廣播spring事件
  • invokeListener() 實現(xiàn)每個listener的onApplicationEvent()方法

父類AbstractApplicationEventMulticaster,封裝了四個重要方法:

  • addApplicationListener添加listener
  • addApplicationListenerBean添加注入的listener bean名稱
  • removeApplicationListener刪除listener
  • removeApplicationListenerBean刪除注入的listener bean名稱
  • getApplicationListeners()先從緩存retrieverCache獲取listener,如果緩存不存在, 封裝數(shù)據(jù)放入緩存中, 增刪listener的時候, 緩存retrieverCache會被清空

以下是父類AbstractApplicationEventMulticaster源碼分析:

//抽象事件廣播器
public abstract class AbstractApplicationEventMulticaster
        implements ApplicationEventMulticaster, BeanClassLoaderAware, BeanFactoryAware {
    //監(jiān)聽器遍歷器
    //成員變量applicationListeners Set維護(hù)了application中包含的listeners,
    //成員變量applicationListenerBeans Set維護(hù)了注入的listener bean名稱
    private final ListenerRetriever defaultRetriever = new ListenerRetriever(false);
    //調(diào)用getApplicationListeners()方法之后
    //緩存spring事件以及對應(yīng)的listener列表
    final Map<ListenerCacheKey, ListenerRetriever> retrieverCache = new ConcurrentHashMap<>(64);
    private Object retrievalMutex = this.defaultRetriever;
    @Override
    public void addApplicationListener(ApplicationListener<?> listener) {
        synchronized (this.retrievalMutex) {
            //監(jiān)聽器已經(jīng)被加載過,
            //先執(zhí)行刪除操作,防止重復(fù)執(zhí)行
            Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
            if (singletonTarget instanceof ApplicationListener) {
                this.defaultRetriever.applicationListeners.remove(singletonTarget);
            }
            this.defaultRetriever.applicationListeners.add(listener);
            //清空緩存
            this.retrieverCache.clear();
        }
    }
    /**
     * 獲取支持監(jiān)聽event的listener
     * 這里使用了單例模式
     */
    protected Collection<ApplicationListener<?>> getApplicationListeners(
            ApplicationEvent event, ResolvableType eventType) {
        Object source = event.getSource();
        Class<?> sourceType = (source != null ? source.getClass() : null);
        ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);
        //嘗試從ConcurrentHashMap緩存中取出listener列表
        ListenerRetriever retriever = this.retrieverCache.get(cacheKey);
        if (retriever != null) {
            return retriever.getApplicationListeners();
        }
        if (this.beanClassLoader == null ||
                (ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
                        (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
            //雙重檢查鎖定
            //當(dāng)多線程訪問的時候,
            //之前retriever多個線程否返回null,
            //此時鎖住this.retrievalMutex
            //防止多次實例化
            synchronized (this.retrievalMutex) {
                //再嘗試從cache中獲取
                retriever = this.retrieverCache.get(cacheKey);
                if (retriever != null) {
                    return retriever.getApplicationListeners();
                }
                //生成Key和Value放入緩存中
                retriever = new ListenerRetriever(true);
                Collection<ApplicationListener<?>> listeners =
                        retrieveApplicationListeners(eventType, sourceType, retriever);
                this.retrieverCache.put(cacheKey, retriever);
                return listeners;
            }
        }
        else {
            //沒有緩存ListenerRetriever,那么就不需要同步
            return retrieveApplicationListeners(eventType, sourceType, null);
        }
    }
    //retrieveApplicationListeners方法中
    //調(diào)用了supportsEvent方法
    //supportsEvent使用了適配器模式
    protected boolean supportsEvent(
            ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType) {
        GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ?
                (GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener));
        return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));
    }
}

SimpleApplicationEventMulticaster源碼分析:

廣播事件, 然后實現(xiàn)每個listener的onApplicationEvent()方法

public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
    @Nullable
    private Executor taskExecutor;
    @Nullable
    private ErrorHandler errorHandler;
    /**
     * 構(gòu)造函數(shù)
     * taskExecutor和errorHandler都是null
     */
    public SimpleApplicationEventMulticaster() {
    }
    /**
     * 廣播事件
     * @param event 事件
     * @param eventType 事件類型
     */
    @Override
    public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
        ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
        //調(diào)用父類getApplicationListeners方法
        //遍歷所有支持ApplicationStartingEvent事件的監(jiān)聽器
        //LoggingApplicationListener
        //BackgroundPreinitializer
        //DelegatingApplicationListener
        //LiquibaseServiceLocatorApplicationListener
        for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
            //此時的executor為null
            Executor executor = getTaskExecutor();
            if (executor != null) {
                executor.execute(() -> invokeListener(listener, event));
            }
            else {
                //調(diào)用listener
                invokeListener(listener, event);
            }
        }
    }
    /**
     * 具體調(diào)用監(jiān)聽器的方法
     * @param listener 監(jiān)聽器
     * @param event 事件
     */
    private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
        try {
            //調(diào)用listener的onApplicationEvent方法
            listener.onApplicationEvent(event);
        }
        catch (ClassCastException ex) {
            String msg = ex.getMessage();
            if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
                Log logger = LogFactory.getLog(getClass());
                if (logger.isDebugEnabled()) {
                    logger.debug("Non-matching event type for listener: " + listener, ex);
                }
            }
            else {
                throw ex;
            }
        }
    }
}

默認(rèn)情況下,有4個監(jiān)聽器監(jiān)聽ApplicationStartingEvent事件:

  • LoggingApplicationListener:日志監(jiān)聽器,配置日志;@since 2.0.0。對日志系統(tǒng)抽象LoggingSystem執(zhí)行實例化以及初始化之前的操作,默認(rèn)使用的是基于Logback的LogbackLoggingSystem
  • BackgroundPreinitializer:啟動一個后臺進(jìn)行對一些類進(jìn)行預(yù)熱。如ValidationInitializer、JacksonInitializer…,因為這些組件有第一次觸發(fā)的特點(并且首次初始化均還比較耗時),所以使用后臺線程先預(yù)熱效果更佳
  • DelegatingApplicationListener:代理監(jiān)聽器, 繼續(xù)發(fā)布事件;它監(jiān)聽的是ApplicationEvent,而實際上只會ApplicationEnvironmentPreparedEvent到達(dá)時生效,所以此處忽略
  • LiquibaseServiceLocatorApplicationListener:將liquibas替換為可以和spring配合工作的版本

總結(jié):此事件節(jié)點結(jié)束時,SpringApplication完成了一些實例化相關(guān)的動作:本實例實例化、本實例屬性賦值、日志系統(tǒng)實例化等。

3、ApplicationEnvironmentPreparedEvent

@since 1.0.0。該事件節(jié)點是最為重要的一個節(jié)點之一,因為對于Spring應(yīng)用來說,環(huán)境抽象Enviroment簡直太重要了,它是最為基礎(chǔ)的元數(shù)據(jù),決定著程序的構(gòu)建和走向,所以構(gòu)建的時機是比較早的。

完成的事件內(nèi)容:

封裝命令行參數(shù)(main方法的args)到ApplicationArguments里面

創(chuàng)建出一個環(huán)境抽象實例ConfigurableEnvironment的實現(xiàn)類,并且填入值:Profiles配置和Properties屬性,默認(rèn)內(nèi)容如下(注意,這只是初始狀態(tài),后面還會改變):

發(fā)送ApplicationEnvironmentPreparedEvent事件,觸發(fā)對應(yīng)的監(jiān)聽器的執(zhí)行;對環(huán)境抽象Enviroment的填值,均是由監(jiān)聽此事件的監(jiān)聽器去完成

bindToSpringApplication(environment):把環(huán)境屬性中spring.main.xxx = xxx綁定到當(dāng)前的SpringApplication實例屬性上,如常用的spring.main.allow-bean-definition-overriding=true會被綁定到當(dāng)前SpringApplication實例的對應(yīng)屬性上

監(jiān)聽此事件的監(jiān)聽器:

默認(rèn)情況下,有9個監(jiān)聽器監(jiān)聽ApplicationEnvironmentPreparedEvent事件:

1.BootstrapApplicationListener:

來自SpringCloud。優(yōu)先級最高,用于啟動/創(chuàng)建Spring Cloud的應(yīng)用上下文。需要注意的是:到此時SB的上下文ApplicationContext還并沒有創(chuàng)建哦。這個流程“嵌套”特別像Bean初始化流程:初始化Bean A時,遇到了Bean B,就需要先去完成Bean B的初始化,再回頭來繼續(xù)完成Bean A的步驟。

說明:在創(chuàng)建SC的應(yīng)用的時候,使用的也是SpringApplication#run()完成的(非web),因此也會走下一整套SpringApplication的生命周期邏輯,所以務(wù)必區(qū)分。特別是這種case會讓“絕大多數(shù)”初始化器、監(jiān)聽器等執(zhí)行多次,若你有那種只需要執(zhí)行一次的需求(比如只想讓SB容器生命周期內(nèi)執(zhí)行,SC生命周期不執(zhí)行),請務(wù)必自行處理,否則會被執(zhí)行多次而帶來不可預(yù)知的結(jié)果;SC應(yīng)用上下文讀取的外部化配置文件名默認(rèn)是:bootstrap,使用的也是ConfigFileApplicationListener完成的加載/解析;

2.LoggingSystemShutdownListener:

來自SpringCloud。對LogbackLoggingSystem先清理,再重新初始化一次,效果同上個事件,相當(dāng)于重新來了一次,畢竟現(xiàn)在有Enviroment環(huán)境;

3.ConfigFileApplicationListener:

@since 1.0.0。它也許是最重要的一個監(jiān)聽器。做了如下事情:

加載SPI配置的所有的EnvironmentPostProcessor實例,并且排好序。

需要注意的是:ConfigFileApplicationListener也是個EnvironmentPostProcessor,也會參與排序; 排好序后,分別一個個的執(zhí)行以下EnvironmentPostProcessor

4.AnsiOutputApplicationListener:

@since 1.2.0。讓你的終端(可以是控制臺、可以是日志文件)支持Ansi彩色輸出,使其更具可讀性。當(dāng)然前提是你的終端支持ANSI顯示。參考類:AnsiOutput。你可通過spring.output.ansi.enabled = xxx配置,可選值是:DETECT/ALWAYS/NEVER,一般不動即可。另外,針對控制臺可以單獨配置:spring.output.ansi.console-available = true/false

5.LoggingApplicationListener:

@since 2.0.0。根據(jù)Enviroment環(huán)境完成initialize()初始化動作:日志等級、日志格式模版等;值得注意的是:它這步相當(dāng)于在ApplicationStartingEvent事件基礎(chǔ)上進(jìn)一步完成了初始化(上一步只是實例化);

6.ClasspathLoggingApplicationListener:

@since 2.0.0。用于把classpath路徑以log.debug()輸出;值得注意的是:classpath類路徑是有N多個的Arrays.toString(((URLClassLoader) classLoader).getURLs()),也就是說每個.jar里都屬于classpath的范疇;

7.BackgroundPreinitializer:

本事件達(dá)到時無動作;

8.DelegatingApplicationListener:

執(zhí)行通過外部化配置context.listener.classes = xxx,xxx的監(jiān)聽器們,然后把該事件廣播給他們,執(zhí)行監(jiān)聽此事件的監(jiān)聽器;這麼做的好處:可以通過屬性文件外部化配置監(jiān)聽器,而不一定必須寫在spring.factories里,更具彈性;

9.FileEncodingApplicationListener:

檢測當(dāng)前系統(tǒng)環(huán)境的file.encoding和spring.mandatory-file-encoding設(shè)置的值是否一樣,如果不一樣則拋出異常如果不配置spring.mandatory-file-encoding則不檢查;

總結(jié):此事件節(jié)點結(jié)束時,Spring Boot的環(huán)境抽象Enviroment已經(jīng)準(zhǔn)備完畢,但此時其上下文ApplicationContext還沒有創(chuàng)建,但是Spring Cloud的應(yīng)用上下文(引導(dǎo)上下文)已經(jīng)全部初始化完畢哦,所以SC管理的外部化配置也應(yīng)該都進(jìn)入到了SB里面。

如下圖所示(這是基本上算是Enviroment的最終態(tài)了):

4、ApplicationContextInitializedEvent

@since 2.1.0,非常新的一個事件。當(dāng)SpringApplication的上下文ApplicationContext準(zhǔn)備好后,對單例Bean們實例化之前,發(fā)送此事件。

所以此事件又可稱為:contextPrepared事件。

完成的事件內(nèi)容:

上下文實例已經(jīng)有了,那么就開始對它進(jìn)行一些參數(shù)的設(shè)置:

  • 首先最重要的便是把已經(jīng)準(zhǔn)備好的環(huán)境Enviroment環(huán)境設(shè)置給它
  • 設(shè)置些beanNameGenerator、resourceLoader、ConversionService等組件
  • 實例化所有的ApplicationContextInitializer上下文初始化器,并且排序好后挨個執(zhí)行它(這個很重要),默認(rèn)有如下截圖這些初始化器此時要執(zhí)行:

監(jiān)聽此事件的監(jiān)聽器:監(jiān)聽此事件默認(rèn)情況下,有2個監(jiān)聽器監(jiān)聽ApplicationContextInitializedEvent事件:

  • BackgroundPreinitializer:本事件達(dá)到時無動作
  • DelegatingApplicationListener:本事件達(dá)到時無動作

總結(jié):此事件節(jié)點結(jié)束時,完成了應(yīng)用上下文ApplicationContext的準(zhǔn)備工作,并且執(zhí)行所有注冊的上下文初始化器ApplicationContextInitializer。但是此時,單例Bean是仍舊還沒有初始化,并且WebServer也還沒有啟動;

5、ApplicationPreparedEvent

@since 1.0.0。截止到上個事件ApplicationContextInitializedEvent,應(yīng)用上下文ApplicationContext充其量叫實例化好了,但是還剩下很重要的事沒做,便是此事件的執(zhí)行內(nèi)容了;

完成的事件內(nèi)容:

  • 把applicationArguments、printedBanner等都作為一個Bean放進(jìn)Bean工廠里(因此你就可以@Autowired注入的哦)

比如:有了Banner這個Bean,你可以在你任何想要輸出的地方輸出一個Banner,而不僅僅是啟動時只會輸出一次了;

  • 若lazyInitialization = true延遲初始化,那就向Bean工廠放一個:new LazyInitializationBeanFactoryPostProcessor()

該處理器@since 2.2.0。該處理器的作用是:對所有的Bean(通過LazyInitializationExcludeFilter接口指定的排除在外)全部.setLazyInit(true),延遲初始化;

根據(jù)primarySources和allSources,交給BeanDefinitionLoader(SB提供的實現(xiàn))實現(xiàn)加載Bean的定義信息,它支持4種加載方式(4種源):

  • AnnotatedBeanDefinitionReader -> 基于注解
  • XmlBeanDefinitionReader -> 基于xml配置
  • GroovyBeanDefinitionReader -> Groovy文件
  • ClassPathBeanDefinitionScanner -> classpath中加載(不同的源使用了不同的load加載方式)

發(fā)送ApplicationPreparedEvent事件,觸發(fā)對應(yīng)的監(jiān)聽器的執(zhí)行

總結(jié):此事件節(jié)點結(jié)束時,應(yīng)用上下文ApplicationContext初始化完成,該賦值的賦值了,Bean定義信息也已全部加載完成。但是,單例Bean還沒有被實例化,web容器依舊還沒啟動。

6、ApplicationStartedEvent

@since 2.0.0。截止到此,應(yīng)用已經(jīng)準(zhǔn)備就緒,并且通過監(jiān)聽器、初始化器等完成了非常多的工作了,但仍舊剩下被認(rèn)為最為重要的初始化單例Bean動作還沒做、web容器(如Tomcat)還沒啟動,這便是這個周期所要做的事。

完成的事件內(nèi)容:

啟動Spring容器:AbstractApplicationContext#refresh(),這個步驟會做很多事,比如會實例化單例Bean;該步驟屬于Spring Framework的核心內(nèi)容范疇,做了很多事,請參考Spring核心技術(shù);在Spring容器refresh()啟動完成后,WebServer也隨之完成啟動,成功監(jiān)聽到對應(yīng)端口;

輸出啟動成功的日志:Started Application in xxx seconds (JVM running for xxx);

發(fā)送ApplicationStartedEvent事件,觸發(fā)對應(yīng)的監(jiān)聽器的執(zhí)行;

  • callRunners():依次執(zhí)行容器內(nèi)配置的ApplicationRunner/CommandLineRunner的Bean實現(xiàn)類,支持sort排序:
  • ApplicationRunner:@since 1.3.0,入?yún)⑹茿pplicationArguments,先執(zhí)行(推薦使用)
  • CommandLineRunner:@since 1.0.0,入?yún)⑹荢tring… args,后執(zhí)行(不推薦使用)

監(jiān)聽此事件的監(jiān)聽器:

默認(rèn)情況下,有3個監(jiān)聽器監(jiān)聽ApplicationStartedEvent事件:

1.前兩個不用再解釋了吧:本事件達(dá)到時無動作

2.TomcatMetricsBinder:@since 2.1.0。和監(jiān)控相關(guān):將你的tomcat指標(biāo)信息TomcatMetrics綁定到MeterRegistry,從而就能收集到相關(guān)指標(biāo)了

總結(jié):此事件節(jié)點結(jié)束時,SpringApplication的生命周期到這一步,正常的啟動流程就全部完成了。也就說Spring Boot應(yīng)用可以正常對對外提供服務(wù)了。

7、ApplicationReadyEvent

@since 1.3.0。該事件所處的生命周期可認(rèn)為基本和ApplicationStartedEvent相同,僅是在其后執(zhí)行而已,兩者中間并無其它特別的動作,但是監(jiān)聽此事件的監(jiān)聽器們還是蠻重要的。

監(jiān)聽此事件的監(jiān)聽器:

默認(rèn)情況下,有4個監(jiān)聽器監(jiān)聽ApplicationStartedEvent事件:

  • SpringApplicationAdminMXBeanRegistrar:當(dāng)此事件到達(dá)時,告訴Admin Spring應(yīng)用已經(jīng)ready,可以使用啦。
  • 中間這兩個不用再解釋了吧:本事件達(dá)到時無動作
  • RefreshEventListener:當(dāng)此事件到達(dá)時,告訴Spring應(yīng)用已經(jīng)ready了,接下來便可以執(zhí)行ContextRefresher.refresh()

總結(jié):此事件節(jié)點結(jié)束時,應(yīng)用已經(jīng)完完全全的準(zhǔn)備好了,并且也已經(jīng)完成了相關(guān)組件的周知工作。

8、ApplicationFailedEvent

當(dāng)SpringApplication在啟動時拋出異常:可能是端口綁定、也可能是你自定義的監(jiān)聽器你寫了個bug等,就會“可能”發(fā)送此事件。

完成的事件內(nèi)容:

  • 得到異常的退出碼ExitCode,然后發(fā)送ExitCodeEvent事件(非生命周期事件)
  • 發(fā)送ApplicationFailedEvent事件,觸發(fā)對應(yīng)的監(jiān)聽器的執(zhí)行

監(jiān)聽此事件的監(jiān)聽器:

默認(rèn)情況下,有6個監(jiān)聽器監(jiān)聽ApplicationStartedEvent事件:

  • LoggingApplicationListener:執(zhí)行l(wèi)oggingSystem.cleanUp()清理資源
  • ClasspathLoggingApplicationListener:輸出一句debug日志:Application failed to start with classpath: …
  • 中間這兩個不用再解釋了吧:本事件達(dá)到時無動作
  • ConditionEvaluationReportLoggingListener:自動配置輸出報告,輸出錯誤日志唄:特別方便你查看和錯誤定位;
  • BootstrapApplicationListener.CloseContextOnFailureApplicationListener:執(zhí)行context.close()

總結(jié):此事件節(jié)點結(jié)束時,會做一些釋放資源的操作。一般情況下:我們并不需要監(jiān)聽到此事件;

最后

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • java實現(xiàn)文件上傳下載

    java實現(xiàn)文件上傳下載

    這篇文章主要為大家詳細(xì)介紹了java實現(xiàn)文件上傳下載功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-08-08
  • Spring AI集成DeepSeek的詳細(xì)步驟

    Spring AI集成DeepSeek的詳細(xì)步驟

    DeepSeek 作為一款卓越的國產(chǎn) AI 模型,越來越多的公司考慮在自己的應(yīng)用中集成,對于 Java 應(yīng)用來說,我們可以借助 Spring AI 集成 DeepSeek,非常簡單方便,本文給大家介紹了Spring AI集成DeepSeek的詳細(xì)步驟,需要的朋友可以參考下
    2025-02-02
  • JAVA操作MongoDB數(shù)據(jù)庫實例教程

    JAVA操作MongoDB數(shù)據(jù)庫實例教程

    MongoDB是一個文檔型數(shù)據(jù)庫,是NOSQL家族中最重要的成員之一,下面這篇文章主要給大家介紹了關(guān)于JAVA操作MongoDB數(shù)據(jù)庫的相關(guān)資料,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-05-05
  • springboot?無法自動裝配的問題

    springboot?無法自動裝配的問題

    這篇文章主要介紹了springboot?無法自動裝配的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • mybatis-plus添加數(shù)據(jù)時id自增問題及解決

    mybatis-plus添加數(shù)據(jù)時id自增問題及解決

    這篇文章主要介紹了mybatis-plus添加數(shù)據(jù)時id自增問題及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • Java中類的初始化和實例化區(qū)別詳解

    Java中類的初始化和實例化區(qū)別詳解

    這篇文章主要介紹了Java中類的初始化和實例化區(qū)別詳解,類的初始化<BR>是完成程序執(zhí)行前的準(zhǔn)備工作,類的實例化(實例化對象)是指創(chuàng)建一個對象的過程,需要的朋友可以參考下
    2023-08-08
  • Jmeter設(shè)置全局變量token過程圖解

    Jmeter設(shè)置全局變量token過程圖解

    這篇文章主要介紹了Jmeter設(shè)置全局變量token過程圖解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-09-09
  • java中Spring Security的實例詳解

    java中Spring Security的實例詳解

    這篇文章主要介紹了java中Spring Security的實例詳解的相關(guān)資料,spring security是一個多方面的安全認(rèn)證框架,提供了基于JavaEE規(guī)范的完整的安全認(rèn)證解決方案,需要的朋友可以參考下
    2017-09-09
  • 解讀@Scheduled任務(wù)調(diào)度/定時任務(wù)非分布式

    解讀@Scheduled任務(wù)調(diào)度/定時任務(wù)非分布式

    這篇文章主要介紹了解讀@Scheduled任務(wù)調(diào)度/定時任務(wù)非分布式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • spring boot使用WebClient調(diào)用HTTP服務(wù)代碼示例

    spring boot使用WebClient調(diào)用HTTP服務(wù)代碼示例

    這篇文章主要介紹了spring boot使用WebClient調(diào)用HTTP服務(wù)代碼示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-12-12

最新評論