從 2018 年 2 月 28 號釋出 Spring Boot 2.0 版本開始,整個 2.X 版本已經經過了 4 年多的時間,累計釋出了 95 個不同的版本,而就在前不久,2.X 系列的也已經迎來了他的最終版本:2.7。
前幾天我還寫了一篇關於 Spring Boot 從 2.1 版本升級到 2.7 的文章,而現在,Spring Boot 3.0 也要來了!
時間就定在本月的 24 號,Spring Boot 將要釋出 3.0 的最終 RELEASE 版本。
截止到現在為止,Spring Boot3已經發布了 6 個版本,累計 5 個里程碑版本,2 個 RC 候選版,現在就跟著我一起看下 Spring Boot 3.0 將會要哪些重大的變化。
對於我們比較關注的第一個最重要的事情就是,Spring Boot3 版本最低支援 Java17,還在萬年 Java8 的同學,該升級就升級了吧,這裡介紹一下關於 Java17 之後的一些重要改變。
record 是在 Java14中引入的,https://openjdk.org/jeps/395 。
以前我們寫一個類需要寫一堆 get、set 方法,後來有了lombok
之後這些都省了,現在 Java 給我們提供了原生的寫法。
public record User() {}
本質上 record 修飾之後的類就是一個 final 類,而且他的父類別不是 Object,也不是餘某軍,而是 java.lang.Record
。
record 類屬性只能宣告在頭部,所有的成員變數都是 public final 的,而且只能宣告靜態屬性,但是可以宣告成員方法和靜態方法。
public record User(String username) {
static int id;
public String getName(){
return this.username;
}
}
text blocks 文字塊是在 Java13 引入的,並且在 Java15 版本成為永久特性,https://openjdk.org/jeps/378。
以前我們複製一個多行的字串到 Java 裡,會自動加上行終止符。
String sql = "SELECT\n" +
"\t* \n" +
"FROM\n" +
"\tsys_user0 \n" +
"WHERE\n" +
"\tuser_name = 'abc'";
而有了文字塊的功能之後,可以幫助我們更方便的定義包含多行文字的字串字面量,他使用三引號作為開始和結束的分隔符。
String sqlBlock = """
SELECT
*
FROM
sys_user0
WHERE
user_name = 'abc'
""";
switch表示式是在 Java12 中引入的,在 Java14 成為永久特性,https://openjdk.org/jeps/361。
升級後的 switch 其實包含兩個特性,一個是允許 case 使用多個常數,另外一個就是有返回值。
新增case x->
語法,使用方面更加簡潔,而且不需要再每個 case 寫一個 break了。
String name = "xiao";
int ret = switch (name) {
case "ai" -> 1;
case "xiao", "xian" -> 2;
default -> 0;
};
模式匹配可以幫助我們簡化instanceof
程式碼。
if (obj instanceof String s) {
System.out.println(s.toLowerCase());
}
還可以在 switch-case 語句使用:
static double getDoubleUsingSwitch(Object o) {
return switch (o) {
case Integer i -> i.doubleValue();
case Float f -> f.doubleValue();
case String s -> Double.parseDouble(s);
default -> 0d;
};
}
sealed 在 Java15中引入,在 Java17成為永久特性。
sealed 密封類的主要作用就是限制類的繼承。
比如我們有 Animal類,Dog 和 Cat 分別繼承它,實現了 eat 方法,他們吃的動作是不一樣的,但是我們不希望人能繼承 Animal,不允許他去繼承動物吃的行為,就可以像下面這樣通過 sealed 和 permits 關鍵字限制它是一個密封類,只有貓和狗能夠繼承它。
需要注意,父類別被定義為 sealed 之後,子類必須是 sealed、 non-sealed 或者 final。
public abstract sealed class Animal permits Cat, Dog {
public abstract void eat();
}
public non-sealed class Dog extends Animal{
@Override
public void eat() {
System.out.println("dog eat");
}
}
public non-sealed class Cat extends Animal{
@Override
public void eat() {
System.out.println("cat eat");
}
}
另外一個很重要的變化就是本次升級之後,最低只支援 Jakarta EE 9,使用 Servlet5.0 和 JPA3.0 規範,不過最新版本RC2已經升級到了 JakartaEE 10,預設使用 Servlet6.0 和 JPA3.1 規範。
有些同學可能連 Jakarta 是什麼都不知道,這個英文單詞是印尼首都雅加達的意思,其實就是我們知道的 JavaEE 改名之後就叫 JakartaEE,比如我們之前的javax.servlet
包現在就叫jakarta.servlet
。
也因此,程式碼中所有使用到比如 HttpServletRequest 物件的 import 都需要修改。
import javax.servlet.http.HttpServletRequest;
改為
import jakarta.servlet.http.HttpServletRequest;
Spring Native 也是升級的一個重大特性,支援使用 GraalVM 將 Spring 的應用程式編譯成本地可執行的映象檔案,可以顯著提升啟動速度、峰值效能以及減少記憶體使用。
我們傳統的應用都是編譯成位元組碼,然後通過 JVM 解釋並最終編譯成機器碼來執行,而 Spring Native 則是通過 AOT 提前編譯為機器碼,在執行時直接靜態編譯成可執行檔案,不依賴 JVM。
關於 AOT 技術,在我之前寫過的文章中有提及到:這樣優化Spring Boot,啟動速度快到飛起!。
這裡我簡單演示一下怎麼使用,首先我們需要做一些準備工作:
JAVA_HOME
,export JAVA_HOME=/Users/user/Desktop/graalvm-ce-java17-22.3.0/Contents/Home然後通過 Spring Initialzr 建立一個新專案,使用最新版本Spring Boot 3.0.0-SNAPSHOT,勾選GraalVM Native Support
,建立好專案之後新增一個測試的Controller
。
@RestController
public class TestController {
@GetMapping("/")
public String hello(){
return "GraalVM ...";
}
}
然後直接執行程式,發現啟動時間花費了大概 1 秒。
然後執行命令,生成映象檔案:
./gradlew nativeCompile
這個過程挺耗時的,花了大概 2 分多鐘才生成好。
最後執行命令:
./build/native/nativeCompile/demo2
我們看到,最終啟動時間是 0.082 秒,快了 10 多倍。
這裡我使用的是 gradle,如果使用 maven 的話,使用如下的命令:
1. mvnw -Pnative native:compile
2. ./target/demo2
Spring Boot 3 最低依賴 Spring6 版本,因此對應的 Spring 版本也該換了(不會有人還在用 Spring2 的吧),其他的依賴升級如下:
另外我想說的是,SpringBoot2.7引入了新的自動裝配方式META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
,原來的寫法spring.factories
在 3.0 版本以下還能相容,3.0 新版本之後,老的寫法spring.factories
不能使用了,中介軟體相關的開發同學要注意了。
其他一些關於設定的變化,Spring MVC 的一些小變化就不說了,更新紀錄檔到時候都可以看到。
最後,如果想升級的話,在新版本釋出之後,會有一個基於Spring Boot 2.7 版本的遷移指南。
參考: