程式入口 SpringApplication.run(BeautyApplication.class, args); 執行此方法來載入整個SpringBoot的環境。 1. 從哪兒開始? SpringApplication.java /** * Run the Spring application, ...
程式入口
SpringApplication.run(BeautyApplication.class, args);
執行此方法來載入整個SpringBoot的環境。
1. 從哪兒開始?
SpringApplication.java
/** * Run the Spring application, creating and refreshing a new * {@link ApplicationContext}. * @param args the application arguments (usually passed from a Java main method) * @return a running {@link ApplicationContext} */ public ConfigurableApplicationContext run(String... args) { //... }
調用SpringApplication.java 中的 run 方法,目的是載入Spring Application,同時返回 ApplicationContext。
2. 執行了什麼?
2.1 計時
記錄整個Spring Application的載入時間!
StopWatch stopWatch = new StopWatch(); stopWatch.start(); // ... stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass) .logStarted(getApplicationLog(), stopWatch); }
2.2 聲明
// 聲明 ApplicationContext ConfigurableApplicationContext context = null; // 聲明 一個異常報告集合 Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
2.3 指定程式運行模式
指定 java.awt.headless,預設是true 一般是在程式開始激活headless模式,告訴程式,現在你要工作在Headless mode下,就不要指望硬體幫忙了,你得自力更生,依靠系統的計算能力模擬出這些特性來。
private void configureHeadlessProperty() { System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, System.getProperty( SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless))); }
2.4 配置監聽併發布應用啟動事件
SpringApplicationRunListener 負責載入 ApplicationListener事件。
SpringApplicationRunListeners listeners = getRunListeners(args); // 開始 listeners.starting(); // 處理所有 property sources 配置和 profiles 配置,準備環境,分為標準 Servlet 環境和標準環境 ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments); // 準備應用上下文 prepareContext(context, environment, listeners, applicationArguments,printedBanner); // 完成 listeners.started(context); // 異常 handleRunFailure(context, ex, exceptionReporters, listeners); // 執行 listeners.running(context);
getRunListeners 中根據 type = SpringApplicationRunListener.class 去拿到了所有的 Listener 並根據優先順序排序。
對應的就是 META-INF/spring.factories 文件中的 org.springframework.boot.SpringApplicationRunListener=org.springframework.boot.context.event.EventPublishingRunListener
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); // Use names and ensure unique to protect against duplicates Set<String> names = new LinkedHashSet<>( SpringFactoriesLoader.loadFactoryNames(type, classLoader)); List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); AnnotationAwareOrderComparator.sort(instances); return instances; }
在 ApplicationListener 中 , 可以針對任何一個階段插入處理代碼。
public interface SpringApplicationRunListener { /** * Called immediately when the run method has first started. Can be used for very * early initialization. */ void starting(); /** * Called once the environment has been prepared, but before the * {@link ApplicationContext} has been created. * @param environment the environment */ void environmentPrepared(ConfigurableEnvironment environment); /** * Called once the {@link ApplicationContext} has been created and prepared, but * before sources have been loaded. * @param context the application context */ void contextPrepared(ConfigurableApplicationContext context); /** * Called once the application context has been loaded but before it has been * refreshed. * @param context the application context */ void contextLoaded(ConfigurableApplicationContext context); /** * The context has been refreshed and the application has started but * {@link CommandLineRunner CommandLineRunners} and {@link ApplicationRunner * ApplicationRunners} have not been called. * @param context the application context. * @since 2.0.0 */ void started(ConfigurableApplicationContext context); /** * Called immediately before the run method finishes, when the application context has * been refreshed and all {@link CommandLineRunner CommandLineRunners} and * {@link ApplicationRunner ApplicationRunners} have been called. * @param context the application context. * @since 2.0.0 */ void running(ConfigurableApplicationContext context); /** * Called when a failure occurs when running the application. * @param context the application context or {@code null} if a failure occurred before * the context was created * @param exception the failure * @since 2.0.0 */ void failed(ConfigurableApplicationContext context, Throwable exception); }
3. 每個階段執行的內容
3.1 listeners.starting();
在載入Spring Application之前執行,所有資源和環境未被載入。
3.2 prepareEnvironment(listeners, applicationArguments);
創建 ConfigurableEnvironment;將配置的環境綁定到Spring Application中;
private ConfigurableEnvironment prepareEnvironment( SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) { // Create and configure the environment ConfigurableEnvironment environment = getOrCreateEnvironment(); configureEnvironment(environment, applicationArguments.getSourceArgs()); listeners.environmentPrepared(environment); bindToSpringApplication(environment); if (this.webApplicationType == WebApplicationType.NONE) { environment = new EnvironmentConverter(getClassLoader()) .convertToStandardEnvironmentIfNecessary(environment); } ConfigurationPropertySources.attach(environment); return environment; }
3.3 prepareContext
配置忽略的Bean;
private void configureIgnoreBeanInfo(ConfigurableEnvironment environment) { if (System.getProperty( CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME) == null) { Boolean ignore = environment.getProperty("spring.beaninfo.ignore", Boolean.class, Boolean.TRUE); System.setProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME, ignore.toString()); } }
列印日誌-載入的資源
Banner printedBanner = printBanner(environment);
根據不同的WebApplicationType創建Context
context = createApplicationContext();
3.4 refreshContext
支持定製刷新
/** * Register a shutdown hook with the JVM runtime, closing this context * on JVM shutdown unless it has already been closed at that time. * <p>This method can be called multiple times. Only one shutdown hook * (at max) will be registered for each context instance. * @see java.lang.Runtime#addShutdownHook * @see #close() */ void registerShutdownHook();
3.5 afterRefresh
刷新後的實現方法暫未實現
/** * Called after the context has been refreshed. * @param context the application context * @param args the application arguments */ protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) { }
3.6 listeners.started(context);
到此為止, Spring Application的環境和資源都載入完畢了;發佈應用上下文啟動完成事件;執行所有 Runner 運行器 - 執行所有 ApplicationRunner 和 CommandLineRunner 這兩種運行器。
// 啟動 callRunners(context, applicationArguments);
3.7 listeners.running(context);
觸發所有 SpringApplicationRunListener 監聽器的 running 事件方法
(完)
本人免費整理了Java高級資料,涵蓋了Java、Redis、MongoDB、MySQL、Zookeeper、Spring Cloud、Dubbo高併發分散式等教程,一共30G,需要自己領取。
傳送門:https://mp.weixin.qq.com/s/osB-BOl6W-ZLTSttTkqMPQ