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