SpringBoot是一個(gè)快速開發(fā)框架,快速的將一些常用的第三方依賴整合(原理:通過Maven子父工程的方式),簡(jiǎn)化XML配置,全部采用注解形式,內(nèi)置Http服務(wù)器(Jetty和Tomcat),最終以java應(yīng)用程序進(jìn)行執(zhí)行,它是為了簡(jiǎn)化Spring應(yīng)用的創(chuàng)建、運(yùn)行、調(diào)試、部署等而出現(xiàn)的,使用它可以做到專注于Spring應(yīng)用的開發(fā),而無需過多關(guān)注XML的配置。
核心原理
1. SpringBoot核心通過Maven繼承依賴關(guān)系快速整合第三方框架
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.RELEASE</version>
</parent>
<dependencies>
<!-- SpringBoot 整合SpringMVC -->
<!-- 我們依賴spring-boot-starter-web能夠幫我整合Spring環(huán)境 原理通過Maven子父工程 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
springboot 通過引用spring-boot-starter-web依賴,整合SpingMVC框架。當(dāng)你添加了相應(yīng)的starter模塊,就相當(dāng)于添加了相應(yīng)的所有必須的依賴包,包括spring-boot-starter(這是Spring Boot的核心啟動(dòng)器,包含了自動(dòng)配置、日志和YAML);spring-boot-starter-test(支持常規(guī)的測(cè)試依賴,包括JUnit、Hamcrest、Mockito以及spring-test模塊);spring-boot-starter-web (支持全棧式Web開發(fā),包括Tomcat和spring-webmvc)等相關(guān)依賴。
2. 基于SpringMVC無配置文件(純Java)完全注解化實(shí)現(xiàn)SpringBoot框架,Main函數(shù)啟動(dòng)。
@SpringBootApplication
public class Application {
//方式一
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
//方式二
public static void main(String[] args) {
SpringApplication app = new SpringApplication(MySpringConfiguration.class);
app.run(args);
}
//方式三
public static void main(String[] args) {
new SpringApplicationBuilder()
.sources(Parent.class)
.child(Application.class)
.run(args);
}
}
springboot有三種方式啟動(dòng),都會(huì)在沒有web.xml配置文件的情況,通過java代碼操作整個(gè)SpringMVC的初始化過程,java代碼最終會(huì)生成class文件,內(nèi)置Tomcat就會(huì)加載這些class文件,當(dāng)所有程序加載完成后,項(xiàng)目就可以訪問了。
啟動(dòng)流程
springboot中只需要有@SpringBootApplication這個(gè)注解,有了它馬上就能夠讓整個(gè)應(yīng)用跑起來。實(shí)際上它只是一個(gè)組合注解,@Configuration配置類,@ComponentScan類,包掃描,@EnableAutoConfiguration根據(jù)需求自動(dòng)加載相關(guān)的bean這三個(gè)注解。
啟動(dòng)流程如下:
1. 初始化監(jiān)聽器,以及添加到SpringApplication的自定義監(jiān)聽器。
2. 發(fā)布ApplicationStartedEvent事件,如果想監(jiān)聽ApplicationStartedEvent事件,你可以這樣定義:public class ApplicationStartedListener implements ApplicationListener,然后通過SpringApplication.addListener(..)添加進(jìn)去即可。
3. 裝配參數(shù)和環(huán)境,確定是web環(huán)境還是非web環(huán)境。
4. 裝配完環(huán)境后,就觸發(fā)ApplicationEnvironmentPreparedEvent事件。
5. 如果SpringApplication的showBanner屬性被設(shè)置為true,則打印啟動(dòng)的Banner。
6. 創(chuàng)建ApplicationContext,會(huì)根據(jù)是否是web環(huán)境,來決定創(chuàng)建什么類型的ApplicationContext。
7. 裝配Context的環(huán)境變量,注冊(cè)Initializers、beanNameGenerator等。
8. 發(fā)布ApplicationPreparedEvent事件。
9. 注冊(cè)springApplicationArguments、springBootBanner,加載資源等
10. 遍歷調(diào)用所有SpringApplicationRunListener的contextLoaded()方法。
11. 調(diào)用ApplicationContext的refresh()方法,裝配context beanfactory等非常重要的核心組件。
12. 查找當(dāng)前ApplicationContext中是否注冊(cè)有CommandLineRunner,如果有,則遍歷執(zhí)行它們。
13. 發(fā)布ApplicationReadyEvent事件,啟動(dòng)完畢,表示服務(wù)已經(jīng)可以開始正常提供服務(wù)了。通常我們這里會(huì)監(jiān)聽這個(gè)事件來打印一些監(jiān)控性質(zhì)的日志,表示應(yīng)用正常啟動(dòng)了。
SpringApplication是springboot的入口
SpringApplication是springboot驅(qū)動(dòng)spring應(yīng)用上下文的引導(dǎo)類,他的run()方法啟動(dòng)Spring應(yīng)用,實(shí)質(zhì)上是為Spring應(yīng)用創(chuàng)建并初始化Spring上下文。
執(zhí)行流程

1. 初始化監(jiān)聽器,以及添加到SpringApplication的自定義監(jiān)聽器。
2. 發(fā)布ApplicationStartedEvent事件,如果想監(jiān)聽ApplicationStartedEvent事件,你可以這樣定義:public class ApplicationStartedListener implements ApplicationListener,然后通過SpringApplication.addListener(..)添加進(jìn)去即可。
3. 裝配參數(shù)和環(huán)境,確定是web環(huán)境還是非web環(huán)境。
4. 裝配完環(huán)境后,就觸發(fā)ApplicationEnvironmentPreparedEvent事件。
5. 如果SpringApplication的showBanner屬性被設(shè)置為true,則打印啟動(dòng)的Banner。
6. 創(chuàng)建ApplicationContext,會(huì)根據(jù)是否是web環(huán)境,來決定創(chuàng)建什么類型的ApplicationContext。
7. 裝配Context的環(huán)境變量,注冊(cè)Initializers、beanNameGenerator等。
8. 發(fā)布ApplicationPreparedEvent事件。
9. 注冊(cè)springApplicationArguments、springBootBanner,加載資源等
10. 遍歷調(diào)用所有SpringApplicationRunListener的contextLoaded()方法。
11. 調(diào)用ApplicationContext的refresh()方法,裝配context beanfactory等非常重要的核心組件。
12. 查找當(dāng)前ApplicationContext中是否注冊(cè)有CommandLineRunner,如果有,則遍歷執(zhí)行它們。
13. 發(fā)布ApplicationReadyEvent事件,啟動(dòng)完畢,表示服務(wù)已經(jīng)可以開始正常提供服務(wù)了。通常我們這里會(huì)監(jiān)聽這個(gè)事件來打印一些監(jiān)控性質(zhì)的日志,表示應(yīng)用正常啟動(dòng)了。
SpringBoot會(huì)觸發(fā)其他的一些事件,這些事件按下列順序觸發(fā):
(1)ApplicationStartingEvent:項(xiàng)目剛啟動(dòng)時(shí)觸發(fā),此時(shí)除了注冊(cè)監(jiān)聽器和初始器之外,其他所有處理都沒有開始;
(2)ApplicationEnvironmentPreparedEvent:上下文得到環(huán)境信息之后觸發(fā),此時(shí)上下文創(chuàng)建還沒有創(chuàng)建;
(3)ApplicationPreparedEvent:bean的定義信息加載完成之后觸發(fā),此時(shí)bean還沒有初始化;
(4)ApplicationReadyEvent:在所有bean初始化完畢,所有回調(diào)處理完成,系統(tǒng)準(zhǔn)備處理服務(wù)請(qǐng)求時(shí)觸發(fā);
(5)ApplicationFailedEvent:?jiǎn)?dòng)過程出現(xiàn)異常時(shí)候觸發(fā)。
SpringApplication.run()
如果我們使用的是SpringApplication的靜態(tài)run方法,那么,這個(gè)方法里面首先要?jiǎng)?chuàng)建一個(gè)SpringApplication對(duì)象實(shí)例,然后調(diào)用這個(gè)創(chuàng)建好的SpringApplication的實(shí)例方法。在SpringApplication實(shí)例初始化的時(shí)候,它會(huì)提前做幾件事情:
1. 根據(jù)classpath里面是否存在某個(gè)特征類(org.springframework.web.context.ConfigurableWebApplicationContext)來決定是否應(yīng)該創(chuàng)建一個(gè)為Web應(yīng)用使用的ApplicationContext類型。
2. 使用SpringFactoriesLoader在應(yīng)用的classpath中查找并加載所有可用的ApplicationContextInitializer。
3. 使用SpringFactoriesLoader在應(yīng)用的classpath中查找并加載所有可用的ApplicationListener。
4. 推斷并設(shè)置main方法的定義類。
它會(huì)執(zhí)行以下步驟:
1. 創(chuàng)建一個(gè)合適的ApplicationContext實(shí)例 (取決于classpath)。
2. 注冊(cè)一個(gè)CommandLinePropertySource,以便將命令行參數(shù)作為Spring properties。
3. 刷新application context,加載所有單例beans。
4. 激活所有CommandLineRunner beans。
Run啟動(dòng)方式
@SpringBootApplication
public class Application {
//方式一
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
//方式二
public static void main(String[] args) {
SpringApplication app = new SpringApplication(MySpringConfiguration.class);
app.run(args);
}
//方式三
public static void main(String[] args) {
new SpringApplicationBuilder()
.sources(Parent.class)
.child(Application.class)
.run(args);
}
}
1. SpringApplication.run()的底層其實(shí)就是new了一個(gè)SpringApplication的對(duì)象,并執(zhí)行run()方法。
2. 有時(shí)我們需要?jiǎng)?chuàng)建多層次的ApplicationContext (例如,父子關(guān)系的Spring的ApplicationContext 和SpringMVC),這時(shí)我們可以使用SpringApplicationBuilder講多個(gè)方法調(diào)用串起來,通過parent() 和 child()來創(chuàng)建多層次的ApplicationContext。
啟動(dòng)信息

啟動(dòng)信息如下:
第 9 行,啟動(dòng)SampleController。
第10行,查找active profile,無,設(shè)為default。
第11行,刷新上下文。
第12行,初始化tomcat,設(shè)置端口8080,設(shè)置訪問方式為http。
第13行,啟動(dòng)tomcat服務(wù)。
第14行,啟動(dòng)Servlet引擎。
第15行,Spring內(nèi)嵌的WebApplicationContext 初始化開始。
第16行,Spring內(nèi)嵌的WebApplicationContext 初始化完成。
第17行,映射servlet,將 dispatcherServlet 映射到 [/] 。
第18行,映射filter,將 characterEncodingFilter 映射到 [/*] 。
第19行,映射filter,將 hiddenHttpMethodFilter 映射到 [/*] 。
第20行,映射filter,將 httpPutFormContentFilter 映射到 [/*] 。
第21行,映射filter,將 requestContextFilter 映射到 [/*] 。
第22行,查找 @ControllerAdvice。
第23行,映射路徑 "{[/]}" 到 cn.larry.spring.controller.SampleController.home()。
第24行,映射路徑 "{[/error]}" 到 org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)。
第25行,映射路徑 "{[/error],produces=[text/html]}" 到 org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)。
第30行,tomcat啟動(dòng)完畢。
第31行,SampleController啟動(dòng)耗費(fèi)的時(shí)間。
第32行,初始化 dispatcherServlet 。
第33行,dispatcherServlet 的初始化已啟動(dòng)。
第34行,dispatcherServlet 的初始化已完成。
第35行,收到shutdown關(guān)閉請(qǐng)求。
第36行,關(guān)閉AnnotationConfigEmbeddedWebApplicationContext。
SpringBootApplication的啟動(dòng)過程非常復(fù)雜,只需要在main方法里調(diào)用SpringApplicatio.run()方法即可啟動(dòng)Spring Boot應(yīng)用。
