Spring Boot 是個什么東西?官方給出的解釋是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 是為了快速的啟動且最小化配置Spring應用而設計的。Spring Boot 采用固化視圖來構建生產級別應用。 這是官網首頁最顯眼的地方擺出的兩句話,當然官網推崇Spring Boot 遠不止這兩句話,下面還來了句更狠的Spring Boot is the starting point for building all Spring-based applications. 這句話有多狠呢?Spring Boot 是都有基于Spring 構建的應用的起點,可見Spring 官方為了推出Spring Boot的決心。
Spring Boot 的特點
下面是官網列出的9個特點,我們逐一了解下
-
Get started in seconds using Spring Initializr
使用Spring Initializr 幾秒的時間就可以啟動。我個人的理解是在https://start.spring.io/網址花幾秒鐘的時間就可以構建一個Spring Boot 項目,剛好這個網頁的title就叫Spring Initializr。
Spring Initializr Build anything: REST API, WebSocket, web, streaming, tasks, and more
可以用來構建任何東西如: REST API,WebSocket, web, streaming, tasks 這個我們以后探討。Simplified security
簡化了安全框架,這個比較明確了,需要實踐發現如何簡化。Rich support for SQL and NoSQL
良好的支持了SQL和NoSQLEmbedded runtime support: Tomcat, Jetty, and Undertow
嵌入式運行時容器:Tomcat, Jetty, and Undertow,實際上Spring Boot2.0 加入的Web Flux 默認采用的是Netty容器,當然這個后面討論吧。Developer productivity tools such as LiveReload and Auto Restart
開發者的生產工具如LiveReload 和 Auto RestartCurated dependencies that just work
更加精簡的依賴Production-ready features such as tracing, metrics, and health status
提供為生產環境準備的功能如:跟蹤、度量和運行狀態Works in your favorite IDE: Spring Tool Suite, IntelliJ IDEA, and NetBeans
可以在你喜歡的IDE上工作如Spring Tool Suite, IntelliJ IDEA, and NetBeans,好吧,我現在用得就是IntelliJ IDEA
說了那么多特點,直接開干就知道了
Spring Initializr直接點generate project 生成項目,存放到本地,解壓,目錄如下
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 下面列出文件目錄的指令時tree,將文件和目錄一起列出是tree /f ,輸出到文件中使用tree /f > list.txt
.gitignore 文件存放的是一些流行的IDE的元信息如STS,IntelliJ IDEA,NetBeans,VS Code
mvnw.cmd 文件配置的是一些maven信息,我們知道Spring Boot 要求使用Maven3.0以上的版本構建,但是有了這個文件后,我們甚至在本機中沒有安裝Maven也能采Maven來構建項目
pom.xml文件,依賴配置文件,這里我們采用的Spring Boot 版本是org.springframework.boot:spring-boot-starter-parent:2.2.0.M2
DemoApplication.java 啟動類
- 編譯啟動項目
進入到pom.xml同級目錄使用mvn spring-boot:run 或者mvnw.cmd spring-boot:run啟動項目,程序就會自動去下載依賴包和編譯,是不是很方便。
由于國內環境下載速度太慢,推薦使用mvn spring-boot:run ,然后我們對本地的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>
這個時候,程序直接退出了,主要原因是沒有嵌入式web容器,就是說剛才啟動的就是一個普通的Java項目,執行完后就退出了。我們添加依賴org.springframework.boot:spring-boot-starter-web 再啟動,這個時候我們就可以去訪問http://localhost:8080/ 返回404,當然,我們沒有配置信息,至少可以確定,服務器已經啟動了。
-
打包
剛才已經說過了,我們可以采用mvn spring-boot:run 指令來啟動項目,而我們線上環境當然不能那么草率的啟動,還是需要jar包或者war包的形式的。我們知道maven的打包指令時mvn package 。那么我們直接試試吧。
打包
打包成功,生成了兩個文件16.3M的demo-0.0.1-SNAPSHOT.jar和2.75K的demo-0.0.1-SNAPSHOT.jar.original。
我們再試試打war包,修改pom的packaging為war。執行mvn clean package。如果嫌測試麻煩加上-Dmaven.test.skip=true,打包成功,同樣生成demo-0.0.1-SNAPSHOT.war和demo-0.0.1-SNAPSHOT.war.original,這樣我們就可以用java -jar 的指令來啟動了。 - 分析包
解壓下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
我們發現BOOT-INF目錄下面有classes目錄和lib目錄,這個是不是感覺似曾相識?沒錯,就是WEB-INF目錄嘛,當然,web.xml是不存在的。這么看來,classes我們理解成我們寫的Java代碼編譯目錄,lib為依賴jar包,這就是個web項目嘛。我們大膽猜測下,Spring Boot其實就是模擬的一個JavaEE項目。
我們再看下jar包的元信息,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。這個文件中的Main-Class 是JarLauncher,并不是我們的啟動類DemoApplication,我們猜想下,使用java JarLauncher 命令是不是也能啟動項目。驗證了下,發現真的可以啟動項目。
我們假設下jar包里面org目錄下為Tomcat容器,那么通過啟動Tomcat容器來啟動我們的Spring Boot 項目,那么這一切就解釋的通了(ps 個人看法)
理解嵌入式Web容器
首先我們將demo項目導入到IDEA中,然后查看下IDEA下的maven依賴如下圖:
我們看到spring-boot-starter-web下面有spring-boot-stater-tomcat的依賴,所以容器默認使用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>
再次啟動項目
什么鬼,不生效。
根據上面的依賴關系,我們知道spring-boot-starter-web內部有了tomcat的依賴,如果我們不移出的話,依舊會使用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>
重啟下項目
這個時候就使用了Undertow作為web容器了。
從pom.xml為入口再談編譯
首先,Spring 文檔中提到了一個Executable Jar的概念,也稱為fat jars。就是說將我們的Spring Boot 項目打成一個可執行的jar包,那么如何打包呢?
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
我們可以通過spring-boot-maven-plugin插件將我們的項目打成可執行jar包。這就完事了?當然不可能,我們看下這句話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構建Spring Boot 項目呢?
- 搭建不以spring-boot-starter-parent為parent 的Spring Boot 項目
為了演示方便,我們修改下啟動類DemoApplication.java,將訪問http://localhost:8080/ 返回字符串,而不再是報404錯誤。
@RestController
@SpringBootApplication
public class DemoApplication {
@RequestMapping("/")
public String hello(){
return "hello spring boot";
}
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
我們再將pom.xml的parent
注釋掉,然后修改spring-boot-starter-web的依賴,添加版本號
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.1.4.RELEASE</version>
</dependency>
我們執行下mvn spring-boot:run
我們發現,啟動時成功的,訪問下http://localhost:8080/
返回也沒有問題,那么說是不是我們的項目搭建成功了呢?別急,打包試試。篇幅有限,我這里不截圖了,打包也是成功的,包是demo-0.0.1-SNAPSHOT.jar,但是我們發現一個問題,這個包只有3K,肯定不是fat jars。
我們翻看下官方文檔的 Using Spring Boot without the Parent POM章節,說的是需要添加dependencyManagement依賴,好吧,我們試試。再次
maven clean package
發現沒什么卵用,還是打的3K的jar包,看來問題不是這個,我們再試試其他辦法。(其實dependencyManagement是為了約定spring boot 的版本,我們使用了spring-boot-starter-web:2.1.4.RELEASE 指定好了版本號加不加入影響不大)我們猜想應該是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. 好吧,這句話就是說創建fat jars,我們加入后,發現打包后和parent效果是一樣的。至于為什么使用parent后不需要repackage就能生成fat jars,這個我就不知道了,希望大家幫忙解答下。
之前的依賴發現使用的是2.2.0.M2版本,由于這個是里程碑版本,pom中需要加入一些依賴信息,我們為了方便閱讀,之后采取2.1.4.RELEASE版本。剛好,官方的最新文檔也是這個版本。
未完,待續