激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務(wù)器之家:專(zhuān)注于服務(wù)器技術(shù)及軟件下載分享
分類(lèi)導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語(yǔ)言|JavaScript|易語(yǔ)言|vb.net|

服務(wù)器之家 - 編程語(yǔ)言 - Java教程 - SpringBoot啟動(dòng)過(guò)程的實(shí)現(xiàn)

SpringBoot啟動(dòng)過(guò)程的實(shí)現(xiàn)

2020-09-15 13:57chengbinbbs Java教程

這篇文章主要介紹了SpringBoot啟動(dòng)過(guò)程的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

SpringBoot啟動(dòng)過(guò)程分析,首先打開(kāi)SpringBoot的啟用入口Main類(lèi):

?
1
2
3
4
5
6
@SpringBootApplication
public class ApplicationMain{
 public static void main(String[] args) {
  SpringApplication.run(ApplicationMain.class, args);
 }
}

可以看到main方法里面只有一行核心啟用類(lèi):SpringApplication.run(ApplicationMain.class, args);這個(gè)是關(guān)鍵,在改行打上斷點(diǎn),debug模式啟動(dòng)該main類(lèi)。點(diǎn)擊下一步進(jìn)入SpringApplication的源碼對(duì)應(yīng)的run方法:

?
1
2
3
public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
  return (new SpringApplication(sources)).run(args);
 }

初始化SpringApplication

SpringApplication實(shí)例化之前會(huì)調(diào)用構(gòu)造方法進(jìn)行初始化:

?
1
2
3
4
5
6
7
8
9
public SpringApplication(Object... sources) {
  this.bannerMode = Mode.CONSOLE;
  this.logStartupInfo = true;
  this.addCommandLineProperties = true;
  this.headless = true;
  this.registerShutdownHook = true;
  this.additionalProfiles = new HashSet();
  this.initialize(sources);
 }

而SpringApplication構(gòu)造方法的核心是:this.initialize(sources);初始化方法,SpringApplication通過(guò)調(diào)用該方法來(lái)初始化。

?
1
2
3
4
5
6
7
8
9
10
private void initialize(Object[] sources) {
 if (sources != null && sources.length > 0) {
  this.sources.addAll(Arrays.asList(sources));
 }
 this.webEnvironment = deduceWebEnvironment();
 setInitializers((Collection) getSpringFactoriesInstances(
   ApplicationContextInitializer.class));
 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
 this.mainApplicationClass = deduceMainApplicationClass();
}

1.deduceWebEnvironment方法是用來(lái)判斷當(dāng)前應(yīng)用的環(huán)境,該方法通過(guò)獲取這兩個(gè)類(lèi)來(lái)判斷當(dāng)前環(huán)境是否是web環(huán)境,如果能獲得這兩個(gè)類(lèi)說(shuō)明是web環(huán)境,否則不是。

?
1
2
javax.servlet.Servlet
org.springframework.web.context.ConfigurableWebApplicationContext

2.getSpringFactoriesInstances方法主要用來(lái)從spring.factories文件中找出key為ApplicationContextInitializer的類(lèi)并實(shí)例化,然后調(diào)用setInitializers方法設(shè)置到SpringApplication的initializers屬性中。這個(gè)過(guò)程就是找出所有的應(yīng)用程序初始化器。

?
1
2
3
4
5
6
7
private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
  ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
  Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
  List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
  AnnotationAwareOrderComparator.sort(instances);
  return instances;
 }
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
  String factoryClassName = factoryClass.getName();
 
  try {
   //從spring.factories文件中找出key為ApplicationContextInitializer的類(lèi)
   Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
   ArrayList result = new ArrayList();
 
   while(urls.hasMoreElements()) {
    URL url = (URL)urls.nextElement();
    Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
    String factoryClassNames = properties.getProperty(factoryClassName);
    result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
   }
 
   return result;
  } catch (IOException var8) {
   throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() + "] factories from location [" + "META-INF/spring.factories" + "]", var8);
  }
 }

當(dāng)前的初始化器有如下幾個(gè):

SpringBoot啟動(dòng)過(guò)程的實(shí)現(xiàn)

3.同理調(diào)用getSpringFactoriesInstances從spring.factories文件中找出key為ApplicationListener的類(lèi)并實(shí)例化,然后調(diào)用setListeners方法設(shè)置到SpringApplication的listeners屬性中。這個(gè)過(guò)程就是找出所有的應(yīng)用程序事件監(jiān)聽(tīng)器。
當(dāng)前的事件監(jiān)聽(tīng)器有如下幾個(gè):

SpringBoot啟動(dòng)過(guò)程的實(shí)現(xiàn)

4.調(diào)用deduceMainApplicationClass方法找出main類(lèi),就是這里的ApplicationMain類(lèi)。

運(yùn)行SpringApplication

初始化SpringApplication完成之后,調(diào)用run方法運(yùn)行:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public ConfigurableApplicationContext run(String... args) {
  //計(jì)時(shí)器,統(tǒng)計(jì)任務(wù)的執(zhí)行時(shí)間
  StopWatch stopWatch = new StopWatch();
  //開(kāi)始執(zhí)行
  stopWatch.start();
  ConfigurableApplicationContext context = null;
  FailureAnalyzers analyzers = null;
  this.configureHeadlessProperty();
  // 獲取SpringApplicationRunListeners啟動(dòng)事件監(jiān)聽(tīng)器,這里只有一個(gè)EventPublishingRunListener
  SpringApplicationRunListeners listeners = this.getRunListeners(args);
  // 封裝成SpringApplicationEvent事件然后廣播出去給SpringApplication中的listeners所監(jiān)聽(tīng)
  listeners.starting();
 
  try {
   // 構(gòu)造一個(gè)應(yīng)用程序參數(shù)持有類(lèi)
   ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
   // 準(zhǔn)備并配置環(huán)境
   ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
    // 打印banner圖形
   Banner printedBanner = this.printBanner(environment);
   // 創(chuàng)建Spring容器
   context = this.createApplicationContext();
   new FailureAnalyzers(context);
   // 配置Spring容器
   this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
   // 容器上下文刷新
   this.refreshContext(context);
   // 容器創(chuàng)建完成之后調(diào)用afterRefresh方法
   this.afterRefresh(context, applicationArguments);
   // 調(diào)用監(jiān)聽(tīng)器,廣播Spring啟動(dòng)結(jié)束的事件
   listeners.finished(context, (Throwable)null);
   // 停止計(jì)時(shí)器
   stopWatch.stop();
   if (this.logStartupInfo) {
    (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
   }
 
   return context;
  } catch (Throwable var9) {
   this.handleRunFailure(context, listeners, (FailureAnalyzers)analyzers, var9);
   throw new IllegalStateException(var9);
  }
 }

SpringApplicationRunListeners

1.獲取啟動(dòng)事件監(jiān)聽(tīng)器,可以看看該方法:

SpringApplicationRunListeners listeners = this.getRunListeners(args);

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

同樣的通過(guò)調(diào)用getSpringFactoriesInstances方法去META-INF/spring.factories文件中拿到SpringApplicationRunListener監(jiān)聽(tīng)器,當(dāng)前的SpringApplicationRunListener事件監(jiān)聽(tīng)器只有一個(gè)EventPublishingRunListener廣播事件監(jiān)聽(tīng)器:

SpringBoot啟動(dòng)過(guò)程的實(shí)現(xiàn)

SpringApplicationRunListeners內(nèi)部持有SpringApplicationRunListener集合和1個(gè)Log日志類(lèi)。用于SpringApplicationRunListener監(jiān)聽(tīng)器的批量執(zhí)行。

SpringApplicationRunListener用于監(jiān)聽(tīng)SpringApplication的run方法的執(zhí)行,它定義了5個(gè)步驟:

1.starting:run方法執(zhí)行的時(shí)候立馬執(zhí)行,對(duì)應(yīng)的事件類(lèi)型是ApplicationStartedEvent
2.environmentPrepared:ApplicationContext創(chuàng)建之前并且環(huán)境信息準(zhǔn)備好的時(shí)候調(diào)用,對(duì)應(yīng)的事件類(lèi)型是ApplicationEnvironmentPreparedEvent
3.contextPrepared:ApplicationContext創(chuàng)建好并且在source加載之前調(diào)用一次,沒(méi)有具體的對(duì)應(yīng)事件
4.contextLoaded:ApplicationContext創(chuàng)建并加載之后并在refresh之前調(diào)用,對(duì)應(yīng)的事件類(lèi)型是ApplicationPreparedEvent
5.finished:run方法結(jié)束之前調(diào)用,對(duì)應(yīng)事件的類(lèi)型是ApplicationReadyEvent或ApplicationFailedEvent

SpringApplicationRunListener目前只有一個(gè)實(shí)現(xiàn)類(lèi)EventPublishingRunListener,詳見(jiàn)獲取SpringApplicationRunListeners。它把監(jiān)聽(tīng)的過(guò)程封裝成了SpringApplicationEvent事件并讓內(nèi)部屬性ApplicationEventMulticaster接口的實(shí)現(xiàn)類(lèi)SimpleApplicationEventMulticaster廣播出去,廣播出去的事件對(duì)象會(huì)被SpringApplication中的listeners屬性進(jìn)行處理。

所以說(shuō)SpringApplicationRunListener和ApplicationListener之間的關(guān)系是通過(guò)ApplicationEventMulticaster廣播出去的SpringApplicationEvent所聯(lián)系起來(lái)的

2.啟動(dòng)事件監(jiān)聽(tīng)器

通過(guò)listeners.starting()可以啟動(dòng)事件監(jiān)聽(tīng)器SpringApplicationRunListener ,SpringApplicationRunListener 是一個(gè)啟動(dòng)事件監(jiān)聽(tīng)器接口:

?
1
2
3
4
5
6
7
8
9
10
11
public interface SpringApplicationRunListener {
 void starting();
 
 void environmentPrepared(ConfigurableEnvironment var1);
 
 void contextPrepared(ConfigurableApplicationContext var1);
 
 void contextLoaded(ConfigurableApplicationContext var1);
 
 void finished(ConfigurableApplicationContext var1, Throwable var2);
}

SpringApplicationRunListener 接口的具體實(shí)現(xiàn)就是EventPublishingRunListener類(lèi),我們主要來(lái)看一下它的startting方法,該方法會(huì)封裝成SpringApplicationEvent事件然后廣播出去給SpringApplication中的listeners所監(jiān)聽(tīng)。

?
1
2
3
public void starting() {
  this.initialMulticaster.multicastEvent(new ApplicationStartedEvent(this.application, this.args));
 }

配置并準(zhǔn)備環(huán)境

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private ConfigurableEnvironment prepareEnvironment(
  SpringApplicationRunListeners listeners,
  ApplicationArguments applicationArguments) {
 // 創(chuàng)建應(yīng)用程序的環(huán)境信息。如果是web程序,創(chuàng)建StandardServletEnvironment;否則,創(chuàng)建StandardEnvironment
 ConfigurableEnvironment environment = getOrCreateEnvironment();
 // 配置環(huán)境信息。比如profile,命令行參數(shù)
 configureEnvironment(environment, applicationArguments.getSourceArgs());
 // 廣播出ApplicationEnvironmentPreparedEvent事件給相應(yīng)的監(jiān)聽(tīng)器執(zhí)行
 listeners.environmentPrepared(environment);
 // 環(huán)境信息的校對(duì)
 if (!this.webEnvironment) {
  environment = new EnvironmentConverter(getClassLoader())
    .convertToStandardEnvironmentIfNecessary(environment);
 }
 return environment;
}

判斷環(huán)境,如果是web程序,創(chuàng)建StandardServletEnvironment;否則,創(chuàng)建StandardEnvironment。

?
1
2
3
4
5
6
7
private ConfigurableEnvironment getOrCreateEnvironment() {
  if (this.environment != null) {
   return this.environment;
  } else {
   return (ConfigurableEnvironment)(this.webEnvironment ? new StandardServletEnvironment() : new StandardEnvironment());
  }
 }

創(chuàng)建Spring容器上下文

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
protected ConfigurableApplicationContext createApplicationContext() {
 Class<?> contextClass = this.applicationContextClass;
 if (contextClass == null) {
  try {
   // 判斷是否是web應(yīng)用,
   // 如果是則創(chuàng)建AnnotationConfigEmbeddedWebApplicationContext,否則創(chuàng)建AnnotationConfigApplicationContext
   contextClass = Class.forName(this.webEnvironment
     ? DEFAULT_WEB_CONTEXT_CLASS : DEFAULT_CONTEXT_CLASS);
  }
  catch (ClassNotFoundException ex) {
   throw new IllegalStateException(
     "Unable create a default ApplicationContext, "
       + "please specify an ApplicationContextClass",
     ex);
  }
 }
 return (ConfigurableApplicationContext) BeanUtils.instantiate(contextClass);
}

配置Spring容器上下文

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
private void prepareContext(ConfigurableApplicationContext context,
  ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
  ApplicationArguments applicationArguments, Banner printedBanner) {
 // 設(shè)置Spring容器上下文的環(huán)境信息
 context.setEnvironment(environment);
 // Spring容器創(chuàng)建之后做一些額外的事
 postProcessApplicationContext(context);
 // SpringApplication的初始化器開(kāi)始工作
 applyInitializers(context);
 // 遍歷調(diào)用SpringApplicationRunListener的contextPrepared方法。目前只是將這個(gè)事件廣播器注冊(cè)到Spring容器中
 listeners.contextPrepared(context);
 if (this.logStartupInfo) {
  logStartupInfo(context.getParent() == null);
  logStartupProfileInfo(context);
 }
 
 // 把應(yīng)用程序參數(shù)持有類(lèi)注冊(cè)到Spring容器中,并且是一個(gè)單例
 context.getBeanFactory().registerSingleton("springApplicationArguments",
   applicationArguments);
 if (printedBanner != null) {
  context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
 }
 
 // 加載sources,sources是main方法所在的類(lèi)
 Set<Object> sources = getSources();
 Assert.notEmpty(sources, "Sources must not be empty");
 // 將sources加載到應(yīng)用上下文中。最終調(diào)用的是AnnotatedBeanDefinitionReader.registerBean方法
 load(context, sources.toArray(new Object[sources.size()]));
 // 廣播出ApplicationPreparedEvent事件給相應(yīng)的監(jiān)聽(tīng)器執(zhí)行
 // 執(zhí)行EventPublishingRunListener.contextLoaded方法
 listeners.contextLoaded(context);
}

Spring容器創(chuàng)建之后回調(diào)方法postProcessApplicationContext

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
 // 如果SpringApplication設(shè)置了實(shí)例命名生成器,則注冊(cè)到Spring容器中
 if (this.beanNameGenerator != null) {
  context.getBeanFactory().registerSingleton(
    AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
    this.beanNameGenerator);
 }
 // 如果SpringApplication設(shè)置了資源加載器,設(shè)置到Spring容器中
 if (this.resourceLoader != null) {
  if (context instanceof GenericApplicationContext) {
   ((GenericApplicationContext) context)
     .setResourceLoader(this.resourceLoader);
  }
  if (context instanceof DefaultResourceLoader) {
   ((DefaultResourceLoader) context)
     .setClassLoader(this.resourceLoader.getClassLoader());
  }
 }
}

初始化器開(kāi)始工作

?
1
2
3
4
5
6
7
8
9
protected void applyInitializers(ConfigurableApplicationContext context) {
 // 遍歷每個(gè)初始化器,調(diào)用對(duì)應(yīng)的initialize方法
 for (ApplicationContextInitializer initializer : getInitializers()) {
  Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(
    initializer.getClass(), ApplicationContextInitializer.class);
  Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
  initializer.initialize(context);
 }
}

Spring容器創(chuàng)建完成之后會(huì)調(diào)用afterRefresh方法

ApplicationRunner、CommandLineRunner類(lèi)都是在在afterRefresh方法中調(diào)用的,也就是說(shuō)在Spring容器創(chuàng)建之后執(zhí)行的。

?
1
2
3
4
5
6
7
8
9
protected void applyInitializers(ConfigurableApplicationContext context) {
 // 遍歷每個(gè)初始化器,調(diào)用對(duì)應(yīng)的initialize方法
 for (ApplicationContextInitializer initializer : getInitializers()) {
  Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(
    initializer.getClass(), ApplicationContextInitializer.class);
  Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
  initializer.initialize(context);
 }
}

參考:https://blog.wangqi.love/articles/Spring/SpringBoot啟動(dòng)過(guò)程.html

到此這篇關(guān)于SpringBoot啟動(dòng)過(guò)程的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)SpringBoot啟動(dòng)過(guò)程內(nèi)容請(qǐng)搜索服務(wù)器之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持服務(wù)器之家!

原文鏈接:https://blog.csdn.net/chengbinbbs/article/details/88557162

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 久久91亚洲人成电影网站 | 久久久久久亚洲国产精品 | 欧美在线观看视频一区 | 又黄又爽免费无遮挡在线观看 | 综合网天天射 | 91在线免费观看 | 久久成年网站 | 中文字幕四区 | 国产无遮挡一级毛片 | 欧美一级高清片 | 欧美精品v国产精品v日韩精品 | 成人h视频在线 | 欧美精品久久久久久久久久 | 成人国产精品色哟哟 | 99成人精品视频 | 欧美在线观看视频一区 | 日韩视频一区二区三区四区 | 污在线观看网站 | 亚洲免费高清 | 88xx成人精品视频 | 日韩色视频在线观看 | 毛片免费视频网站 | 亚洲成人精品国产 | 九色激情网 | 亚洲精品久久久久久久久久 | 国产一区二区三区在线观看视频 | 日日草夜夜草 | 国产成人高潮免费观看精品 | 久久人人爽人人爽人人片av免费 | 亚洲一级簧片 | 欧美成人三级大全 | 精品欧美一区二区精品久久 | 蜜桃网站在线观看 | 欧美另类69xxxxx 视频 | 亚洲热线99精品视频 | 亚洲免费毛片基地 | 成人毛片100免费观看 | h视频免费在线观看 | 国产在线精品区 | 亚欧美一区二区 | 在线日韩在线 |