1 public ConfigurableApplicationContext run(String... args) { 2 StopWatch stopWatch = new StopWatch(); //設置計時器 3 stopWatch.start(); //記錄當前時間 4 ConfigurableApplicationContext context = null; 5 configureHeadlessProperty(); //設置java.awt.headless為true或false 6 SpringApplicationRunListeners listeners = getRunListeners(args);//獲取事件發布器(控制所有事件的執行時機) 7 listeners.started(); //事件發布器發布ApplicationStartedEvent事件,所有監聽了該事件的ApplicationListener實現類執行邏輯 8 try { 9 context = doRun(listeners, args); 10 stopWatch.stop(); //計時結束(記錄總共花了多少時間) 11 if (this.logStartupInfo) { 12 new StartupInfoLogger(this.mainApplicationClass) 13 .logStarted(getApplicationLog(), stopWatch); 14 } 15 return context; 16 } 17 catch (Throwable ex) { 18 handleRunFailure(context, listeners, ex); 19 throw new IllegalStateException(ex); 20 } 21 }
1 private ConfigurableApplicationContext doRun(SpringApplicationRunListeners listeners, 2 String... args) { 3 ConfigurableApplicationContext context; 4 // Create and configure the environment 5 ConfigurableEnvironment environment = getOrCreateEnvironment(); //創建Environment 6 configureEnvironment(environment, args); //配置Environment(包括配置要使用的PropertySource和Profile) 7 listeners.environmentPrepared(environment); //事件發布器發布ApplicationEnvironmentPreparedEvent事件,所有監聽了該事件的ApplicationListener執行相應邏輯 8 if (isWebEnvironment(environment) && !this.webEnvironment) { 9 environment = convertToStandardEnvironment(environment); 10 } 11 12 if (this.bannerMode != Banner.Mode.OFF) { 13 printBanner(environment); 14 } 15 16 // Create, load, refresh and run the ApplicationContext 17 context = createApplicationContext(); //創建ApplicationContext容器 18 context.setEnvironment(environment); //設置Environment到容器 19 postProcessApplicationContext(context); 20 applyInitializers(context); //執行所有的ApplicationContextInitializer的initial方法,對創建出來的ApplicationContext容器進行初始化 21 listeners.contextPrepared(context); 22 if (this.logStartupInfo) { 23 logStartupInfo(context.getParent() == null); 24 logStartupProfileInfo(context); 25 } 26 27 // Add boot specific singleton beans 28 ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); 29 context.getBeanFactory().registerSingleton("springApplicationArguments", 30 applicationArguments); 31 32 // Load the sources 33 Set<Object> sources = getSources(); 34 Assert.notEmpty(sources, "Sources must not be empty"); 35 load(context, sources.toArray(new Object[sources.size()])); //將之前通過@EnableAutoConfiguration的所有配置以及其他形式的IOC容器加載到已經准備完畢的ApplicationContext 36 listeners.contextLoaded(context); //事件發布器將所有的ApplicationListener注冊給當前的ApplicationContext,之后發布ApplicationPreparedEvent事件 37 38 // Refresh the context 39 refresh(context); //刷新ApplicationContext 40 if (this.registerShutdownHook) { 41 try { 42 context.registerShutdownHook(); 43 } 44 catch (AccessControlException ex) { 45 // Not allowed in some environments. 46 } 47 } 48 afterRefresh(context, applicationArguments); 49 listeners.finished(context, null); 50 return context; 51 }
步驟總結:
- 設置計時器,記錄當前時間
- 該類是一個非線程的安全的,如果自己使用要考慮多線程的情況.
- 設置java.awt.headless為true或false
- java.awt.headless是J2SE的一種模式用於在缺少顯示屏、鍵盤或者鼠標時的系統配置,很多監控工具如jconsole 需要將該值設置為true
- 獲取事件發布器(用於控制所有事件的執行時機)
- 事件發布器發布ApplicationStartedEvent事件,所有監聽了該事件的ApplicationListener實現類執行邏輯
- 創建並配置Environment(包括配置要使用的PropertySource和Profile)
- PropertySource主要是讀取SpringApplication.setDefaultProperties指定的默認屬性 + 命令行屬性
- 通常,只有命令行屬性,而且該屬性會addFirst,說明優先級是最高的!!!
- Profile主要是讀取application-{level}.properties中的內容
- 需要配置:"spring.active.profiles"
- 關於配置文件的一系列問題 見附 5 springboot之配置文件
- PropertySource主要是讀取SpringApplication.setDefaultProperties指定的默認屬性 + 命令行屬性
- 事件發布器發布ApplicationEnvironmentPreparedEvent事件,所有監聽了該事件的ApplicationListener執行相應邏輯
- 創建ApplicationContext容器
- 設置Environment到容器
- 執行所有的ApplicationContextInitializer的initial方法,對創建出來的ApplicationContext容器進行初始化
- 將之前通過@EnableAutoConfiguration的所有配置以及其他形式的IOC容器加載到已經准備完畢的ApplicationContext
- 裝載beanDefinition到ApplicationContext(之后在使用Bean的時候,直接由beanDefinition初始化為bean)
- 事件發布器將所有的ApplicationListener注冊給當前的ApplicationContext,之后發布ApplicationPreparedEvent事件
- 刷新ApplicationContext
- 這里如果有ContextRefreshedEvent的監聽器,那么此時就會觸發其onApplication方法
- 結束計時,記錄整個啟動時間
以上紅色部分就是核心步驟!
參考:
http://www.jianshu.com/p/692b10aef052
http://zhaox.github.io/java/2016/03/22/spring-boot-start-flow
《springboot揭秘-快速構建微服務體系》