免费A级毛片无码专区网站-成人国产精品视频一区二区-啊 日出水了 用力乖乖在线-国产黑色丝袜在线观看下-天天操美女夜夜操美女-日韩网站在线观看中文字幕-AV高清hd片XXX国产-亚洲av中文字字幕乱码综合-搬开女人下面使劲插视频

【Spring boot】啟動過程源碼分析

啟動過程結論

  • 推測web應用類型 。
  • spi的方式獲取BootstrapRegistryInitializer、ApplicationContextInitializer、ApplicationContextInitializer對象 。
  • 通過調用棧推測出main()方法所在的類 。
  • 調用啟動方法:run(String... args) 。后面的步驟在這個方法內部!
  • 觸發(fā)SpringApplicationRunListener的starting() 。
  • 創(chuàng)建Environment對象 。
  • 觸發(fā)SpringApplicationRunListener的environmentPrepared() 。
  • 打印Banner 。
  • 創(chuàng)建Spring容器對象(ApplicationContext) 。
  • 利用ApplicationContextInitializer初始化Spring容器對象 。
  • 觸發(fā)SpringApplicationRunListener的contextPrepared() 。
  • 調用DefaultBootstrapContext對象的close() 。
  • 將啟動類作為配置類注冊到Spring容器中(load()方法) 。
  • 觸發(fā)SpringApplicationRunListener的contextLoaded() 。
  • 刷新Spring容器 。
  • 觸發(fā)SpringApplicationRunListener的started() 。
  • 調用ApplicationRunner和CommandLineRunner 。
  • 觸發(fā)SpringApplicationRunListener的ready() 。
  • 上述過程拋異常了就觸發(fā)SpringApplicationRunListener的failed() 。
入口位置
  • 第一步構造對象:new SpringApplication(primarySources)
  • 第二步調用SpringApplication.run(String... args)
// 我們自己寫的main方法@SpringBootApplicationpublic class ZfcqApp {public static void main(String[] args) {SpringApplication.run(ZfcqApp.class, args);}}/** * 他會調用SpringApplication的run方法 * primarySource:我們傳入的類的class * args:我們傳入的參數(shù),一般是啟動的時候-D制定的參數(shù) */public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {return run(new Class<?>[] { primarySource }, args);}/** * 繼續(xù)看內部調用的run方法 */public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {// 倆步,第一步構造對象:new SpringApplication(primarySources)// 第二步調用SpringApplication.run(String... args)// 這里我們可以在main方法中分開倆步去寫,從而可以在中間設置SpringApplication對象的信息return new SpringApplication(primarySources).run(args);}構造SpringApplication源碼分析/** * 調用倆個參數(shù)的構造方法 * primarySources:我們主類的class */public SpringApplication(Class<?>... primarySources) {this(null, primarySources);}/** * 倆個產生的構造方法 */public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {// 賦值到全局,這里第一次傳入的是nullthis.resourceLoader = resourceLoader;// 主類存在的判斷Assert.notNull(primarySources, "PrimarySources must not be null");// 賦值到全局,這里一般傳入的是我們的main方法的類this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));// 推測WEB應用的類型(NONE、SERVLET、REACTIVE)this.webApplicationType = WebApplicationType.deduceFromClasspath();// 從spring.factories中獲取BootstrapRegistryInitializer對象的值this.bootstrapRegistryInitializers = new ArrayList<>(getSpringFactoriesInstances(BootstrapRegistryInitializer.class));// 從spring.factories中獲取ApplicationContextInitializer對象的值setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));// 從spring.factories中獲取ApplicationListener對象的值 。非常重要的有一個是EnvironmentPostProcessorApplicationListenersetListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));// 推測出main方法所在的類!SpringApplication.run(ZfcqApp.class, args);可以傳任意的類!this.mainApplicationClass = deduceMainApplicationClass();}推測web應用類型
  • REACTIVE:web應用 。
  • NONE:無Servlet,不是web應用 。
  • SERVLET:除去上面?zhèn)z種的其他應用 。
static WebApplicationType deduceFromClasspath() {// 如果項目依賴中存在org.springframework.web.reactive.DispatcherHandler,并且不存在org.springframework.web.servlet.DispatcherServlet,那么應用類型為WebApplicationType.REACTIVEif (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null) && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {return WebApplicationType.REACTIVE;}// 如果項目依賴中不存在org.springframework.web.reactive.Dispatche#rHandler,也不存在org.springframework.web.servlet.DispatcherServlet,那么應用類型為WebApplicationType.NONEfor (String className : SERVLET_INDICATOR_CLASSES) {if (!ClassUtils.isPresent(className, null)) {return WebApplicationType.NONE;}}// 否則,應用類型為WebApplicationType.SERVLETreturn WebApplicationType.SERVLET;}

經驗總結擴展閱讀