此版本仍在开发中,尚未被视为稳定版本。对于最新的稳定版本,请使用 Spring Framework 6.2.6spring-doc.cadn.net.cn

Null 安全

尽管 Java 不允许你用它的类型系统来表达空安全,但 Spring 框架代码库用 JSpecify 注释来声明 API、字段和相关类型的空性 用法。强烈建议阅读 JSpecify 用户指南,以便获取 熟悉这些注释和语义。spring-doc.cadn.net.cn

这种显式 null 安全安排的主要目标是防止NullPointerException在运行时通过 构建时检查,并将显式 null 转换为一种表示可能缺少值的方式。它可用于 通过利用一些工具(NullAway 或支持 null 安全的 IDE)的 Java 注解(如 IntelliJ IDEA 或 Eclipse)和 Kotlin,其中 JSpecify 注解会自动转换为 Kotlin 的 null 安全性spring-doc.cadn.net.cn

NullnessSpring API可以在运行时用于检测 Type usage、字段、方法返回类型或参数。它完全支持 JSpecify 注解、 Kotlin null 安全性、Java 原语类型以及对任何@Nullable注解(无论 包)。spring-doc.cadn.net.cn

使用 JSpecify 注释对库进行注释

从 Spring Framework 7 开始,Spring Framework 代码库利用 JSpecify 注释来公开空安全的 API 和 检查这些 null 安全声明的一致性,其中 NullAway 作为 它的构建。建议根据 Spring Framework(Spring portfolio 项目)对每个库进行 以及与 Spring 生态系统相关的其他库(Reactor、Micrometer 和 Spring 社区项目)一起执行 相同。spring-doc.cadn.net.cn

在 Spring 应用程序中利用 JSpecify 注释

使用支持 null 安全注释的 IDE(例如 IntelliJ IDEA 或 Eclipse)开发应用程序将提供 当不遵守 null-safety 协定时,Java 中的警告和 Kotlin 中的错误,从而允许 Spring 应用程序 开发人员优化其 null 处理以防止NullPointerException在运行时抛出。spring-doc.cadn.net.cn

或者,Spring 应用程序开发人员可以注释他们的代码库,并使用 NullAway 在构建时在应用程序级别强制执行 null 安全。spring-doc.cadn.net.cn

指引

本节的目的是分享一些为明确指定 Spring 相关的 null 性而提出的准则 库或应用程序。spring-doc.cadn.net.cn

JS指定

需要了解的关键点是,默认情况下,类型的 null 性在 Java 中是未知的,并且非 null 类型 用法比可为 null 的用法更频繁。为了保持代码库的可读性,我们通常希望定义 默认情况下,类型用法为非 null,除非对于特定范围标记为可为 null。这正是@NullMarked通常使用 Spring 设置 在软件包级别通过package-info.java文件,例如:spring-doc.cadn.net.cn

@NullMarked
package org.springframework.core;

import org.jspecify.annotations.NullMarked;

在属于包的各种 Java 文件中,可为 null 的类型用法是使用@Nullable.建议将此 annotation 的 intent 指定在 related type 之前。spring-doc.cadn.net.cn

例如,对于字段:spring-doc.cadn.net.cn

private @Nullable String fileEncoding;

或者对于方法参数和返回值:spring-doc.cadn.net.cn

public static @Nullable String buildMessage(@Nullable String message,
                                            @Nullable Throwable cause) {
    // ...
}

重写方法时,不会从超类方法继承 null 注释。这意味着那些 如果您只想覆盖实现并保持相同的 API,则应重复 nullness 注释 nullness 的 null 值。spring-doc.cadn.net.cn

使用数组和 varargs,您需要能够区分元素的 null 性与 数组本身。注意 Java 规范定义的语法,可能是 最初令人惊讶:spring-doc.cadn.net.cn

Java 规范还强制要求使用@Target(ElementType.TYPE_USE)如 JSpecify@Nullable应在最后一个.使用内部或完全限定类型:spring-doc.cadn.net.cn

@NonNull@NullUnmarked很少需要 典型用例。spring-doc.cadn.net.cn

NullAway (空消失)

配置

建议的配置为:spring-doc.cadn.net.cn

  • NullAway:OnlyNullMarked=true为了仅对@NullMarked.spring-doc.cadn.net.cn

  • NullAway:CustomContractAnnotations=org.springframework.lang.Contract这使得 NullAway @Contract知道org.springframework.langpackage 中 可用于表达互补语义,以避免在代码库中出现不相关的 null 安全警告。spring-doc.cadn.net.cn

一个很好的例子@Contract好处是Assert#notnull它被注释 跟@Contract("null, _ → fail").通过上面的配置,NullAway 会明白,在成功的 ininvokecation 时,作为参数传递的值不为 null。spring-doc.cadn.net.cn

或者,可以将NullAway:JSpecifyMode=true启用对完整 JSpecify 语义的检查,包括 泛型类型。请注意,此模式仍在开发中,并且需要 使用 JDK 22 或更高版本(通常与--releaseJava 编译器标志来配置 预期基线)。建议仅在第二步启用 JSpecify 模式,在确保代码库 使用上述建议的配置不会生成警告。spring-doc.cadn.net.cn

警告抑制

在一些有效的用例中,NullAway 会错误地检测到 null 性问题。在这种情况下,建议 要禁止显示相关警告并记录原因,请执行以下作:spring-doc.cadn.net.cn

  • @SuppressWarnings("NullAway.Init")在 field、constructor 或 class 级别可用于避免不必要的警告 由于字段的延迟初始化,例如由于类实现InitializingBean.spring-doc.cadn.net.cn

  • @SuppressWarnings("NullAway") // Dataflow analysis limitation可以在 NullAway 数据流分析不是时使用 能够检测到涉及 null 问题的 path 永远不会发生。spring-doc.cadn.net.cn

  • @SuppressWarnings("NullAway") // Lambda当 NullAway 不考虑执行的断言时,可以使用 在 Lambda 之外,用于 Lambda 中的代码路径。spring-doc.cadn.net.cn

  • @SuppressWarnings("NullAway") // Reflection可用于一些已知的 return 非 null 值,即使 API 无法表示。spring-doc.cadn.net.cn

  • @SuppressWarnings("NullAway") // Well-known map keys可用于Map#get调用是使用已知的键完成的 存在,并且之前插入了非 null 相关值。spring-doc.cadn.net.cn

  • @SuppressWarnings("NullAway") // Overridden method does not define nullness可以在 super class 执行 不定义 null 性(通常当超类来自依赖项时)。spring-doc.cadn.net.cn

从 Spring 空安全注释迁移

Spring 空安全注释@Nullable,@NonNull,@NonNullApi@NonNullFieldsorg.springframework.lang包已被 在 Spring Framework 5 中引入,当时 JSpecify 不存在,最好的选择是利用 JSR 305(休眠的 但广泛使用的 JSR)元注解。从 Spring Framework 7 开始,它们已被弃用,取而代之的是 JSpecify 注释,它提供了重要的增强功能,例如正确 定义的规范、没有拆分包问题的规范依赖项、更好的工具、更好的 Kotlin 集成 以及为更多使用案例更精确地指定 null 性的能力。spring-doc.cadn.net.cn

一个关键的区别是,遵循 JSR 305 语义的 Spring 空安全注释适用于字段, 参数和返回值,而 JSpecify 注释适用于类型用法。这种细微的差异 在实践中非常重要,因为它允许将元素的 null 性与 数组/vararg 的 null性以及定义泛型类型的 null 性。spring-doc.cadn.net.cn

这意味着 array 和 varargs 空安全声明必须更新以保持相同的语义。例如@Nullable Object[] array替换为 Spring 注解需要更改为Object @Nullable [] array使用 JSpecify 附注。varargs 也是如此。spring-doc.cadn.net.cn

此外,还建议将字段和返回值注释移到更靠近类型的位置,例如:spring-doc.cadn.net.cn

  • 对于字段,而不是@Nullable private String field对于 Spring 注解,请使用private @Nullable String field使用 JSpecify 注释。spring-doc.cadn.net.cn

  • 对于返回值,而不是@Nullable public String method()对于 Spring 注解,请使用public @Nullable String method()使用 JSpecify 注释。spring-doc.cadn.net.cn

此外,使用 JSpecify,您无需指定@NonNull当覆盖@Nullable在 super 方法在标记为 null 的代码中“撤消”可为 null 的声明。只需声明它未注释,并将 null 标记为 defaults(除非显式注释为 nullable,否则类型用法被视为非 null)将适用。spring-doc.cadn.net.cn