您好,登錄后才能下訂單哦!
這篇文章主要介紹“springboot2.0.6中SpringApplication實(shí)例初始化”,在日常操作中,相信很多人在springboot2.0.6中SpringApplication實(shí)例初始化問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”springboot2.0.6中SpringApplication實(shí)例初始化”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { // 設(shè)置資源加載器屬性 this.resourceLoader = resourceLoader; // 校驗(yàn)主要加載資源不能為空,為空拋出異常 Assert.notNull(primarySources, "PrimarySources must not be null"); // 設(shè)置primarySources(主要來(lái)源)屬性【后面會(huì)交給BeanDefinitionLoader,其分別load這些 primarySources 設(shè)置到scanner(掃描儀)中,避免重復(fù)掃描這些類進(jìn)入容器】 this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); // 獲取ApplicationContext類型,并設(shè)置到webApplicationType屬性中 this.webApplicationType = WebApplicationType.deduceFromClasspath(); // 獲取應(yīng)用上下文初始化器實(shí)例集合,并設(shè)置到initializers屬性中 setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class)); // 獲取應(yīng)用監(jiān)聽(tīng)器實(shí)例集合,并設(shè)置到listeners屬性中 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); // 找出main(主入口應(yīng)用類)類,這里是CoreServerApplication類 this.mainApplicationClass = deduceMainApplicationClass(); }
NONE:既不是運(yùn)行在 web 容器下的應(yīng)用并且也不應(yīng)該啟動(dòng)一個(gè)內(nèi)置的web服務(wù)。
SERVLET:是需要運(yùn)行在基于 servlet 的web應(yīng)用且需要啟動(dòng)一個(gè)內(nèi)置 servlet-web 服務(wù)。
REACTIVE:還是運(yùn)行在 reactive 的web應(yīng)用中且需要啟動(dòng)一個(gè) reactive-web 服務(wù)。
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"; private static final String SERVLET_APPLICATION_CONTEXT_CLASS = "org.springframework.web.context.WebApplicationContext"; private static final String REACTIVE_APPLICATION_CONTEXT_CLASS = "org.springframework.boot.web.reactive.context.ReactiveWebApplicationContext"; static WebApplicationType deduceFromClasspath() { if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null) && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) { return WebApplicationType.REACTIVE; } for (String className : SERVLET_INDICATOR_CLASSES) { if (!ClassUtils.isPresent(className, null)) { return WebApplicationType.NONE; } } return WebApplicationType.SERVLET; }
根據(jù)org.springframework.util.ClassUtils的靜態(tài)方法 isPresent 判斷classpath里面是否有包含 WEBFLUX_INDICATOR_CLASS 并且沒(méi)有包含 WEBMVC_INDICATOR_CLASS 和 JERSEY_INDICATOR_CLASSERVLET_INDICATOR_CLASSE ,滿足條件則表示啟動(dòng)一個(gè) REACTIVE 類型的WEB應(yīng)用,不滿足上述條件且有 SERVLET_INDICATOR_CLASSES 包含的類,則表示啟動(dòng)一個(gè) SERVLET 類型的WEB應(yīng)用,否則啟動(dòng)一個(gè)標(biāo)準(zhǔn)應(yīng)用。
是否啟動(dòng)一個(gè)WEB應(yīng)用就是取決于 classpath 下是否滿足有 javax.servlet.Servlet 和 org.springframework.web.context.ConfigurableWebApplicationContext 或有 org. springframework.web.reactive.DispatcherHandler 并且沒(méi)有org.springframework.web.servlet.DispatcherServlet 和 org.glassfish.jersey.servlet.ServletContainer。
初始化 classpath 下的所有的可用的 ApplicationContextInitializer
ApplicationContextInitializer 應(yīng)用程序初始化器,做一些初始化的工作,是 springboot 準(zhǔn)備調(diào)用 prepareContext 方法準(zhǔn)備 spring 容器(此時(shí)spring容器已經(jīng)創(chuàng)建需要refresh)之前調(diào)用的用來(lái)在這個(gè)時(shí)間點(diǎn)執(zhí)行一些操作:比如設(shè)置 servletContext 等
默認(rèn)情況下,getSpringFActoriesInstances 方法從 spring.factories 文件中找出key為 ApplicationContextInitializer 類型的權(quán)限定名稱集合有:
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer:
向應(yīng)用上下文中注冊(cè)后置處理器(ConfigurationWarningsPostProcessor)
org.springframework.boot.context.ContextIdApplicationContextInitializer
設(shè)置應(yīng)用上下文ID,并將上面生成的ContextId(ContextIdApplicationContextInitializer)對(duì)象,作為一個(gè)單例bean注冊(cè)到當(dāng)前應(yīng)用上下文。
org.springframework.boot.context.config.DelegatingApplicationContextInitializer
執(zhí)行環(huán)境屬性"context.initializer.classes"指定的初始化器,然后執(zhí)行這些初始化器。這里實(shí)現(xiàn)springboot應(yīng)用程序自己實(shí)現(xiàn)的ApplicationContextInitializer對(duì)應(yīng)用程序做一些初始化工作。
org.springframework.boot.context.web.ServerPortInfoApplicationContextInitializer
把自己作為監(jiān)聽(tīng)器注冊(cè)到應(yīng)用上下文中
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer
向應(yīng)用上下文中注冊(cè)后置處理器(CachingMetadataReaderFactoryPostProcessor)
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
向應(yīng)用上下文中注冊(cè)監(jiān)聽(tīng)器(ConditionEvaluationReportListener)當(dāng)應(yīng)用上下文實(shí)現(xiàn)GenercApplicationContext時(shí),則設(shè)置“report”屬性
( 圖1-2 spring-boot.jar 中 spring.factories文件中applicationContextInitializer相關(guān))
( 圖1 執(zhí)行g(shù)etSpringFactoriesInstances(ApplicationContextInitializer.class)獲取 spring.factories文件中applicationContextInitializer相關(guān)的工廠類,并進(jìn)行初始化)
( 圖2 springApplication對(duì)象中instances屬性值)
初使化 classpath 下的所有的可用的 ApplicationListener
ApplicationListener 應(yīng)用程序事件(ApplicationEvent)監(jiān)聽(tīng)器
這里的應(yīng)用程序事件(ApplicationEvent)有應(yīng)用程序啟動(dòng)事件(ApplicationStartedEvent),失敗事件(ApplicationFailedEvent),準(zhǔn)備事件(ApplicationPreparedEvent)等
應(yīng)用程序事件監(jiān)聽(tīng)器跟監(jiān)聽(tīng)事件是綁定的。比如 ConfigServerBootstrapApplicationListener 只跟 ApplicationEnvironmentPreparedEvent 事件綁定, LiquibaseServiceLocatorApplicationListener 只跟 ApplicationStartedEvent 事件綁定,LoggingApplicationListener 跟所有事件綁定等
默認(rèn)情況下,getSpringFactoriesInstances 方法從 spring.factories 文件中找出key為 ApplicationListener 類型的,類全限定名稱集合有:
org.springframework.boot.autoconfigure.BackgroundPreinitializer
org.springframework.boot.ClearCachesApplicationListener
org.springframework.boot.builder.ParentContextCloserApplicationListener
org.springframework.boot.context.FileEncodingApplicationListener
org.springframework.boot.context.config.AnsiOutputApplicationListener
org.springframework.boot.context.config.ConfigFileApplicationListener
org.springframework.boot.context.config.DelegatingApplicationListener
org.springframework.boot.context.logging.ClasspathLoggingApplicationListener
org.springframework.boot.context.logging.LoggingApplicationListener
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener
( 圖3-1 spring-boot.jar 中 spring.factories文件中applicationlistener相關(guān))
( 圖3-2 spring-boot.jar 中 spring.factories文件中applicationlistener相關(guān))
( 圖4 執(zhí)行g(shù)etSpringFactoriesInstances(Applicationlistener.class)獲取 spring.factories文件中applicationContextInitializer相關(guān)的工廠類,并進(jìn)行初始化)
由于spring 有一大堆事件比如 ContextRefreshedEvent,ContextStartedEvent 等等 我們有一個(gè) ApplicationListener 就會(huì)監(jiān)聽(tīng)到這些事件進(jìn)而做相應(yīng)的處理。
其實(shí)都是 applicationContext 調(diào)用其 publishEvent 發(fā)送一些 event,該方法會(huì)從很多 listener 中找到對(duì)該 event 感興趣的 listener 調(diào)用其 onApplicationEvent,而實(shí)現(xiàn)這些的就是 SimpleApplicationEventMulticaster,如果有 Executor,其會(huì)優(yōu)先使用Executor來(lái)執(zhí)行這就可能導(dǎo)致我們的回調(diào)是異步的。
applicationContext 還會(huì)把event傳播到其父容器(我們知道我們常用到AnnotationConfigApplicationContext 已經(jīng)其有很多父容器)
這邊還有一個(gè)策略就是如果 earlyApplicationEvents 存在 則先把事件加入到 earlyApplicationEvents,稍后在發(fā)送,如果不存在則直接發(fā)送。
applicationevent 中包含時(shí)間戳,springboot 啟動(dòng)類(source),還有我們的spring容器
如果我們想自己在代碼中寫 ApplicationContextInitializer 和 ApplicationListener 的實(shí)現(xiàn)類時(shí)候可以采用下列方式:
在項(xiàng)目中建立一個(gè) META-INF/spring.factories 文件,里面以 key=value 存放我們的實(shí)現(xiàn)類
手動(dòng)調(diào)用 SpringApplication 的對(duì)應(yīng)添加方法也可以
在我們的 application.properties 里面配置 context.initializer.classes = 實(shí)現(xiàn)類(通過(guò) DelegatingApplicationContextInitializer 獲取到我們配置的 initializer,進(jìn)而可以保證在 prepareContext 時(shí)候調(diào)用),context.listener.classes = 實(shí)現(xiàn)類(無(wú)法監(jiān)聽(tīng)到 springboot 啟動(dòng)時(shí)候的一些事件,因?yàn)槟莻€(gè)時(shí)候該實(shí)現(xiàn)類還未加入容器)
雖然我們使用 @Configuration 來(lái)講我們 ApplicationListener 的實(shí)現(xiàn)類加入到spring容器,且也能監(jiān)聽(tīng)到程序正常運(yùn)行的一些事件(無(wú)法監(jiān)聽(tīng)到 springboot 啟動(dòng)時(shí)候的一些事件,因?yàn)槟莻€(gè)時(shí)候該實(shí)現(xiàn)類還未加入容器),但是 我們?nèi)绻氡O(jiān)聽(tīng)全部的事件最好使用上述三種方式配置這樣可以在 springboot 啟動(dòng)的時(shí)候就監(jiān)聽(tīng)
通過(guò)系統(tǒng)加載類去指定目錄下根據(jù) propties 文件獲取對(duì)應(yīng)的 class 的全限定名稱
SpringApplication 的構(gòu)造方法主要就是設(shè)置 Initializers 和 Listeners 同時(shí)設(shè)置 primaryClass 方便后面先去加載 primaryClass,而且也順便確定了當(dāng)前的 springboot 的運(yùn)行環(huán)境
到此,關(guān)于“springboot2.0.6中SpringApplication實(shí)例初始化”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注億速云網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。