SpringBoot3正式版將於11月24日釋出:都有哪些新特性?

2022-11-15 12:01:04

從 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 將會要哪些重大的變化。

JAVA 17

對於我們比較關注的第一個最重要的事情就是,Spring Boot3 版本最低支援 Java17,還在萬年 Java8 的同學,該升級就升級了吧,這裡介紹一下關於 Java17 之後的一些重要改變。

record

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

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表示式

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;
};

Pattern Matching 模式匹配

模式匹配可以幫助我們簡化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 密封類

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

另外一個很重要的變化就是本次升級之後,最低只支援 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

Spring Native 也是升級的一個重大特性,支援使用 GraalVM 將 Spring 的應用程式編譯成本地可執行的映象檔案,可以顯著提升啟動速度、峰值效能以及減少記憶體使用。

我們傳統的應用都是編譯成位元組碼,然後通過 JVM 解釋並最終編譯成機器碼來執行,而 Spring Native 則是通過 AOT 提前編譯為機器碼,在執行時直接靜態編譯成可執行檔案,不依賴 JVM。

關於 AOT 技術,在我之前寫過的文章中有提及到:這樣優化Spring Boot,啟動速度快到飛起!

演示

這裡我簡單演示一下怎麼使用,首先我們需要做一些準備工作:

  1. https://www.graalvm.org/downloads/ 下載GraalVM,指定JAVA_HOME,export JAVA_HOME=/Users/user/Desktop/graalvm-ce-java17-22.3.0/Contents/Home
  2. 下載個新一點的 IDEA,比如我使用的是最新的 EAP 版本
  3. 下載個新一點的 JDK,比如使用 JDK17

然後通過 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 的吧),其他的依賴升級如下:

  • Kotlin 1.7+
  • Lombok 1.18.22+ (JDK17 support支援版本)
  • Gradle 7.3+

另外我想說的是,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 版本的遷移指南。

參考:

  1. https://www.baeldung.com/spring-boot-3-spring-6-new
  2. https://blogs.oracle.com/java/post/go-native-with-spring-boot-3-and-graalvm
  3. https://spring.io/blog/2022/05/24/preparing-for-spring-boot-3-0
  4. https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.0-Release-Notes