一、自動裝配原理
之前博文已經講過,@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大步;