Spring Boot 是個(gè)什么東西?官方給出的解釋是Spring Boot is designed to get you up and running as quickly as possible, with minimal upfront configuration of Spring. Spring Boot takes an opinionated view of building production-ready applications. 解釋下來就是Spring Boot 是為了快速的啟動(dòng)且最小化配置Spring應(yīng)用而設(shè)計(jì)的。Spring Boot 采用固化視圖來構(gòu)建生產(chǎn)級(jí)別應(yīng)用。 這是官網(wǎng)首頁(yè)最顯眼的地方擺出的兩句話,當(dāng)然官網(wǎng)推崇Spring Boot 遠(yuǎn)不止這兩句話,下面還來了句更狠的Spring Boot is the starting point for building all Spring-based applications. 這句話有多狠呢?Spring Boot 是都有基于Spring 構(gòu)建的應(yīng)用的起點(diǎn),可見Spring 官方為了推出Spring Boot的決心。
Spring Boot 的特點(diǎn)
下面是官網(wǎng)列出的9個(gè)特點(diǎn),我們逐一了解下
-
Get started in seconds using Spring Initializr
使用Spring Initializr 幾秒的時(shí)間就可以啟動(dòng)。我個(gè)人的理解是在https://start.spring.io/網(wǎng)址花幾秒鐘的時(shí)間就可以構(gòu)建一個(gè)Spring Boot 項(xiàng)目,剛好這個(gè)網(wǎng)頁(yè)的title就叫Spring Initializr。
Spring Initializr Build anything: REST API, WebSocket, web, streaming, tasks, and more
可以用來構(gòu)建任何東西如: REST API,WebSocket, web, streaming, tasks 這個(gè)我們以后探討。Simplified security
簡(jiǎn)化了安全框架,這個(gè)比較明確了,需要實(shí)踐發(fā)現(xiàn)如何簡(jiǎn)化。Rich support for SQL and NoSQL
良好的支持了SQL和NoSQLEmbedded runtime support: Tomcat, Jetty, and Undertow
嵌入式運(yùn)行時(shí)容器:Tomcat, Jetty, and Undertow,實(shí)際上Spring Boot2.0 加入的Web Flux 默認(rèn)采用的是Netty容器,當(dāng)然這個(gè)后面討論吧。Developer productivity tools such as LiveReload and Auto Restart
開發(fā)者的生產(chǎn)工具如LiveReload 和 Auto RestartCurated dependencies that just work
更加精簡(jiǎn)的依賴Production-ready features such as tracing, metrics, and health status
提供為生產(chǎn)環(huán)境準(zhǔn)備的功能如:跟蹤、度量和運(yùn)行狀態(tài)Works in your favorite IDE: Spring Tool Suite, IntelliJ IDEA, and NetBeans
可以在你喜歡的IDE上工作如Spring Tool Suite, IntelliJ IDEA, and NetBeans,好吧,我現(xiàn)在用得就是IntelliJ IDEA
說了那么多特點(diǎn),直接開干就知道了
Spring Initializr直接點(diǎn)generate project 生成項(xiàng)目,存放到本地,解壓,目錄如下
demo
│ .gitignore
│ HELP.md
│ mvnw
│ mvnw.cmd
│ pom.xml
│
├─.mvn
│ └─wrapper
│ maven-wrapper.jar
│ maven-wrapper.properties
│ MavenWrapperDownloader.java
│
└─src
├─main
│ ├─java
│ │ └─com
│ │ └─example
│ │ └─demo
│ │ DemoApplication.java
│ │
│ └─resources
│ application.properties
│
└─test
└─java
└─com
└─example
└─demo
DemoApplicationTests.java
windows 下面列出文件目錄的指令時(shí)tree,將文件和目錄一起列出是tree /f ,輸出到文件中使用tree /f > list.txt
.gitignore 文件存放的是一些流行的IDE的元信息如STS,IntelliJ IDEA,NetBeans,VS Code
mvnw.cmd 文件配置的是一些maven信息,我們知道Spring Boot 要求使用Maven3.0以上的版本構(gòu)建,但是有了這個(gè)文件后,我們甚至在本機(jī)中沒有安裝Maven也能采Maven來構(gòu)建項(xiàng)目
pom.xml文件,依賴配置文件,這里我們采用的Spring Boot 版本是org.springframework.boot:spring-boot-starter-parent:2.2.0.M2
DemoApplication.java 啟動(dòng)類
- 編譯啟動(dòng)項(xiàng)目
進(jìn)入到pom.xml同級(jí)目錄使用mvn spring-boot:run 或者mvnw.cmd spring-boot:run啟動(dòng)項(xiàng)目,程序就會(huì)自動(dòng)去下載依賴包和編譯,是不是很方便。
由于國(guó)內(nèi)環(huán)境下載速度太慢,推薦使用mvn spring-boot:run ,然后我們對(duì)本地的maven配置上阿里云鏡像 修改settings.xml文件修改
<mirror>
<id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<mirrorOf>central</mirrorOf>
</mirror>

這個(gè)時(shí)候,程序直接退出了,主要原因是沒有嵌入式web容器,就是說剛才啟動(dòng)的就是一個(gè)普通的Java項(xiàng)目,執(zhí)行完后就退出了。我們添加依賴org.springframework.boot:spring-boot-starter-web 再啟動(dòng),這個(gè)時(shí)候我們就可以去訪問http://localhost:8080/ 返回404,當(dāng)然,我們沒有配置信息,至少可以確定,服務(wù)器已經(jīng)啟動(dòng)了。
-
打包
剛才已經(jīng)說過了,我們可以采用mvn spring-boot:run 指令來啟動(dòng)項(xiàng)目,而我們線上環(huán)境當(dāng)然不能那么草率的啟動(dòng),還是需要jar包或者war包的形式的。我們知道m(xù)aven的打包指令時(shí)mvn package 。那么我們直接試試吧。
打包
打包成功,生成了兩個(gè)文件16.3M的demo-0.0.1-SNAPSHOT.jar和2.75K的demo-0.0.1-SNAPSHOT.jar.original。
我們?cè)僭囋嚧騱ar包,修改pom的packaging為war。執(zhí)行mvn clean package。如果嫌測(cè)試麻煩加上-Dmaven.test.skip=true,打包成功,同樣生成demo-0.0.1-SNAPSHOT.war和demo-0.0.1-SNAPSHOT.war.original,這樣我們就可以用java -jar 的指令來啟動(dòng)了。 - 分析包
解壓下demo-0.0.1-SNAPSHOT.jar ,包的目錄如下
├─BOOT-INF
│ ├─classes
│ │ └─com
│ │ └─example
│ │ └─demo
│ └─lib
├─META-INF
│ └─maven
│ └─com.example
│ └─demo
└─org
└─springframework
└─boot
└─loader
├─archive
├─data
├─jar
└─util
我們發(fā)現(xiàn)BOOT-INF目錄下面有classes目錄和lib目錄,這個(gè)是不是感覺似曾相識(shí)?沒錯(cuò),就是WEB-INF目錄嘛,當(dāng)然,web.xml是不存在的。這么看來,classes我們理解成我們寫的Java代碼編譯目錄,lib為依賴jar包,這就是個(gè)web項(xiàng)目嘛。我們大膽猜測(cè)下,Spring Boot其實(shí)就是模擬的一個(gè)JavaEE項(xiàng)目。
我們?cè)倏聪耲ar包的元信息,META-INF/MANIFEST.MF
Manifest-Version: 1.0
Implementation-Title: demo
Implementation-Version: 0.0.1-SNAPSHOT
Built-By: DELL
Implementation-Vendor-Id: com.example
Spring-Boot-Version: 2.2.0.M2
Main-Class: org.springframework.boot.loader.JarLauncher
Start-Class: com.example.demo.DemoApplication
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Created-By: Apache Maven 3.5.2
Build-Jdk: 1.8.0_141
Implementation-URL: https://projects.spring.io/spring-boot/#/spring-bo
ot-starter-parent/demo
我們知道java -jar 指令程序的入口是Main-Class。這個(gè)文件中的Main-Class 是JarLauncher,并不是我們的啟動(dòng)類DemoApplication,我們猜想下,使用java JarLauncher 命令是不是也能啟動(dòng)項(xiàng)目。驗(yàn)證了下,發(fā)現(xiàn)真的可以啟動(dòng)項(xiàng)目。

我們假設(shè)下jar包里面org目錄下為Tomcat容器,那么通過啟動(dòng)Tomcat容器來啟動(dòng)我們的Spring Boot 項(xiàng)目,那么這一切就解釋的通了(ps 個(gè)人看法)
理解嵌入式Web容器
首先我們將demo項(xiàng)目導(dǎo)入到IDEA中,然后查看下IDEA下的maven依賴如下圖:

我們看到spring-boot-starter-web下面有spring-boot-stater-tomcat的依賴,所以容器默認(rèn)使用tomcat。如果我們要用Jetty或者Undertow呢?我們以Undertow為例,修改pom.xml文件
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
再次啟動(dòng)項(xiàng)目

什么鬼,不生效。
根據(jù)上面的依賴關(guān)系,我們知道spring-boot-starter-web內(nèi)部有了tomcat的依賴,如果我們不移出的話,依舊會(huì)使用tomcat作為容器,那么我們就需要修改spring-boot-satrter-web依賴了
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
重啟下項(xiàng)目

這個(gè)時(shí)候就使用了Undertow作為web容器了。
從pom.xml為入口再談編譯
首先,Spring 文檔中提到了一個(gè)Executable Jar的概念,也稱為fat jars。就是說將我們的Spring Boot 項(xiàng)目打成一個(gè)可執(zhí)行的jar包,那么如何打包呢?
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
我們可以通過spring-boot-maven-plugin插件將我們的項(xiàng)目打成可執(zhí)行jar包。這就完事了?當(dāng)然不可能,我們看下這句話If you do not use the parent POM, you need to declare this configuration yourself. 就是說,我們不是以spring-boot-starter-parent 作為parent的話,需要自己聲明配置。
那么問題來了,如何不以spring-boot-starter-parent為parent構(gòu)建Spring Boot 項(xiàng)目呢?
- 搭建不以spring-boot-starter-parent為parent 的Spring Boot 項(xiàng)目
為了演示方便,我們修改下啟動(dòng)類DemoApplication.java,將訪問http://localhost:8080/ 返回字符串,而不再是報(bào)404錯(cuò)誤。
@RestController
@SpringBootApplication
public class DemoApplication {
@RequestMapping("/")
public String hello(){
return "hello spring boot";
}
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
我們?cè)賹om.xml的parent注釋掉,然后修改spring-boot-starter-web的依賴,添加版本號(hào)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.1.4.RELEASE</version>
</dependency>
我們執(zhí)行下mvn spring-boot:run 我們發(fā)現(xiàn),啟動(dòng)時(shí)成功的,訪問下http://localhost:8080/

返回也沒有問題,那么說是不是我們的項(xiàng)目搭建成功了呢?別急,打包試試。篇幅有限,我這里不截圖了,打包也是成功的,包是demo-0.0.1-SNAPSHOT.jar,但是我們發(fā)現(xiàn)一個(gè)問題,這個(gè)包只有3K,肯定不是fat jars。
我們翻看下官方文檔的 Using Spring Boot without the Parent POM章節(jié),說的是需要添加dependencyManagement依賴,好吧,我們?cè)囋?。再?code>maven clean package 發(fā)現(xiàn)沒什么卵用,還是打的3K的jar包,看來問題不是這個(gè),我們?cè)僭囋嚻渌k法。(其實(shí)dependencyManagement是為了約定spring boot 的版本,我們使用了spring-boot-starter-web:2.1.4.RELEASE 指定好了版本號(hào)加不加入影響不大)
我們猜想應(yīng)該是maven插件的問題了,修改下pom.xml
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.1.4.RELEASE</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
repackage描述: create a jar or war file that is auto-executable. It can replace the regular artifact or can be attached to the build lifecycle with a separate classifier. 好吧,這句話就是說創(chuàng)建fat jars,我們加入后,發(fā)現(xiàn)打包后和parent效果是一樣的。至于為什么使用parent后不需要repackage就能生成fat jars,這個(gè)我就不知道了,希望大家?guī)兔獯鹣隆?/p>
之前的依賴發(fā)現(xiàn)使用的是2.2.0.M2版本,由于這個(gè)是里程碑版本,pom中需要加入一些依賴信息,我們?yōu)榱朔奖汩喿x,之后采取2.1.4.RELEASE版本。剛好,官方的最新文檔也是這個(gè)版本。
未完,待續(xù)

