一、自動裝配原理
之前博文已經講過,@SpringBootApplication繼承了@EnableAutoConfiguration,該註解匯入了AutoConfigurationImport Selector,這個類主要是掃描spring-boot-autoconfigure下面的META-INF\spring.factories中的EnableAutoConfiguration對應的全類名,其中XXXAutoConfiguration都是一個個自動配置類。
自動裝配原理具體參考:Spring Boot系列(二):Spring Boot自動裝配原理解析
二、Spring Boot的jar啟動
1、Spring Boot自動裝配Tomcat元件
① EmbeddedWebServerFactoryCustomizerAutoConfiguration內嵌的Web容器工廠定製器自動裝配類,裝配了TomcatWebServerFactoryCustomizer元件
Tomcat工廠定製器TomcatWebServerFactoryCustomizer用來設定容器的屬性,把ServerProperties中的屬性設定到Tomcat容器的工廠中。
ServerProperties服務的屬性類:
② ServletWebServerFactoryAutoConfiguration,ServletWeb工廠自動裝配類,裝配了如下四個元件
- ServletWebServerFactoryCustomizer:用來定製ServletWeb服務工廠
- TomcatServletWebServerFactoryCustomizer:用來定製TomcatServletWeb服務工廠
- ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar :後置處理器
- ServletWebServerFactoryConfiguration:用來配置TomcatServletWeb服務工廠
2、SpringApplication.run啟動流程
① new SpringApplication(primarySources),建立了一個SpringApplication
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); //設定主配置類 我們自己寫的Spring Boot的啟動類 this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); //設定web應用的型別 this.webApplicationType = WebApplicationType.deduceFromClasspath(); //設定容器初始化器(ApplicationContextInitializer型別的) setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); //把監聽器設定到SpringApplication中[ApplicationListener] setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); //設定主配置類 this.mainApplicationClass = deduceMainApplicationClass(); }
② SpringApplication的run方法:
主要流程:
第一:建立容器物件
第二:去META-INFO/spring.factories中獲取SpringApplicationRunListener監聽器(事件釋出監聽器)
第三:釋出容器starting事件(通過spring的事件多播器)
第四:封裝命令列引數
第五:準備容器環境
第六:列印Springboot的圖示
第七:根據webApplicationType來建立容器
第八:準備容器上下文
第九:釋出容器啟動事件
第十:釋出容器執行事件
public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); //容器物件 ConfigurableApplicationContext context = null; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>(); configureHeadlessProperty(); //去META-INFO/spring.factories中獲取SpringApplicationRunListener監聽器(事件釋出監聽器) SpringApplicationRunListeners listeners = getRunListeners(args); //釋出容器starting事件(通過spring的事件多播器) listeners.starting(); try { //封裝命令列引數 ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); /** * 準備容器環境 * 1: 獲取或者建立環境 * 2:把命令列引數設定到環境中 * 3:通過監聽器釋出環境準備事件 */ ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); configureIgnoreBeanInfo(environment); //列印Springboot的圖示 Banner printedBanner = printBanner(environment); //建立容器根據webApplicationType來建立容器(通過反射建立) context = createApplicationContext(); exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context); /** * 準備上下文 * 1:把環境設定到容器中 * 2: 迴圈呼叫ApplicationContextInitializer進行容器初始化工作 * 3: 釋出容器上下文準備完成事件 * 4: 註冊關於Springboot特性的相關單例Bean * 5: 釋出容器上下文載入完畢事件 */ prepareContext(context, environment, listeners, applicationArguments, printedBanner); refreshContext(context); //執行ApplicationRunner和CommandLineRunner afterRefresh(context, applicationArguments); stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch); } //釋出容器啟動事件 listeners.started(context); //執行ApplicationRunner和CommandLineRunner callRunners(context, applicationArguments); } catch (Throwable ex) { //出現異常呼叫異常分析保護類進行分析 handleRunFailure(context, ex, exceptionReporters, listeners); throw new IllegalStateException(ex); } try { //釋出容器執行事件 listeners.running(context); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, null); throw new IllegalStateException(ex); } return context; }
③ org.springframework.boot.SpringApplication#refreshContext
④ org.springframework.boot.SpringApplication#refresh
⑤ org.springframework.context.support.AbstractApplicationContext#refresh
到了AbstractApplicationContext#refresh方法,之前講過Spring IoC原始碼解析講過該方法的12大步,這裡就不細說,詳細可以參考:Spring系列(三):Spring IoC原始碼解析,裡面說過有一步就是onRefresh(),這個方法預設是空的,由子類根據自身需要去實現
⑥ org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#onRefresh
該onRefresh方法分2步
第一:super.onRefresh(); 呼叫父類的onRefresh()
第二:createWebServer();建立Web服務,很重要,很重要,很重要!!!
⑦ createWebServer()方法
第一:ServletContext servletContext = getServletContext(); 獲取Servlet的上下文
第二:ServletWebServerFactory factory = getWebServerFactory();獲取Tomcat的Web服務工廠
第三:this.webServer = factory.getWebServer(getSelfInitializer()); 建立一個Web伺服器
⑧ TomcatServletWebServerFactory#getWebServer()方法,主要用於建立一個Tomcat Web容器
到此我們知道Spring Boot的啟動通過Spring IoC的refresh中的的onRefresh()帶動了Tomcat的啟動,跟我們之前我們學Spring Mvc的時候剛好相反,Spring Mvc的是Tomcat的啟動帶動了Spring容器的啟動;
三、普通Web工程啟動
1、普通的web工程,我們找到web.xml,會發現都配置瞭如下的載入Spring的配置。
2、Tomcat啟動的時候會呼叫該上下文載入的的監聽器的contextInitialized方法,我們進入到該方法:
3、進入初始化Web應用上下文initWebApplicationContext方法中:
- this.context = createWebApplicationContext(servletContext);
- configureAndRefreshWebApplicationContext(cwac, servletContext);
4、進去到configureAndRefreshWebApplicationContext(cwac, servletContext)方法中:
5、進入到refresh方法實際就到了org.springframework.context.support.AbstractApplicationContext#refresh的方法
這個方法很熟悉了,Spring IoC的refresh的12大步;