国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

香港云服务器
服務器之家 - 編程語言 - Java教程 - SpringBoot啟動過程的實現

SpringBoot啟動過程的實現

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

這篇文章主要介紹了SpringBoot啟動過程的實現,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

SpringBoot啟動過程分析,首先打開SpringBoot的啟用入口Main類:

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

可以看到main方法里面只有一行核心啟用類:SpringApplication.run(ApplicationMain.class, args);這個是關鍵,在改行打上斷點,debug模式啟動該main類。點擊下一步進入SpringApplication的源碼對應的run方法:

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

初始化SpringApplication

SpringApplication實例化之前會調用構造方法進行初始化:

?
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構造方法的核心是:this.initialize(sources);初始化方法,SpringApplication通過調用該方法來初始化。

?
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方法是用來判斷當前應用的環境,該方法通過獲取這兩個類來判斷當前環境是否是web環境,如果能獲得這兩個類說明是web環境,否則不是。

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

2.getSpringFactoriesInstances方法主要用來從spring.factories文件中找出key為ApplicationContextInitializer的類并實例化,然后調用setInitializers方法設置到SpringApplication的initializers屬性中。這個過程就是找出所有的應用程序初始化器。

?
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的類
   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);
  }
 }

當前的初始化器有如下幾個:

SpringBoot啟動過程的實現

3.同理調用getSpringFactoriesInstances從spring.factories文件中找出key為ApplicationListener的類并實例化,然后調用setListeners方法設置到SpringApplication的listeners屬性中。這個過程就是找出所有的應用程序事件監聽器。
當前的事件監聽器有如下幾個:

SpringBoot啟動過程的實現

4.調用deduceMainApplicationClass方法找出main類,就是這里的ApplicationMain類。

運行SpringApplication

初始化SpringApplication完成之后,調用run方法運行:

?
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) {
  //計時器,統計任務的執行時間
  StopWatch stopWatch = new StopWatch();
  //開始執行
  stopWatch.start();
  ConfigurableApplicationContext context = null;
  FailureAnalyzers analyzers = null;
  this.configureHeadlessProperty();
  // 獲取SpringApplicationRunListeners啟動事件監聽器,這里只有一個EventPublishingRunListener
  SpringApplicationRunListeners listeners = this.getRunListeners(args);
  // 封裝成SpringApplicationEvent事件然后廣播出去給SpringApplication中的listeners所監聽
  listeners.starting();
 
  try {
   // 構造一個應用程序參數持有類
   ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
   // 準備并配置環境
   ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
    // 打印banner圖形
   Banner printedBanner = this.printBanner(environment);
   // 創建Spring容器
   context = this.createApplicationContext();
   new FailureAnalyzers(context);
   // 配置Spring容器
   this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
   // 容器上下文刷新
   this.refreshContext(context);
   // 容器創建完成之后調用afterRefresh方法
   this.afterRefresh(context, applicationArguments);
   // 調用監聽器,廣播Spring啟動結束的事件
   listeners.finished(context, (Throwable)null);
   // 停止計時器
   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.獲取啟動事件監聽器,可以看看該方法:

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));
 }

同樣的通過調用getSpringFactoriesInstances方法去META-INF/spring.factories文件中拿到SpringApplicationRunListener監聽器,當前的SpringApplicationRunListener事件監聽器只有一個EventPublishingRunListener廣播事件監聽器:

SpringBoot啟動過程的實現

SpringApplicationRunListeners內部持有SpringApplicationRunListener集合和1個Log日志類。用于SpringApplicationRunListener監聽器的批量執行。

SpringApplicationRunListener用于監聽SpringApplication的run方法的執行,它定義了5個步驟:

1.starting:run方法執行的時候立馬執行,對應的事件類型是ApplicationStartedEvent
2.environmentPrepared:ApplicationContext創建之前并且環境信息準備好的時候調用,對應的事件類型是ApplicationEnvironmentPreparedEvent
3.contextPrepared:ApplicationContext創建好并且在source加載之前調用一次,沒有具體的對應事件
4.contextLoaded:ApplicationContext創建并加載之后并在refresh之前調用,對應的事件類型是ApplicationPreparedEvent
5.finished:run方法結束之前調用,對應事件的類型是ApplicationReadyEvent或ApplicationFailedEvent

SpringApplicationRunListener目前只有一個實現類EventPublishingRunListener,詳見獲取SpringApplicationRunListeners。它把監聽的過程封裝成了SpringApplicationEvent事件并讓內部屬性ApplicationEventMulticaster接口的實現類SimpleApplicationEventMulticaster廣播出去,廣播出去的事件對象會被SpringApplication中的listeners屬性進行處理。

所以說SpringApplicationRunListener和ApplicationListener之間的關系是通過ApplicationEventMulticaster廣播出去的SpringApplicationEvent所聯系起來的

2.啟動事件監聽器

通過listeners.starting()可以啟動事件監聽器SpringApplicationRunListener ,SpringApplicationRunListener 是一個啟動事件監聽器接口:

?
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 接口的具體實現就是EventPublishingRunListener類,我們主要來看一下它的startting方法,該方法會封裝成SpringApplicationEvent事件然后廣播出去給SpringApplication中的listeners所監聽。

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

配置并準備環境

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

判斷環境,如果是web程序,創建StandardServletEnvironment;否則,創建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());
  }
 }

創建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應用,
   // 如果是則創建AnnotationConfigEmbeddedWebApplicationContext,否則創建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) {
 // 設置Spring容器上下文的環境信息
 context.setEnvironment(environment);
 // Spring容器創建之后做一些額外的事
 postProcessApplicationContext(context);
 // SpringApplication的初始化器開始工作
 applyInitializers(context);
 // 遍歷調用SpringApplicationRunListener的contextPrepared方法。目前只是將這個事件廣播器注冊到Spring容器中
 listeners.contextPrepared(context);
 if (this.logStartupInfo) {
  logStartupInfo(context.getParent() == null);
  logStartupProfileInfo(context);
 }
 
 // 把應用程序參數持有類注冊到Spring容器中,并且是一個單例
 context.getBeanFactory().registerSingleton("springApplicationArguments",
   applicationArguments);
 if (printedBanner != null) {
  context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
 }
 
 // 加載sources,sources是main方法所在的類
 Set<Object> sources = getSources();
 Assert.notEmpty(sources, "Sources must not be empty");
 // 將sources加載到應用上下文中。最終調用的是AnnotatedBeanDefinitionReader.registerBean方法
 load(context, sources.toArray(new Object[sources.size()]));
 // 廣播出ApplicationPreparedEvent事件給相應的監聽器執行
 // 執行EventPublishingRunListener.contextLoaded方法
 listeners.contextLoaded(context);
}

Spring容器創建之后回調方法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設置了實例命名生成器,則注冊到Spring容器中
 if (this.beanNameGenerator != null) {
  context.getBeanFactory().registerSingleton(
    AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
    this.beanNameGenerator);
 }
 // 如果SpringApplication設置了資源加載器,設置到Spring容器中
 if (this.resourceLoader != null) {
  if (context instanceof GenericApplicationContext) {
   ((GenericApplicationContext) context)
     .setResourceLoader(this.resourceLoader);
  }
  if (context instanceof DefaultResourceLoader) {
   ((DefaultResourceLoader) context)
     .setClassLoader(this.resourceLoader.getClassLoader());
  }
 }
}

初始化器開始工作

?
1
2
3
4
5
6
7
8
9
protected void applyInitializers(ConfigurableApplicationContext context) {
 // 遍歷每個初始化器,調用對應的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容器創建完成之后會調用afterRefresh方法

ApplicationRunner、CommandLineRunner類都是在在afterRefresh方法中調用的,也就是說在Spring容器創建之后執行的。

?
1
2
3
4
5
6
7
8
9
protected void applyInitializers(ConfigurableApplicationContext context) {
 // 遍歷每個初始化器,調用對應的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啟動過程.html

到此這篇關于SpringBoot啟動過程的實現的文章就介紹到這了,更多相關SpringBoot啟動過程內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!

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

延伸 · 閱讀

精彩推薦
337
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25 Weibo Article 26 Weibo Article 27 Weibo Article 28 Weibo Article 29 Weibo Article 30 Weibo Article 31 Weibo Article 32 Weibo Article 33 Weibo Article 34 Weibo Article 35 Weibo Article 36 Weibo Article 37 Weibo Article 38 Weibo Article 39 Weibo Article 40
主站蜘蛛池模板: 亚洲精品www久久久久久广东 | 日韩成人一区 | 久久99精品久久久久婷婷暖91 | 日本在线视频观看 | 久草网站 | 欧美人成在线观看 | 国产精品久久久久av | 亚洲成人毛片 | 免费看一区二区三区 | 色吊丝在线永久观看最新版本 | 欧美国产日韩一区 | 午夜影视 | 日韩精品在线视频 | 日韩城人网站 | 日韩中文字幕在线播放 | 亚洲午夜精品 | 亚洲电影在线 | 久久久91精品国产一区二区三区 | 免费午夜视频 | 蜜桃av一区 | 快色视频在线观看 | 不用播放器的免费av | 欧美区国产 | 午夜精品久久久久久久久 | av片免费看| 色欧美日韩 | 日本免费高清视频 | 欧美精品久久久久 | 欧美精品网| 综合久久亚洲 | 国内精品视频 | 国产精品影视在线观看 | 久久亚洲欧美日韩精品专区 | 久草视频网 | 福利久久 | 日本成人高清视频 | 欧美一区第一页 | 久久久毛片 | 亚洲性网 | 精品国产久 | www.亚洲成人 |