本篇文章是SpringBoot最入門的介紹。咱們不借助任何額外的工具,從無到有建立一個Spring Boot的web項目,並運行這個項目。java
歸根結底,Spring Boot就只是一個框架,幾個jar而已,沒什麼神奇的。但使用Spring Initializr建立項目的過程把不少信息屏蔽掉了,這樣咱們就很難搞清楚Spring Boot的本質是什麼。下面僅使用maven從無到有構建一個Spring Boot的web項目。
先建立一個maven空工程以下所示,項目的名字叫spring-boot-hello。git
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.poype</groupId> <artifactId>spring-boot-hello</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> </dependencies> </project>
如今這仍是一個空的maven項目,咱們能夠在dependencies標籤中添加咱們須要的依賴,例如添加Spring Boot的依賴。可是Spring Boot爲了減小配置,方便咱們開發,提供了一個parent maven工程spring-boot-starter-parent,咱們只要讓咱們的這個項目繼承spring-boot-starter-parent工程,就能減小好多配置。修改咱們的POM配置以下:github
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.poype</groupId> <artifactId>spring-boot-hello</artifactId> <version>1.0-SNAPSHOT</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.4.RELEASE</version> </parent> <dependencies> </dependencies> </project>
目前咱們的這個maven項目尚未導入任何dependency,這點能夠經過執行mvn dependency:tree
命令肯定。
咱們要建立的是一個web項目,因此添加spring-boot-starter-web這個依賴。修改POM配置以下:web
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.poype</groupId> <artifactId>spring-boot-hello</artifactId> <version>1.0-SNAPSHOT</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.4.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> </project>
因爲在spring-boot-starter-parent的dependencyManagement
中已經用聲明瞭spring-boot-starter-web,因此此處咱們能夠省略它的version配置。
再次執行mvn dependency:tree
命令得到以下結果:spring
[INFO] Scanning for projects... [INFO] [INFO] --------------------< com.poype:spring-boot-hello >--------------------- [INFO] Building spring-boot-hello 1.0-SNAPSHOT [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- maven-dependency-plugin:3.1.1:tree (default-cli) @ spring-boot-hello --- [INFO] com.poype:spring-boot-hello:jar:1.0-SNAPSHOT [INFO] \- org.springframework.boot:spring-boot-starter-web:jar:2.1.4.RELEASE:compile [INFO] +- org.springframework.boot:spring-boot-starter:jar:2.1.4.RELEASE:compile [INFO] | +- org.springframework.boot:spring-boot:jar:2.1.4.RELEASE:compile [INFO] | +- org.springframework.boot:spring-boot-autoconfigure:jar:2.1.4.RELEASE:compile [INFO] | +- org.springframework.boot:spring-boot-starter-logging:jar:2.1.4.RELEASE:compile [INFO] | | +- ch.qos.logback:logback-classic:jar:1.2.3:compile [INFO] | | | +- ch.qos.logback:logback-core:jar:1.2.3:compile [INFO] | | | \- org.slf4j:slf4j-api:jar:1.7.26:compile [INFO] | | +- org.apache.logging.log4j:log4j-to-slf4j:jar:2.11.2:compile [INFO] | | | \- org.apache.logging.log4j:log4j-api:jar:2.11.2:compile [INFO] | | \- org.slf4j:jul-to-slf4j:jar:1.7.26:compile [INFO] | +- javax.annotation:javax.annotation-api:jar:1.3.2:compile [INFO] | +- org.springframework:spring-core:jar:5.1.6.RELEASE:compile [INFO] | | \- org.springframework:spring-jcl:jar:5.1.6.RELEASE:compile [INFO] | \- org.yaml:snakeyaml:jar:1.23:runtime [INFO] +- org.springframework.boot:spring-boot-starter-json:jar:2.1.4.RELEASE:compile [INFO] | +- com.fasterxml.jackson.core:jackson-databind:jar:2.9.8:compile [INFO] | | +- com.fasterxml.jackson.core:jackson-annotations:jar:2.9.0:compile [INFO] | | \- com.fasterxml.jackson.core:jackson-core:jar:2.9.8:compile [INFO] | +- com.fasterxml.jackson.datatype:jackson-datatype-jdk8:jar:2.9.8:compile [INFO] | +- com.fasterxml.jackson.datatype:jackson-datatype-jsr310:jar:2.9.8:compile [INFO] | \- com.fasterxml.jackson.module:jackson-module-parameter-names:jar:2.9.8:compile [INFO] +- org.springframework.boot:spring-boot-starter-tomcat:jar:2.1.4.RELEASE:compile [INFO] | +- org.apache.tomcat.embed:tomcat-embed-core:jar:9.0.17:compile [INFO] | +- org.apache.tomcat.embed:tomcat-embed-el:jar:9.0.17:compile [INFO] | \- org.apache.tomcat.embed:tomcat-embed-websocket:jar:9.0.17:compile [INFO] +- org.hibernate.validator:hibernate-validator:jar:6.0.16.Final:compile [INFO] | +- javax.validation:validation-api:jar:2.0.1.Final:compile [INFO] | +- org.jboss.logging:jboss-logging:jar:3.3.2.Final:compile [INFO] | \- com.fasterxml:classmate:jar:1.4.0:compile [INFO] +- org.springframework:spring-web:jar:5.1.6.RELEASE:compile [INFO] | \- org.springframework:spring-beans:jar:5.1.6.RELEASE:compile [INFO] \- org.springframework:spring-webmvc:jar:5.1.6.RELEASE:compile [INFO] +- org.springframework:spring-aop:jar:5.1.6.RELEASE:compile [INFO] +- org.springframework:spring-context:jar:5.1.6.RELEASE:compile [INFO] \- org.springframework:spring-expression:jar:5.1.6.RELEASE:compile [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 2.018 s [INFO] Finished at: 2019-05-19T22:54:50+08:00 [INFO] ------------------------------------------------------------------------
能夠看到在添加spring-boot-starter-web這個依賴後,有許多的jar都被導入了。
除了更多的spring-boot-starter-*被導入了以外,更重要的是不少Spring Framework的jar也被導入了,包括spring-core、spring-beans、spring-context、spring-aop等等。另外還有與tomcat相關的jar也被導入了,也就是說如今咱們已經有了能夠運行web程序的servlet容器了。
工程配置已經完成,新建一個HelloController測試類,輸入以下代碼:express
package com.poype.springboot.web; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @EnableAutoConfiguration public class HelloController { @RequestMapping("/hello") String home() { return "Hello World!"; } public static void main(String[] args) { SpringApplication.run(HelloController.class, args); } }
如今,咱們已經完成了一個簡單的web應用開發,能夠啓動咱們這個應用了。
因爲咱們的工程繼承了spring-boot-starter-parent的POM配置,它提供了啓動spring-boot應用的相關插件(該插件的run目標用於啓動應用),能夠經過執行mvn spring-boot:run
命令啓動應用,獲得以下運行結果。apache
從運行結果中能夠看到,spring-boot啓動了Tomcat服務器,並監聽在8080端口。下面咱們打開瀏覽器,輸入地址http://localhost:8080/hello
就能夠看到程序運行結果。json
應用構建好以後,須要build出一個應用包才能用於生產部署。爲此須要在POM配置中新增一個插件,修改POM配置以下:api
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.poype</groupId> <artifactId>spring-boot-hello</artifactId> <version>1.0-SNAPSHOT</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.4.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
接着咱們執行mvn clean package
命令,能夠在target目錄下發現構建好的應用包 spring-boot-hello-1.0-SNAPSHOT.jar。
執行java -jar ./target/spring-boot-hello-1.0-SNAPSHOT.jar
命令就能夠啓動應用了。瀏覽器
上面的例子雖然很是簡單,但卻也是一個標準的spring web應用。咱們能夠回憶一下,若是沒有Spring Boot,建立一個這樣的web應用都須要哪些步驟呢?首先要在maven的POM中導入N多相關dependency(包括Spring的、servlet的、json的...)。而後添加各類複雜配置(包括servlet的、Spring的、Spring MVC的...)。最後寫完代碼build好一個war包,咱們還須要下載一個Tomcat,並將war包放到tomcat下的指定路徑,啓動tomcat部署應用。這個過程即便是工做幾年的老司機,從無到有建立一個項目估計也要十幾分鍾,若是是新手再遇到一些問題,解決起來就更麻煩了,可能幾個小時也不必定能搞得出來。
使用Spring Boot構建應用,即使咱們僅僅使用maven,也幾乎沒有什麼配置。若是使用Spring Initializr的話,建立好工程無需任何配置就直接能夠寫代碼了,很是的方便,即便是新手幾分鐘也能搞出來這個HelloWorld應用。這就是Spring Boot給個人最初印象,可是它是如何作到這些的呢?
Spring Boot提供了不少Starter依賴,每種類型的Starter提供了這種類型應用可能須要的一系列dependency(利用maven間接依賴的特性)。例如咱們這裏建立的是一個web應用,因此咱們的項目依賴spring-boot-starter-web,而spring-boot-starter-web會將web開發可能須要的依賴所有幫咱們導入,省去不少配置的工做。spring-boot-starter-parent是一個特殊的starter,它提供了許多maven默認配置,如dependenceManagment。
另外一個比較重要的是註解@EnableAutoConfiguration
,Spring Boot看到這個註解,會根據已經加入的jar dependency執行相關的配置。例如在咱們的工程中有Spring MVC和Tomcat的依賴,Spring Boot就會猜到這是一個WEB工程,它就會對項目執行相應的配置(如Spring MVC和Servlet的配置)。
Spring Boot自帶了一個Tomcat容器,省去咱們本身安裝和配置容器的工做。爲了瞭解Spring Boot的啓動過程,咱們將build好的jar解壓獲得的目錄結構以下圖所示:
其中最主要的配置文件是MANIFEST.MF,在執行java -jar *.jar啓動命令時,JVM參考的就是這個文件的配置。其文件內容以下:
Manifest-Version: 1.0 Implementation-Title: spring-boot-hello Implementation-Version: 1.0-SNAPSHOT Built-By: poype Implementation-Vendor-Id: com.poype Spring-Boot-Version: 2.1.4.RELEASE Main-Class: org.springframework.boot.loader.JarLauncher Start-Class: com.poype.springboot.web.HelloController Spring-Boot-Classes: BOOT-INF/classes/ Spring-Boot-Lib: BOOT-INF/lib/ Created-By: Apache Maven 3.6.1 Build-Jdk: 1.8.0_211 Implementation-URL: https://projects.spring.io/spring-boot/#/spring-bo ot-starter-parent/spring-boot-hello
Main-Class是jar包中的啓動類,能夠看到是一個叫org.springframework.boot.loader.JarLauncher類,是Spring Boot提供的Launcher類。Start-Class是咱們本身編寫的含有main方法的類。JarLauncher的代碼以下:
public class JarLauncher extends ExecutableArchiveLauncher { static final String BOOT_INF_CLASSES = "BOOT-INF/classes/"; static final String BOOT_INF_LIB = "BOOT-INF/lib/"; public JarLauncher() {} protected JarLauncher(Archive archive) { super(archive); } @Override protected boolean isNestedArchive(Archive.Entry entry) { if (entry.isDirectory()) { return entry.getName().equals(BOOT_INF_CLASSES); } return entry.getName().startsWith(BOOT_INF_LIB); } public static void main(String[] args) throws Exception { new JarLauncher().launch(args); } }
從代碼中能夠看出,BOOT-INF/classes/路徑下存放了應用程序本身的類,BOOT-INF/lib/路徑下存放了第三方依賴的jar,包括內嵌的tomcat jar。
因爲這個Jar中既包含應用程序本身的類,又包含應用所依賴的第三方的Jar,還包含Spring Boot Loader相關的類,因此這個Jar被稱做Fat Jar。
在JarLauncher類的main函數中,經過launch方法啓動整個應用。launch方法的實如今父類Launcher中。在Launcher方法中,會根據MANIFEST.MF中Start-Class的配置項找到咱們本身的Main Class,而後構造一個ClassLoader加載應用類和第三方的Jar,最後會建立一個新的線程執行應用程序本身的main函數。看到這裏咱們能夠大概總結一下,Spring Boot實現了一套本身的部署路徑規範(應用本身的類放在哪裏,應用依賴的第三方jar放在哪裏等等),就像J2EE規範同樣。而後利用tomcat的jar實現servlet容器的功能,對WEB請求進行處理。能夠說Spring Boot利用tomcat打造了一個全新的平臺,這個平臺也僅僅只在servlet容器部分利用到了tomcat的功能,至於部署規範和加載機制,都是Spring Boot本身全新實現的。