使用 Spring Boot 4 構建空安全應用程式

工程 | Sébastien Deleuze | 2025年11月12日 | ...

這是 Road to GA 系列中的一篇新博文,這次分享了 Spring 組合中空安全支援的最新狀態,作為我之前相關博文 使用 JSpecify 和 NullAway 在 Spring 應用程式中實現空安全 以及相關 Spring I/O 演講的後續。

我們正在修復“十億美元的錯誤”嗎?

是的,我們正在做!這裡的“我們”指的是參與 JSpecify 專案的組織、Spring 團隊以及您,將升級到 Spring Boot 4 的 Spring 開發者。

話雖如此,我並不認為“十億美元的錯誤”是 Tony Hoare 道歉的空引用(null reference)的發明。我認為真正的錯誤是沒有在型別系統中明確表達它,因為正是這種空(nullability)的隱式性導致了生產環境中如此多的 NullPointerException。如果將其明確化,空性就成為了一種零成本抽象,用於表達值可能不存在的情況,並且與現有 API 向後相容。

JSpecify 旨在提供 一套註解,以及相關的 文件,允許 Java 程式碼庫明確表達其 API 的空性。一個關鍵點是這些註解不與特定工具繫結,它們被設計為透過詳細的 規範 允許多個一致的實現。

一項巨大的協作努力

隨意用 @Nullable 註解一些 API 很容易,但用一個作為構建過程一部分的檢查器來完整註解現有程式碼庫,並將空性不一致視為編譯錯誤則更具挑戰性。這是 Spring 團隊幾個月前開始的艱鉅任務。

今天,我很高興地宣佈,我們作為一個團隊已經實現了我們的目標,使 Spring 組合中的大多數 API 具備空安全,以便授權 Spring 開發者減少或消除生產環境中 NullPointerException 的風險。

更具體地說,以下專案現在提供空安全 API:

  • Spring Boot 4.0
  • Spring Framework 7.0
  • Spring Data 4.0
  • Spring Security 7.0
  • Spring Batch 6.0
  • Spring Kafka 4.0
  • Spring Integration 7.0
  • Spring GraphQL 2.0
  • Spring Web Services 5.0
  • Spring AMQP 4.0
  • Spring Shell 4.0
  • Spring Kafka 4.0
  • Spring Plugin 4.0
  • Spring HATEOAS 3.0
  • Spring Modulith 2.0
  • Spring Vault 4.0
  • Spring Cloud Commons 5.0
  • Spring Cloud Gateway 5.0
  • Micrometer 1.16
  • Micrometer Tracing 1.6
  • Context Propagation 1.2
  • Reactor 2025.0

一些 Spring 專案尚未提供空安全 API,但計劃在近期實現

  • Spring AI(計劃在 2.0 版本中實現)
  • Spring Session
  • Spring LDAP
  • Spring gRPC(暫定計劃在 1.0 版本中實現)
  • Spring Cloud 的其餘部分(暫定計劃在 2026.0 版本中實現)

值得注意的是,Spring 使用的一些依賴項也已使用 JSpecify 註解來標記其 API,並且很可能還會有更多依賴項這樣做

  • JUnit
  • GraphQL
  • Caffeine

Kotlin 2,Spring Framework 7 和 Spring Boot 4 的新基線,會自動將 JSpecify 註解轉換為 Kotlin 的空性。再見 平臺型別,包括泛型,Spring API 現在看起來就像是原生用 Kotlin 編寫的!

Spring API 的空安全用法

受益於 Spring 空安全的最簡單方法是升級到 Spring Boot 4 並使用支援 JSpecify 註解的 IDE,以便向開發者提供關於如何處理從 Spring API 使用中檢測到的潛在空性問題的反饋。

JetBrains 自 JSpecify 小組成立以來就是其成員,IntelliJ IDEA 團隊一直在開發一流的 JSpecify 支援,該支援將在 IntelliJ IDEA 2025.3(預計在幾天內釋出)中提供。

JetBrains 產品專家 Andrei Kogun 分享了更多細節:

JSpecify 的採用是 Java 生態系統如何透過協作不僅建立了一個新標準,而且還建立了一個開發者在日常工作中真正受益的標準的一個很好的例子。

IntelliJ IDEA 很早就添加了對 JSpecify 的支援——早在規範的初稿出現時就開始了——此後我們一直在改進它。今天,它包括對泛型型別和複雜資料流分析的全面覆蓋,使空性檢查既強大又直觀。社群反饋以及從將其程式碼庫遷移到 JSpecify 的團隊的合作,一直是塑造這種支援的關鍵。

從 IntelliJ IDEA 2025.3 開始,當 classpath 中存在 JSpecify 註解時,IDE 會自動優先選擇它們,甚至優先於 JetBrains 自己的註解。這意味著當你修復空性問題時,這些註解不僅會被識別,還會透過快速修復和重構自動生成。

例如,請看下面的截圖,IntelliJ IDEA 警告一個潛在的空性問題,並指導開發者如何處理它。

IntelliJ IDEA warnings and guidance

Spring Tools 團隊還在致力於 在 Eclipse 和 VSCode 中自動配置 JSpecify,利用 Eclipse 平臺中對空性註解的現有支援。

這些 IDE 檢查將大大降低執行時 NullPointerException 的風險。

空安全應用程式

如果你的目標不是減少而是消除應用程式在執行時發生 NullPointerException 的幾乎所有可能性,你可以使用 JSpecify 註解來標記你的 Spring Boot 應用程式,我們強烈建議使用像 NullAway 這樣的構建時空性檢查器。請注意,這比上一節描述的僅僅消費空安全 API 要複雜得多,因此在開始之前請務必完全理解其影響。

Spring 團隊一直與加州大學河濱分校計算機科學與工程教授 Manu Sridharan 合作,他也是 NullAway 的負責人。他分享了以下想法:

NullAway 團隊很高興能支援 JSpecify 標準。我們渴望繼續與 Spring 團隊和其他人合作,以提高整個 Java 生態系統的空安全。

要使您的應用程式空安全,您通常會使用 @NullMarked 註解包,並使用 @Nullable 指定可空型別用法,更多詳情請參見 Spring Framework 空安全文件中的相關指南

要啟用構建時檢查,您需要在構建中配置 NullAway。請參閱 jspecify-nullaway-demo 以獲取 build.gradlebuild.gradle.ktspom.xml 的具體示例。

請注意,NullAway JSpecify 模式需要最新版本的 javac,因此如果可以的話,我們建議使用 Java 25,否則大多數 JDK 21.0.8+ 發行版(Oracle JDK 除外)都應該支援 -XDaddTypeAnnotationsToSymbol=true 標誌,這將允許 NullAway 正常工作。此標誌的 Java 17 後向移植版本可能在未來可用。如果像 Spring 一樣,您需要保留 Java 17 基線,您可以使用 Java 25 工具鏈,並按照 jspecify-nullaway-demo 所示,使用 javac 選項 --release 17 配置您的 Maven 或 Gradle 構建。

請注意,org.springframework.lang 包中以前的 Spring 可空性註解現在已棄用,轉而使用 JSpecify 註解。

潛在的未來改進

無法附加型別註解錯誤

Spring 團隊已努力將此類副作用降至最低,但對於像 Java 25 這樣的最新 Java 版本,當匯入一個在 classpath 中不存在的型別上帶有 JSpecify @Nullable@NonNull 等型別使用註解的類時,javac 可能會報告錯誤。

目前正在進行討論和工作,希望能透過恢復 javac 的惰性行為來消除此副作用,使其不再觸發此類錯誤;如果不可能,則將其降級為警告,並提供某種方式來抑制它。有關更多詳細資訊,請參閱 https://github.com/openjdk/jdk/pull/28018

@SuppressWarnings(“nullness”)

JSpecify 工作組正在討論標準化一種與工具無關的方式來抑制空性檢查,例如當它們不相關時。您可以跟蹤 https://github.com/jspecify/jspecify/issues/55 相關問題。

NullAway 改進

NullAway JSpecify 模式仍在發展中,因此請務必檢視或報告 相關問題。例如,在使用 lambda 的 Spring 或 Reactor API 時,您可能會遇到 NullAway#1290。目前,您可以使用 @SuppressWarnings("NullAway") 抑制相關警告。

我們還期待對 JDK API 空性進行改進,請參閱 NullAway#950 相關問題。

結論

我喜歡這些空安全改進之處在於,它們促使 Spring 程式碼庫進行了大量改進,從而提高了其質量和健壯性。而且您可以自由決定要利用它們多少。如果您不關心,可以關閉相關警告;在您的 IDE 中修復它們以降低 NullPointerException 的風險;甚至更進一步,使您的應用程式實現空安全。

此外,正如 Spring 工作所示,這在現有專案上是可行的,而不會破壞您的 API,因為您將在概念上用空性資訊增強當前型別。

我們希望看到更多的開源庫採用 JSpecify,並且我們認為 JSpecify 的採用將有助於 JVM 生態系統和您的應用程式為未來支援 Null-Restricted 和 Nullable Types 做好準備,這可能需要數年才能在實踐中實現(作為非預覽功能可用,庫升級其基線,應用程式也這樣做),並帶來額外的執行時效率優勢。

獲取 Spring 新聞通訊

透過 Spring 新聞通訊保持聯絡

訂閱

領先一步

VMware 提供培訓和認證,助您加速進步。

瞭解更多

獲得支援

Tanzu Spring 提供 OpenJDK™、Spring 和 Apache Tomcat® 的支援和二進位制檔案,只需一份簡單的訂閱。

瞭解更多

即將舉行的活動

檢視 Spring 社群所有即將舉行的活動。

檢視所有