国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當(dāng)前位置: 首頁(yè) > news >正文

免費(fèi)創(chuàng)辦網(wǎng)站印度疫情最新消息

免費(fèi)創(chuàng)辦網(wǎng)站,印度疫情最新消息,東莞平面設(shè)計(jì)公司有哪些,四川南充房產(chǎn)網(wǎng)文章目錄 run方法核心流程SpringApplicationRunListener監(jiān)聽(tīng)器監(jiān)聽(tīng)器的配置與加載SpringApplicationRunListener源碼解析實(shí)現(xiàn)類EventPublishingRunListener 初始化ApplicationArguments初始化ConfigurableEnvironment獲取或創(chuàng)建環(huán)境配置環(huán)境 打印BannerSpring應(yīng)用上下文的創(chuàng)建S…

文章目錄

  • run方法核心流程
  • SpringApplicationRunListener監(jiān)聽(tīng)器
    • 監(jiān)聽(tīng)器的配置與加載
    • SpringApplicationRunListener源碼解析
    • 實(shí)現(xiàn)類EventPublishingRunListener
  • 初始化ApplicationArguments
  • 初始化ConfigurableEnvironment
      • 獲取或創(chuàng)建環(huán)境
      • 配置環(huán)境
  • 打印Banner
  • Spring應(yīng)用上下文的創(chuàng)建
  • Spring應(yīng)用上下文的準(zhǔn)備
  • Spring應(yīng)用上下文的刷新
  • 調(diào)用ApplicationRunner和CommandLineRunner

run方法核心流程

在分析和學(xué)習(xí)整個(gè)run方法的源代碼及操作之前,我們先通過(guò)下圖所示的流程圖來(lái)看一下SpringApplication調(diào)用的run方法處理的核心操作都包含哪些。

在這里插入圖片描述

上面的流程圖可以看出,SpringApplication在run方法中重點(diǎn)做了以下操作。

  • 獲取監(jiān)聽(tīng)器和參數(shù)配置。
  • 打印Banner信息。
  • 創(chuàng)建并初始化容器。
  • 監(jiān)聽(tīng)器發(fā)送通知。

當(dāng)然,除了核心操作,run方法運(yùn)行過(guò)程中還涉及啟動(dòng)時(shí)長(zhǎng)統(tǒng)計(jì)、異常報(bào)告、啟動(dòng)日志、異常處理等輔助操作。

public ConfigurableApplicationContext run(String... args) {StopWatch stopWatch = new StopWatch();stopWatch.start();ConfigurableApplicationContext context = null;Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();this.configureHeadlessProperty();SpringApplicationRunListeners listeners = this.getRunListeners(args);listeners.starting();Collection exceptionReporters;try {// 創(chuàng)建 ApplicationArguments 對(duì)象ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);//  加載屬性配置ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);this.configureIgnoreBeanInfo(environment);//  打印bannerBanner printedBanner = this.printBanner(environment);// 創(chuàng)建容器context = this.createApplicationContext();//  異常報(bào)告器exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);//  準(zhǔn)備容器this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);// 初始化容器this.refreshContext(context);//  初始化容器后this.afterRefresh(context, applicationArguments);// 停止時(shí)長(zhǎng)統(tǒng)計(jì)stopWatch.stop();//  打印日志if (this.logStartupInfo) {(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);}//  通知監(jiān)聽(tīng)器容器啟動(dòng)完成listeners.started(context);this.callRunners(context, applicationArguments);} catch (Throwable var10) {//  異常處理this.handleRunFailure(context, var10, exceptionReporters, listeners);throw new IllegalStateException(var10);}try {//  通知監(jiān)聽(tīng)器:容器正在運(yùn)行listeners.running(context);return context;} catch (Throwable var9) {// 異常處理this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);throw new IllegalStateException(var9);}
}

SpringApplicationRunListener監(jiān)聽(tīng)器

監(jiān)聽(tīng)器的配置與加載

SpringApplicationRunListeners 可以理解為一個(gè)SpringApplicationRunListener的容器,它將SpringApplicationRunListener的集合以構(gòu)造方法傳入,并賦值給其listeners成員變量,然后提供了針對(duì)listeners 成員變量的各種遍歷操作方法,比如,遍歷集合并調(diào)用對(duì)應(yīng)的starting、started、running等方法。

SpringApplicationRunListeners 的構(gòu)建很簡(jiǎn)單,SpringApplication中g(shù)etRunListeners方法代碼如下:


private SpringApplicationRunListeners getRunListeners(String[] args) {Class<?>[] types = new Class[]{SpringApplication.class, String[].class};return new SpringApplicationRunListeners(logger, this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}

SpringApplicationRunListeners構(gòu)造方法的第二個(gè)參數(shù)便是SpringApplicationRunListener的集合,SpringApplication中調(diào)用構(gòu)造方法時(shí)該參數(shù)是通過(guò)getSpringFactoriesInstances方法獲取(都是一樣的套路)的,代碼如下:


private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {// 獲取類加載器ClassLoader classLoader = this.getClassLoader();//  加載監(jiān)聽(tīng)器,并放入set中Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));// 實(shí)例化監(jiān)聽(tīng)器List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);//  排序AnnotationAwareOrderComparator.sort(instances);return instances;
}

通過(guò)方法名便可得知,getSpringFactoriesInstances是用來(lái)獲取factories配置文件中的注冊(cè)類,并進(jìn)行實(shí)例化操作。

關(guān)于通過(guò)SpringFactoriesLoader獲取META-INF/spring.factories中對(duì)應(yīng)的配置,構(gòu)造方法章節(jié)已經(jīng)多次提到,這里不再贊述。SpringApplicationRunListener的注冊(cè)配置位于spring-boot項(xiàng)目中的spring.factories文件內(nèi),SpringBoot默認(rèn)僅有一個(gè)監(jiān)聽(tīng)器進(jìn)行了注冊(cè),關(guān)于其功能后面會(huì)專門(mén)講到。


private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args, Set<String> names) {List<T> instances = new ArrayList(names.size());Iterator var7 = names.iterator();while(var7.hasNext()) {String name = (String)var7.next();try {Class<?> instanceClass = ClassUtils.forName(name, classLoader);Assert.isAssignable(type, instanceClass);Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);T instance = BeanUtils.instantiateClass(constructor, args);instances.add(instance);} catch (Throwable var12) {throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, var12);}}return instances;
}

在上面的代碼中,實(shí)例化監(jiān)聽(tīng)器時(shí)需要有一個(gè)默認(rèn)的構(gòu)造方法,且構(gòu)造方法的參數(shù)為Class<?>[]parameterTypes。我們向上追蹤該參數(shù)的來(lái)源,會(huì)發(fā)現(xiàn)該參數(shù)的值為Class數(shù)組,數(shù)組的內(nèi)容依次為SpringApplication.class和String[].class。也就是說(shuō),SpringApplicationRunListener的實(shí)現(xiàn)類必須有默認(rèn)的構(gòu)造方法,且構(gòu)造方法的參數(shù)必須依次為SpringApplication和String[]類型。

SpringApplicationRunListener源碼解析

接口SpringApplicationRunListener是SpringApplication的run方法監(jiān)聽(tīng)器。上節(jié)提到了 SpringApplicationRunListener通過(guò)SpringFactoriesLoader加載,并且必須聲明一個(gè)公共構(gòu)造函數(shù),該函數(shù)接收SpringApplication實(shí)例和String[]的參數(shù),而且每次運(yùn)行都會(huì)創(chuàng)建一個(gè)新的實(shí)例。

SpringApplicationRunListener提供了一系列的方法,用戶可以通過(guò)回調(diào)這些方法,在啟動(dòng)各個(gè)流程時(shí)加入指定的邏輯處理。


class SpringApplicationRunListeners {private final Log log;private final List<SpringApplicationRunListener> listeners;SpringApplicationRunListeners(Log log, Collection<? extends SpringApplicationRunListener> listeners) {this.log = log;this.listeners = new ArrayList(listeners);}public void starting() {Iterator var1 = this.listeners.iterator();while(var1.hasNext()) {SpringApplicationRunListener listener = (SpringApplicationRunListener)var1.next();listener.starting();}}public void environmentPrepared(ConfigurableEnvironment environment) {Iterator var2 = this.listeners.iterator();while(var2.hasNext()) {SpringApplicationRunListener listener = (SpringApplicationRunListener)var2.next();listener.environmentPrepared(environment);}}public void contextPrepared(ConfigurableApplicationContext context) {Iterator var2 = this.listeners.iterator();while(var2.hasNext()) {SpringApplicationRunListener listener = (SpringApplicationRunListener)var2.next();listener.contextPrepared(context);}}public void contextLoaded(ConfigurableApplicationContext context) {Iterator var2 = this.listeners.iterator();while(var2.hasNext()) {SpringApplicationRunListener listener = (SpringApplicationRunListener)var2.next();listener.contextLoaded(context);}}public void started(ConfigurableApplicationContext context) {Iterator var2 = this.listeners.iterator();while(var2.hasNext()) {SpringApplicationRunListener listener = (SpringApplicationRunListener)var2.next();listener.started(context);}}public void running(ConfigurableApplicationContext context) {Iterator var2 = this.listeners.iterator();while(var2.hasNext()) {SpringApplicationRunListener listener = (SpringApplicationRunListener)var2.next();listener.running(context);}}public void failed(ConfigurableApplicationContext context, Throwable exception) {Iterator var3 = this.listeners.iterator();while(var3.hasNext()) {SpringApplicationRunListener listener = (SpringApplicationRunListener)var3.next();this.callFailedListener(listener, context, exception);}}private void callFailedListener(SpringApplicationRunListener listener, ConfigurableApplicationContext context, Throwable exception) {try {listener.failed(context, exception);} catch (Throwable var6) {if (exception == null) {ReflectionUtils.rethrowRuntimeException(var6);}if (this.log.isDebugEnabled()) {this.log.error("Error handling failed", var6);} else {String message = var6.getMessage();message = message != null ? message : "no error message";this.log.warn("Error handling failed (" + message + ")");}}}
}

我們通過(guò)源代碼可以看出,SpringApplicationRunListener為run方法提供了各個(gè)運(yùn)行階段的監(jiān)聽(tīng)事件處理功能。

下圖展示了在整個(gè)run方法的生命周期中SpringApplicationRunListener的所有方法所處的位置,該圖可以幫助我們更好地學(xué)習(xí)run方法的運(yùn)行流程。在前面run方法的代碼中已經(jīng)看到相關(guān)監(jiān)聽(tīng)方法被調(diào)用,后續(xù)的源代碼中也將涉及對(duì)應(yīng)方法的調(diào)用,我們可參考此圖以便理解和加深記憶。

在這里插入圖片描述

實(shí)現(xiàn)類EventPublishingRunListener

EventPublishingRunListener是SpringBoot中針對(duì)SpringApplicationRunListener接口的唯一內(nèi)建實(shí)現(xiàn)。EventPublishingRunListener使用內(nèi)置的SimpleApplicationEventMulticaster來(lái)廣播在上下文刷新之前觸發(fā)的事件。

默認(rèn)情況下,SpringBoot在初始化過(guò)程中觸發(fā)的事件也是交由EventPublishingRunListener來(lái)代理實(shí)現(xiàn)的。

SpringBoot完成基本的初始化之后,會(huì)遍歷SpringApplication的所有ApplicationListener實(shí)例,并將它們與SimpleApplicationEventMulticaster進(jìn)行關(guān)聯(lián),方便SimpleApplicationEventMulticaster后續(xù)將事件傳遞給所有的監(jiān)聽(tīng)器。

EventPublishingRunListener針對(duì)不同的事件提供了不同的處理方法,但它們的處理流程基本相同。


public void contextLoaded(ConfigurableApplicationContext context) {ApplicationListener listener;for(Iterator var2 = this.application.getListeners().iterator(); var2.hasNext(); context.addApplicationListener(listener)) {listener = (ApplicationListener)var2.next();if (listener instanceof ApplicationContextAware) {((ApplicationContextAware)listener).setApplicationContext(context);}}this.initialMulticaster.multicastEvent(new ApplicationPreparedEvent(this.application, this.args, context));
}

contextLoaded方法在發(fā)布事件之前做了兩件事:第一,遍歷application的所有監(jiān)聽(tīng)器實(shí)現(xiàn)類,如果該實(shí)現(xiàn)類還實(shí)現(xiàn)了ApplicationContextAware接口,則將上下文信息設(shè)置到該監(jiān)聽(tīng)器內(nèi);第二,將application中的監(jiān)聽(tīng)器實(shí)現(xiàn)類全部添加到上下文中。最后一步才是調(diào)用事件廣播。

也正是這個(gè)方法形成了不同事件廣播形式的分水嶺,在此方法之前執(zhí)行的事件廣播都是通過(guò)multicastEvent來(lái)進(jìn)行的,而該方法之后的方法則均采用publishEvent來(lái)執(zhí)行。這是因?yàn)橹挥械搅薱ontextLoaded方法之后,上下文才算初始化完成,才可通過(guò)它的publishEvent方法來(lái)進(jìn)行事件的發(fā)布。

初始化ApplicationArguments

監(jiān)聽(tīng)器啟動(dòng)之后,緊接著便是執(zhí)行ApplicationArguments對(duì)象的初始化,ApplicationArguments是用于提供訪問(wèn)運(yùn)行SpringApplication時(shí)的參數(shù)。

ApplicationArguments的初始化過(guò)程非常簡(jiǎn)單,只是調(diào)用了它的實(shí)現(xiàn)類DefaultApplicationArguments并傳入main方法中的args參數(shù)。

在DefaultApplicationArguments中將參數(shù)args封裝為Source對(duì)象,Source對(duì)象是基于Spring框架的SimpleCommandLinePropertySource來(lái)實(shí)現(xiàn)的。

初始化ConfigurableEnvironment

完成ApplicationArguments參數(shù)的準(zhǔn)備之后,便開(kāi)始通過(guò)prepareEnvironment方法對(duì)ConfigurableEnvironment對(duì)象進(jìn)行初始化操作。

ConfigurableEnvironment接口繼承自Environment接口和ConfigurablePropertyResolver,最終都繼承自接口PropertyResolverConfigurableEnvironment接口的主要作用是提供當(dāng)前運(yùn)行環(huán)境的公開(kāi)接口,比如配置文件profiles各類系統(tǒng)屬性和變量的設(shè)置、添加、讀取、合并等功能。

通過(guò)ConfigurableEnvironment接口中方法定義,可以更清楚地了解它的功能,代碼如下:


public interface ConfigurableEnvironment extends Environment, ConfigurablePropertyResolver {void setActiveProfiles(String... var1);void addActiveProfile(String var1);void setDefaultProfiles(String... var1);MutablePropertySources getPropertySources();Map<String, Object> getSystemProperties();Map<String, Object> getSystemEnvironment();void merge(ConfigurableEnvironment var1);
}

通過(guò)接口提供的方法,我們可以看出ConfigurableEnvironment就是圍繞著這個(gè)“環(huán)境”來(lái)提供相應(yīng)的功能,這也是為什么我們也將它稱作“環(huán)境”。

了解了ConfigurableEnvironment的功能及方法,我們回歸到SpringApplication的流程看相關(guān)源代碼。run方法中調(diào)用prepareEnvironment方法相關(guān)代碼如下:


private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {ConfigurableEnvironment environment = this.getOrCreateEnvironment();this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());listeners.environmentPrepared((ConfigurableEnvironment)environment);this.bindToSpringApplication((ConfigurableEnvironment)environment);if (!this.isCustomEnvironment) {environment = (new EnvironmentConverter(this.getClassLoader())).convertEnvironmentIfNecessary((ConfigurableEnvironment)environment, this.deduceEnvironmentClass());}ConfigurationPropertySources.attach((Environment)environment);return (ConfigurableEnvironment)environment;
}

通過(guò)以上代碼可知,prepareEnvironment進(jìn)行了以下的操作:

  • 獲取或創(chuàng)建環(huán)境。
  • 配置環(huán)境。
  • ConfigurationPropertySources附加到指定環(huán)境:將ConfigurationPropertySources附加到指定環(huán)境中的第一位,并動(dòng)態(tài)跟蹤環(huán)境的添加或刪除(當(dāng)前版本新增了該行代碼,與最后一步操作相同)。
  • 設(shè)置listener監(jiān)聽(tīng)事件:前面章節(jié)已經(jīng)講過(guò),此處主要針對(duì)準(zhǔn)備環(huán)境的監(jiān)聽(tīng)。
  • 綁定環(huán)境到SpringApplication:將環(huán)境綁定到name為“spring.main”的目標(biāo)上。
  • 轉(zhuǎn)換環(huán)境:判斷是否是定制的環(huán)境,如果不是定制的,則將環(huán)境轉(zhuǎn)換為StandardEnvironment。此時(shí)判斷條件isCustomEnvironment默認(rèn)為false,在后面的操作中會(huì)將其設(shè)置為true,如果為true則不再會(huì)進(jìn)行此轉(zhuǎn)換操作。
  • ConfigurationPropertySources附加到指定環(huán)境:將ConfigurationPropertySources附加到指定環(huán)境中的第一位,并動(dòng)態(tài)跟蹤環(huán)境的添加或刪除操作。

獲取或創(chuàng)建環(huán)境

SpringApplication類中通過(guò)getOrCreateEnvironment方法來(lái)獲取或創(chuàng)建環(huán)境。在該方法中首先判斷環(huán)境是否為null,如果不為null則直接返回;如果為null,則根據(jù)前面推斷出來(lái)的WebApplicationType類型來(lái)創(chuàng)建指定的環(huán)境。

配置環(huán)境

在獲得環(huán)境變量對(duì)象之后,開(kāi)始對(duì)環(huán)境變量和參數(shù)進(jìn)行相應(yīng)的設(shè)置,主要包括轉(zhuǎn)換服務(wù)的設(shè)置、PropertySources的設(shè)置和activeProfiles的設(shè)置。

打印Banner

完成環(huán)境的基本處理之后,下面就是控制臺(tái)Banner的打印了。SpringBoot的Banner打印是一個(gè)比較酷炫的功能,但又顯得有些華而不實(shí),特別是打印圖片時(shí)啟動(dòng)速度會(huì)變慢。

private Banner printBanner(ConfigurableEnvironment environment) {if (this.bannerMode == Mode.OFF) {return null;} else {ResourceLoader resourceLoader = this.resourceLoader != null ? this.resourceLoader : new DefaultResourceLoader(this.getClassLoader());SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter((ResourceLoader)resourceLoader, this.banner);return this.bannerMode == Mode.LOG ? bannerPrinter.print(environment, this.mainApplicationClass, logger) : bannerPrinter.print(environment, this.mainApplicationClass, System.out);}
}

上面的代碼中展示了Banner的開(kāi)啟及打印位置的設(shè)置。程序通過(guò)Banner.Mode枚舉值來(lái)判斷是否開(kāi)啟Banner打印,此項(xiàng)參數(shù)可以在SpringBoot入口nmain方法中通過(guò)setBannerMode方法來(lái)設(shè)置,也可以通過(guò)application.properties中的spring.main.banner-mode進(jìn)行設(shè)置。

SpringApplicationBannerPrinter類承載了Banner初始化及打印的核心功能,比如默認(rèn)如何獲取Banner信息、如何根據(jù)約定優(yōu)于配置來(lái)默認(rèn)獲得Banner的內(nèi)容、Banner支持的文件格式等。

而具體打印的信息是由Banner接口的實(shí)現(xiàn)類來(lái)完成的,比如默認(rèn)情況下使用SpringBootBanner來(lái)打印SpringBoot的版本信息及簡(jiǎn)單的圖形。當(dāng)然還有通過(guò)資源文件打印的ResourceBanner,通過(guò)圖片打印的ImageBanner等方法。

Spring應(yīng)用上下文的創(chuàng)建

SpringBoot創(chuàng)建Spring的應(yīng)用上下文時(shí),如果未指定要?jiǎng)?chuàng)建的類,則會(huì)根據(jù)之前推斷出的類型來(lái)進(jìn)行默認(rèn)上下文類的創(chuàng)建。

在SpringBoot中通過(guò)SpringApplication類中的createApplicationContext來(lái)進(jìn)行應(yīng)用上下文的創(chuàng)建,代碼如下:


protected ConfigurableApplicationContext createApplicationContext() {//  獲取容器的類變量Class<?> contextClass = this.applicationContextClass;//  如果為null,則根據(jù)Web應(yīng)用類型按照默認(rèn)類進(jìn)行創(chuàng)建if (contextClass == null) {try {switch(this.webApplicationType) {case SERVLET:contextClass = Class.forName("org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext");break;case REACTIVE:contextClass = Class.forName("org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext");break;default:contextClass = Class.forName("org.springframework.context.annotation.AnnotationConfigApplicationContext");}} catch (ClassNotFoundException var3) {throw new IllegalStateException("Unable create a default ApplicationContext, please specify an ApplicationContextClass", var3);}}return (ConfigurableApplicationContext)BeanUtils.instantiateClass(contextClass);
}

Spring應(yīng)用上下文的準(zhǔn)備

我們?cè)谏弦还?jié)完成了應(yīng)用上下文的創(chuàng)建工作,SpringApplication繼續(xù)通過(guò)prepareContext方法來(lái)進(jìn)行應(yīng)用上下文的準(zhǔn)備工作。


private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {// 設(shè)置應(yīng)用上下文環(huán)境context.setEnvironment(environment);// 設(shè)置應(yīng)用上下文后置處理this.postProcessApplicationContext(context);// 初始化contextthis.applyInitializers(context);// 通知監(jiān)聽(tīng)器上下文準(zhǔn)備階段listeners.contextPrepared(context);// 打印 profileif (this.logStartupInfo) {this.logStartupInfo(context.getParent() == null);this.logStartupProfileInfo(context);}//  獲取 ConfigurableListableBeanFactory ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();beanFactory.registerSingleton("springApplicationArguments", applicationArguments);if (printedBanner != null) {beanFactory.registerSingleton("springBootBanner", printedBanner);}if (beanFactory instanceof DefaultListableBeanFactory) {((DefaultListableBeanFactory)beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);}//  獲取全部配置源Set<Object> sources = this.getAllSources();Assert.notEmpty(sources, "Sources must not be empty");//  將獲取到的配置源加載到context中this.load(context, sources.toArray(new Object[0]));//  通知監(jiān)聽(tīng)器 context 加載完成listeners.contextLoaded(context);
}

Spring應(yīng)用上下文的刷新

Spring應(yīng)用上下文的刷新,是通過(guò)調(diào)用SpringApplication中的refreshContext方法來(lái)完成的。SpringApplication中refreshContext方法相關(guān)代碼如下:


private void refreshContext(ConfigurableApplicationContext context) {this.refresh(context);if (this.registerShutdownHook) {try {context.registerShutdownHook();} catch (AccessControlException var3) {}}}protected void refresh(ApplicationContext applicationContext) {Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);((AbstractApplicationContext)applicationContext).refresh();
}

其中refresh方法調(diào)用的是AbstractApplicationContext中的refresh方法,該類屬于spring-context包。AbstractApplicationContext的refresh方法更多的是Spring相關(guān)的內(nèi)容。


public void refresh() throws BeansException, IllegalStateException {synchronized(this.startupShutdownMonitor) {this.prepareRefresh();ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();this.prepareBeanFactory(beanFactory);try {this.postProcessBeanFactory(beanFactory);this.invokeBeanFactoryPostProcessors(beanFactory);this.registerBeanPostProcessors(beanFactory);this.initMessageSource();this.initApplicationEventMulticaster();this.onRefresh();this.registerListeners();this.finishBeanFactoryInitialization(beanFactory);this.finishRefresh();} catch (BeansException var9) {if (this.logger.isWarnEnabled()) {this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);}this.destroyBeans();this.cancelRefresh(var9);throw var9;} finally {this.resetCommonCaches();}}
}

在上面的代碼中,調(diào)用finishRefresh方法初始化容器的生命周期處理器并發(fā)布容器的生命周期事件之后,Spring應(yīng)用上下文正式開(kāi)啟,SpringBoot核心特性也隨之啟動(dòng)。完成refreshContext方法操作之后,調(diào)用afterRefresh方法。

完成以上操作之后,調(diào)用SpringApplicationRunListeners的started方法,通知監(jiān)聽(tīng)器容器啟動(dòng)完成,并調(diào)用ApplicationRunner和CommandLineRunner的運(yùn)行方法。

調(diào)用ApplicationRunner和CommandLineRunner

ApplicationRunner和CommandLineRunner是通過(guò) SpringApplication類的callRunners方法來(lái)完成的,具體代碼如下:


private void callRunners(ApplicationContext context, ApplicationArguments args) {List<Object> runners = new ArrayList();runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());AnnotationAwareOrderComparator.sort(runners);Iterator var4 = (new LinkedHashSet(runners)).iterator();while(var4.hasNext()) {Object runner = var4.next();if (runner instanceof ApplicationRunner) {this.callRunner((ApplicationRunner)runner, args);}if (runner instanceof CommandLineRunner) {this.callRunner((CommandLineRunner)runner, args);}}}

以上代碼,首先從context中獲得類型為ApplicationRunner和CommandLineRunner的Bean,將它們放入List列表中并進(jìn)行排序。然后再遍歷調(diào)用其run方法,并將ApplicationArguments參數(shù)傳入。

SpringBoot提供這兩個(gè)接口的目的,是為了我們?cè)陂_(kāi)發(fā)的過(guò)程中,通過(guò)它們來(lái)實(shí)現(xiàn)在容器啟動(dòng)時(shí)執(zhí)行一些操作,如果有多個(gè)實(shí)現(xiàn)類,可通過(guò)@Order注解或?qū)崿F(xiàn)Ordered接口來(lái)控制執(zhí)行順序。

這兩個(gè)接口都提供了一個(gè)run方法,但不同之處在于:ApplicationRunner中run方法的參數(shù)為ApplicationArguments,而CommandLineRunner接口中run方法的參數(shù)為String數(shù)組。

以上方法執(zhí)行完成后,會(huì)通過(guò)SpringApplicationRunListeners的running方法通知監(jiān)聽(tīng)器:容器此刻已處于運(yùn)行狀態(tài)。至此,SpringApplication的run方法執(zhí)行完畢。

http://m.aloenet.com.cn/news/43728.html

相關(guān)文章:

  • 99到家網(wǎng)站怎么做客戶關(guān)系管理
  • 娛樂(lè)網(wǎng)站建設(shè)公司營(yíng)銷軟件有哪些
  • 怎么搭建自己的博客網(wǎng)站百度網(wǎng)頁(yè)版入口鏈接
  • 有名網(wǎng)站建設(shè)公司百度網(wǎng)盤(pán)pc端網(wǎng)頁(yè)版
  • 網(wǎng)站建設(shè)測(cè)試流程圖友情鏈接如何添加
  • 怎么增加網(wǎng)站的外鏈學(xué)校網(wǎng)站建設(shè)
  • 網(wǎng)站設(shè)計(jì)任務(wù)書(shū)范文站長(zhǎng)工具seo綜合查詢?cè)L問(wèn)
  • 精通網(wǎng)站建設(shè) 全能建站密碼pdf理發(fā)美發(fā)培訓(xùn)學(xué)校
  • 公司網(wǎng)站制作推廣公司
  • 電子商務(wù)網(wǎng)站有哪幾種搜索引擎營(yíng)銷的常見(jiàn)方式
  • 網(wǎng)站代理游戲合川網(wǎng)站建設(shè)
  • 蘇州專業(yè)高端網(wǎng)站建設(shè)公司專業(yè)制作網(wǎng)站的公司哪家好
  • 泰州網(wǎng)站建設(shè)服務(wù)熱線全網(wǎng)推廣軟件
  • 免費(fèi)推廣網(wǎng)站2023mmm網(wǎng)絡(luò)營(yíng)銷項(xiàng)目
  • 桐鄉(xiāng)住房和城鄉(xiāng)規(guī)劃建設(shè)局網(wǎng)站如何做網(wǎng)絡(luò)銷售產(chǎn)品
  • 上海網(wǎng)站設(shè)計(jì)工具網(wǎng)絡(luò)推廣運(yùn)營(yíng)團(tuán)隊(duì)
  • 建設(shè)廳特種作業(yè)證件查詢官網(wǎng)網(wǎng)站優(yōu)化推廣公司
  • 重慶品牌網(wǎng)站建設(shè)優(yōu)化網(wǎng)站排名方法
  • 網(wǎng)站設(shè)計(jì)導(dǎo)航欄高度佛山市人民政府門(mén)戶網(wǎng)站
  • 網(wǎng)站建設(shè)詢價(jià)文件無(wú)錫營(yíng)銷型網(wǎng)站制作
  • 海爾集團(tuán)電商網(wǎng)站建設(shè)百度網(wǎng)頁(yè)版進(jìn)入
  • 怎樣在國(guó)外網(wǎng)站做推廣搜索關(guān)鍵詞排名一般按照什么收費(fèi)
  • 做網(wǎng)站做軟件怎么賺錢(qián)嗎搜索量最大的關(guān)鍵詞
  • 咸秧草做哪些網(wǎng)站優(yōu)化大師免安裝版
  • 鄭州做網(wǎng)站推廣外包產(chǎn)品推廣方式
  • 鞍山網(wǎng)站制作公司優(yōu)化綠松石什么意思
  • 泉州建設(shè)網(wǎng)站開(kāi)發(fā)快速排名優(yōu)化
  • 湖南做網(wǎng)站磐石網(wǎng)絡(luò)案例cba最新排名
  • 淘寶的網(wǎng)站建設(shè)seo分析報(bào)告怎么寫(xiě)
  • 網(wǎng)站如何提高權(quán)重做百度推廣怎么做才能有電話