最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

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

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

1、SpringApplicationEvent

它是和SpringApplication生命周期有關的所有事件的父類,@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,確保了事件和應用實體SpringApplication產(chǎn)生關聯(lián),它有如下子類,每個事件都代表著SpringApplication不同生命周期所處的位置:

2、ApplicationStartingEvent

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

ApplicationStartingEvent構造方法中傳遞了一個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維護的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默認事件廣播器, 有三個重要方法, 用于發(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維護了application中包含的listeners,
    //成員變量applicationListenerBeans Set維護了注入的listener bean名稱
    private final ListenerRetriever defaultRetriever = new ListenerRetriever(false);
    //調(diào)用getApplicationListeners()方法之后
    //緩存spring事件以及對應的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í)行刪除操作,防止重復執(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)))) {
            //雙重檢查鎖定
            //當多線程訪問的時候,
            //之前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;
    /**
     * 構造函數(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;
            }
        }
    }
}

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

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

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

3、ApplicationEnvironmentPreparedEvent

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

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

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

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

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

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

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

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

1.BootstrapApplicationListener:

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

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

2.LoggingSystemShutdownListener:

來自SpringCloud。對LogbackLoggingSystem先清理,再重新初始化一次,效果同上個事件,相當于重新來了一次,畢竟現(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彩色輸出,使其更具可讀性。當然前提是你的終端支持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()初始化動作:日志等級、日志格式模版等;值得注意的是:它這步相當于在ApplicationStartingEvent事件基礎上進一步完成了初始化(上一步只是實例化);

6.ClasspathLoggingApplicationListener:

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

7.BackgroundPreinitializer:

本事件達到時無動作;

8.DelegatingApplicationListener:

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

9.FileEncodingApplicationListener:

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

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

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

4、ApplicationContextInitializedEvent

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

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

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

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

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

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

  • BackgroundPreinitializer:本事件達到時無動作
  • DelegatingApplicationListener:本事件達到時無動作

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

5、ApplicationPreparedEvent

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

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

  • 把applicationArguments、printedBanner等都作為一個Bean放進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ā)對應的監(jiān)聽器的執(zhí)行

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

6、ApplicationStartedEvent

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

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

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

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

發(fā)送ApplicationStartedEvent事件,觸發(fā)對應的監(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)聽器:

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

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

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

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

7、ApplicationReadyEvent

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

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

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

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

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

8、ApplicationFailedEvent

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

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

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

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

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

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

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

最后

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

相關文章

  • Java8 Zip 壓縮與解壓縮的實現(xiàn)

    Java8 Zip 壓縮與解壓縮的實現(xiàn)

    這篇文章主要介紹了Java8 Zip 壓縮與解壓縮的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-03-03
  • Java中Object toString方法簡介_動力節(jié)點Java學院整理

    Java中Object toString方法簡介_動力節(jié)點Java學院整理

    Object類在Java里面是一個比較特殊的類,JAVA為了組織這個類組織得比較方便,它提供了一個最根上的類,相當于所有的類都是從這個類繼承,這個類就叫Object。接下來通過本文給大家介紹Object toString方法,需要的的朋友參考下吧
    2017-05-05
  • linux環(huán)境下java程序打包成簡單的hello world輸出jar包示例

    linux環(huán)境下java程序打包成簡單的hello world輸出jar包示例

    這篇文章主要介紹了linux環(huán)境下java程序打包成簡單的hello world輸出jar包,結合簡單hello world輸出程序示例分析了Linux環(huán)境下的java可執(zhí)行jar包文件的生成相關操作技巧,需要的朋友可以參考下
    2019-11-11
  • Spring 中優(yōu)雅的獲取泛型信息的方法

    Spring 中優(yōu)雅的獲取泛型信息的方法

    這篇文章主要介紹了Spring 中優(yōu)雅的獲取泛型信息的方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-03-03
  • Java Bean的作用域,生命周期和注解

    Java Bean的作用域,生命周期和注解

    這篇文章主要介紹了淺談Spring中Bean的作用域,生命周期和注解,具有一定借鑒價值,需要的朋友可以參考下,希望能夠給你帶來幫助
    2021-11-11
  • JAVA獲取特定格式時間方式

    JAVA獲取特定格式時間方式

    我們有時要獲取時間,年月日時分秒周幾,有時要以特定的格式出現(xiàn),本文主要介紹了JAVA獲取特定格式時間方式,具有一定的參考價值,感興趣的可以了解一下
    2023-10-10
  • SpringBoot整合Vue實現(xiàn)微信掃碼支付以及微信退款功能詳解

    SpringBoot整合Vue實現(xiàn)微信掃碼支付以及微信退款功能詳解

    最近公司要在微信公眾號上做一個活動預報名,活動的門票等需要在微信中支付,下面這篇文章主要給大家介紹了關于SpringBoot整合Vue實現(xiàn)微信掃碼支付以及微信退款功能的相關資料,需要的朋友可以參考下
    2022-05-05
  • Zookeeper啟動指定JDK版本方式

    Zookeeper啟動指定JDK版本方式

    文章講述了如何在Linux系統(tǒng)上啟動指定JDK版本的Zookeeper,包括下載JDK、解壓文件、修改zkEnv.sh腳本和重啟Zookeeper的過程
    2025-02-02
  • FreeMarker如何調(diào)用Java靜態(tài)方法及靜態(tài)變量方法

    FreeMarker如何調(diào)用Java靜態(tài)方法及靜態(tài)變量方法

    這篇文章主要介紹了FreeMarker如何調(diào)用Java靜態(tài)方法及靜態(tài)變量方法,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • Java基于阻塞隊列實現(xiàn)生產(chǎn)者消費者模型示例詳解

    Java基于阻塞隊列實現(xiàn)生產(chǎn)者消費者模型示例詳解

    這篇文章主要介紹了Java基于阻塞隊列實現(xiàn)生產(chǎn)者消費者模型,阻塞隊列的特點就是阻塞兩個字,阻塞功能使得生產(chǎn)者和消費者兩端的能力得以平衡,當有任何一端速度過快時,阻塞隊列便會把過快的速度降下來,感興趣的朋友可以參考下
    2023-12-12

最新評論

理塘县| 辽宁省| 乐昌市| 马尔康县| 囊谦县| 会泽县| 葵青区| 兴山县| 怀柔区| 建平县| 光山县| 古浪县| 锡林郭勒盟| 舒城县| 永德县| 固安县| 隆尧县| 西贡区| 达州市| 浦北县| 赫章县| 溆浦县| 内乡县| 宜丰县| 内黄县| 临湘市| 尚志市| 福海县| 洛隆县| 湛江市| 金山区| 余姚市| 商都县| 贡嘎县| 德化县| 灌南县| 游戏| 水富县| 奉新县| 会理县| 珲春市|