AICon 深圳站 Keynote 嘉宾官宣!共探AI价值转化的实践路径 了解详情
写点什么

Jakarta EE 11 概览:虚拟线程、Record 和持久化的未来

作者:Otavio Santana

  • 2025-08-05
    北京
  • 本文字数:6526 字

    阅读完需:约 21 分钟

大小:1.88M时长:10:57
Jakarta EE 11概览:虚拟线程、Record和持久化的未来

核心要点

  • Jakarta EE 11 引入了一个新的规范 Jakarta Data,并更新了 16 个规范和一个新的技术兼容性套件(Technology Compatibility Kit)。

  • Jakarta EE 11 的发布有所推迟,主要是为了更新技术兼容性工具包,以改进兼容性测试,随着 Jakarta EE 生态系统的发展和演变,会降低添加更多测试的障碍。

  • Jakarta EE 11 现在需要 Java 17 作为最低版本,并支持 Java 21,从而支持 Java Record 和虚拟线程等新特性。

  • Jakarta EE 12 将具有先进的数据管理能力。

  • Jakarta Persistence、Jakarta Validation 和 Jakarta Expression Language 规范包含了对 Java Record 的支持。

  • Jakarta Concurrency 规范支持在使用 Java 21 时通过修改单个属性来使用虚拟线程。


Jakarta EE 11 已经发布,它提供了额外的特性和能力,以提高软件开发者的生产力并促进进一步的创新。你可能会问:“这个版本有什么新的内容?”以及“接下来会有什么变化?”本文就将回答这些问题。

 

Jakarta EE,以前称为 Java EE,代表 Jakarta 企业版及其相关的规范。它是一个开源的生态系统,包含Jakarta EE 11 Platform中的三十个活跃规范。你可以将规范视为生态系统中的一个单元或组件。

 

例如,Jakarta Persistence是一个处理关系数据库的规范,而Jakarta上下文和依赖注入(Jakarta Contexts and Dependency Injection,CDI)是一个在应用程序中注入依赖项的规范。Jakarta EE 11 Web ProfileJakarta EE 11 Core Profile是 Jakarta EE 11 Platform 的子集,我们将在后文进行介绍。

 

因此,作为一名 Java 开发者,你肯定已经在使用 Jakarta EE 平台了,无论你使用的是 Spring、Quarkus、Helidon、Open Liberty、Payara 还是 Tomcat。例如,当你在应用程序中使用 servlet 时,那么你就正在使用Jakarta Servlet规范。

 

Spring 生态系统将 Jakarta EE 作为依赖项。例如,Spring Data 依赖于 Jakarta Persistence 规范。

 

Jakarta EE 工作组决定推迟 Jakarta EE 11 的发布,以专注于现代化技术兼容性套件(Technology Compatibility Kit,TCK)。进行这项投资的好处包括改进兼容性测试,以及随着 Jakarta EE 生态系统的增长和演变,降低添加更多测试的障碍。

 

现在我们已经提供了 Jakarta EE 生态系统的概述以及它与 Java 社区的关联性,接下来我们讨论一下 Jakarta EE 11 中的新内容。

 

Jakarta EE 11 中的新特性

Jakarta EE 11标志着在简化企业级 Java 方面迈出了重要一步,它重点关注提高开发者的生产力和性能。主要亮点包括引入新的Jakarta Data规范,将 Java 17 作为最低要求,支持 Java 21,以及对十六个规范的更新。TCK 也进行了更新,包括从 Ant 迁移到 Maven,以及从 TestHarness 迁移到 Arquillian。

 

该版本提供了 Java Record 在多个规范中的集成改进,如 Jakarta Persistence、Jakarta ValidationJakarta表达式语言(Jakarta Expression Language),以及在使用 Java 21 时对Jakarta Concurrency中虚拟线程的支持。

 

图 1 显示了 Jakarta EE Platform、Web Profile 和 Core Profile 中的规范。我们可以看到,Jakarta Data 是新加入的规范,另外还包含对十六个规范的更新,如 Jakarta CDI 4.1 和 Jakarta Persistence 3.2。

 

图 1:Jakarta EE Platform、Web Profile 和 Core Profile 中的规范。

 

平台间不断增加的集成策略已经构建起来。Jakarta EE 11 通过移除 Jakarta Managed Beans规范,转而支持 CDI 替代方案,从而发展了上下文和依赖注入功能。此外,该版本还移除了在 Java 17 中被弃用并将在 Java 24 中永久禁用的安全管理器(Security Manager)的所有引用。这为 Jakarta EE 中更加现代化的安全能力腾出了空间。此外,这个版本还移除了一些可选特性,如Jakarta SOAP with AttachmentsJakarta XML BindingJakarta XML Web Services,主要是为了简化新厂商在平台中的体验。

 

Jakarta EE 将 Java 17 作为最低要求,并支持 Java 21,这很自然地期望与 Java SE 中最新且更受欢迎的新特性进行集成和能力扩展,即 Java Record 和虚拟线程。

 

让我们从 Java Record 开始。首先,考虑这个Driver数据结构:

public record Driver(String name, String document, Integer age) {}
复制代码

 

现在,让我们使用 Jakarta Validation 规范提供的注解进行一些校验。我们希望确保namedocument参数不能为空,并指定最小和最大的范围。然后,我们可以断言最小年龄,以确保 16 岁以下的人不能开车。

public record Driver(@NotBlank @Size(min = 5, max = 50)String name, @NotBlank @Size(min = 5, max = 50) String document, @Min(16)Integer age) {}
复制代码

 

借助 Jakarta Persistence,我们可以将 Java Record 用作嵌入式类和 ID。然而,规范不支持 Java Record 和实体。我们现在可以使用 @Embeddable 注解更有效地组织代码结构,特别是不可变部分。例如,考虑一个通常不会改变的地址,但如果它确实改变了,那么地址的所有属性,即城市、街道和邮政编码都需要改变。下面的代码展示了 Java Record 与 Jakarta Persistence 的用法示例:

@Embeddablepublic record Address(String street, String city, String zipCode) {}
@Entitypublic class Customer {
@Id @GeneratedValue private Long id;
private String name;
@Embedded private Address address;
}
复制代码

我们也可以在复合键中使用@Embedded注解。因此,可以在最新的 Jakarta EE 项目中使用它。例如,给定一个订单项,其复合键组合了订单和产品,我们现在可以将这个结构作为一个 Record 来使用,如下面的代码所示。

@Embeddablepublic record OrderItemId(Long orderId, Long productId) implements Serializable {}
@Entitypublic class OrderItem {
@EmbeddedId OrderItemId id;
int quantity;
@ManyToOne(fetch = FetchType.LAZY) @MapsId("orderId") Order order;}
@Entitypublic class Order {
@Id @GeneratedValue Long id;
String customerName;
@OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true) List<OrderItem> items;}
复制代码

在 Jakarta EE 11 中,我们还可以利用虚拟线程。Jakarta Concurrency 规范提供了一种直接的方法来在你的代码中启用虚拟线程。这是通过在@ManagedExecutorDefinition注解中简单地设置一个布尔标志来实现的。下面的示例代码展示了创建两个 CDI 标识符,其中一个使用虚拟线程,另一个使用平台线程。

@Qualifier@Retention(RUNTIME)@Target({ FIELD, METHOD, PARAMETER, TYPE })public @interface WithVirtual {}@Qualifier@Retention(RUNTIME)@Target({ FIELD, METHOD, PARAMETER, TYPE })public @interface WithoutVirtual {}@ManagedExecutorDefinitions({    @ManagedExecutorDefinition(        name = "java:module/concurrent/ExecutorWithVirtual",        context = "java:module/concurrent/ContextWithVirtual",        qualifiers = WithVirtual.class,        virtual = true,        maxAsync = 10,        hungTaskThreshold = 10000    ),    @ManagedExecutorDefinition(        name = "java:module/concurrent/ExecutorWithoutVirtual",        context = "java:module/concurrent/ContextWithoutVirtual",        qualifiers = WithoutVirtual.class,        virtual = false,        maxAsync = 5,        hungTaskThreshold = 20000    )})@ContextServiceDefinition(    name = "java:module/concurrent/ContextWithVirtual",    propagated = {SECURITY, APPLICATION})@ContextServiceDefinition(    name = "java:module/concurrent/ContextWithoutVirtual",    propagated = {SECURITY, APPLICATION})public class ConcurrencyConfig {}@ApplicationScopedpublic class TaskService {    @Inject    @WithVirtual    ManagedExecutorService virtualExecutor;    @Inject    @WithoutVirtual    ManagedExecutorService platformExecutor;    public void runWithVirtual() {        virtualExecutor.execute(() ->            System.out.println("[VIRTUAL] running in: " + Thread.currentThread())        );    }    public void runWithPlatform() {        platformExecutor.execute(() ->            System.out.println("PLATFORM] running in: " + Thread.currentThread())        );    }}
复制代码

 

最后,Jakarta Data,即 Jakarta EE 11 中的新规范,提供了持久层的能力,使得使用单一接口访问 SQL 和 NoSQL 数据库变得更加容易。这对于那些熟悉 Spring Data 的人来说是非常熟悉的。

 

借助 Jakarta Data,你可以生成查询、数据修改和两种类型的分页,即偏移量和游标。通过使用接口和几个简单的指令,提供商将为你完成后续的转换工作。借助内置的 repository 接口,你可以生成自己的接口,Jakarta Data 能从继承层级接口或自定义接口进行扩展,从而能够从头开始产生动作和术语。

 

例如,下面的代码定义了一个CarRepository接口,它从内置的BasicRepository接口进行扩展。因此,CarRepository提供了多个动作方法,如保存、删除等。

@Repositorypublic interface CarRepository extends BasicRepository<Car, Long> {  List<Car> findByType(CarType type);  Optional<Car> findByName(String name);}@InjectCarRepository repository;...Car ferrari = Car.id(10L).name("Ferrari").type(CarType.SPORT);repository.save(ferrari);
复制代码

当然,有些情况下你可以定义自己的术语,从而能够深入支持领域驱动设计(DDD)和通用语言。例如,你可以创建你的 Car 集合并定义其动作:

@Repositorypublic interface Garage {  @Insert  Car park(Car car);}
复制代码

 

Jakarta Data 还引入了注解,我们可以用它们来定义数据库操作,如@Insert@Update@Delete@Find@Save注解。此外,它带来了三种在仓库上生成查询的方法:

  • 通过方法查询(Query by method),我们可以定义一个基于传统命名约定的查询,这类似于 Spring Data,例如通过类型查找Product

List<Product> findByType(ProductType type);
复制代码
  • @Find注解允许我们编写一个与参数匹配的查询。在这个例子中,注解将根据其类型返回一个Stream<Car>的实例。

@FindStream<Car> type(@By("type") CarType type);
复制代码
  • 借助 Jakarta Data 查询语言(Jakarta Data Query Language,JDQL),我们可以使用基于文本的查询,该语言是 Jakarta 持久化查询语言(Jakarta Persistence Query Language,JPQL)的一个子集。

 @Query("where author.name = :author order by title")  List<Book> findByAuthorSortedByTitle(String author);
复制代码

 

此外,通常需要大量代码的分页功能可以使用 Jakarta Data 来进行简化,因为它定义了返回类型并包含了PageRequest接口。下面的代码提供了两个示例用法,一个使用偏移量分页,另一个使用基于游标的分页。

@Repositorypublic interface CarRepository extends BasicRepository<Car, Long> {Page<Car> findByTypeOrderByName(CarType type, PageRequest pageRequest);@Find@OrderBy(_Car.NAME)@OrderBy(_Car.VIN)CursoredPage<Car> type(CarType type, PageRequest pageRequest);}
复制代码

在这篇关于 Jakarta EE 11 的概述中,你可以看到对 Java Record、虚拟线程以及 Jakarta Data 新的持久化能力的改进支持。但是 Jakarta EE 的未来会是什么样子的呢?是否有 Jakarta EE 12 的计划呢?是的,我们将在下一节中进行介绍。 

Jakarta EE 12 的目标是一致性和配置

在 Jakarta EE 11 最近发布之后,Jakarta EE 12的工作就已经开始了,草案计划包括向 Web Profile 添加新规范,它的目标发布日期是 2026 年 7 月。

 

需要注意的是,这个计划仍在开发中,并且像任何软件开发项目一样,在开发过程中可能会被推迟或修改。图 2 显示了 Jakarta EE 12 规范的状态。


图 2:Jakarta EE 12 提出的规范及其相应的版本。

 

正如 IBM 的高级杰出工程师、Hibernate的创始人Gavin King在他的社交媒体上所说,我们对下一个 Jakarta EE 版本中的持久化满怀期待。如果 Jakarta EE 12 可以有一个昵称的话,我们可以将其定义为数据时代(Data Age),它将包括 Jakarta EE 生态系统中的多语言持久化。它将使 Jakarta 能够同时“支持”SQL 和 NoSQL,这要归功于Jakarta NoSQL 1.1的引入。

@InjectTemplate template;...Car ferrari = Car.id(1L)        .name("Ferrari")        .type(CarType.SPORT);template.insert(ferrari);Optional<Car> car = template.find(Car.class, 1L);template.delete(Car.class, 1L);
复制代码

 

此外,Jakarta Data 还进行了多项改进,包括对元模型的增强,使其能够动态地改变参数。例如,设想一个场景,我们有一个 REST 资源,它允许你定义参数,包括查询条件。

 

在这种情况下,我们会有一个ProductSearchFilter类,从而可以设置返回基于给定条件的Product。正如你看到的,元数据生成了流畅的 API 条件。

public class ProductSearchFilter {    @QueryParam("type")    private String type;    @QueryParam("minPrice")    private BigDecimal minPrice;    @QueryParam("maxPrice")    private BigDecimal maxPrice;    @QueryParam("nameContains")    private String nameContains;    public Optional<String> type() {        return Optional.ofNullable(type);    }    public Optional<BigDecimal> minPrice() {        return Optional.ofNullable(minPrice);    }    public Optional<BigDecimal> maxPrice() {        return Optional.ofNullable(maxPrice);    }    public Optional<String> nameContains() {        return Optional.ofNullable(nameContains);    }}
@GET public List<Product> find(@BeanParam ProductSearchFilter filter) { List<Restriction<Product>> conditions = new ArrayList<>(); filter.type().ifPresent(value -> conditions.add(_Product.type.equalTo(ProductType.valueOf(value))) ); filter.minPrice().ifPresent(value -> conditions.add(_Product.price.greaterThan(value)) ); filter.maxPrice().ifPresent(value -> conditions.add(_Product.price.lessThan(value)) ); filter.nameContains().ifPresent(value -> conditions.add(_Product.name.contains(value)) ); return products.findAll(Restriction.all(conditions)); }
复制代码

 

对于多语言持久化,我们还有一个新的规范,即Jakarta Query,它的目标是定义面向对象查询语言的单一查询,该查询语言旨在与 Jakarta Persistence、Jakarta Data 和 Jakarta NoSQL 协同使用。

 

将所有持久化规范进行整合是很有意义的。我们已经通过 Jakarta Data 迈出了第一步,现在我们将通过新的 Jakarta Query 规范迈出下一步。

 

构建这个规范很具挑战性,这主要是由于如今持久化结构性存储的多样性,以及 Java 应用程序(采用面向对象范式)和数据库(通常不支持面向对象范式)之间的阻抗不匹配。

 

例如,如果我们有两个类,它们之间存在经典的关联关系,即CarDriver

public class Car {private String plate;private Driver driver;}public class Driver {private String id;private String name;}
复制代码

 

设想一个场景,我们要返回car.driver()的值。当我们使用数据库时,这可能意味着要有一个 JOIN 查询、一个子文档、一个用户定义的类型或一个图关系。因此,这个新规范需要有一个通用查询,同时也要具有扩展性,以支持规范兼容的多种数据库。

 

在本文中,我们已经看到了 Jakarta EE 11 发布的多个特性,以及平台的未来发展方向。它包括了在数据方面的明显转变,超越了云原生应用程序。Jakarta EE 是 Eclipse Foundation 旗下的开源项目,像以前一样,你可以加入并参与进来。这主要是因为,正如Peter Drucker所说,“预测未来的最好方式就是创造它”。因此,让我们都参与进来,共同塑造企业级 Java。

 

原文链接:

Jakarta EE 11 Overview: Virtual Threads, Records, and the Future of Persistence

2025-08-05 11:301

评论

发布
暂无评论

看透react源码之感受react的进化

goClient1992

React

从react源码看hooks的原理

flyzz177

React

爆肝整理高频js手写题请查收

helloworld1024fd

JavaScript

深度讲解React Props

夏天的味道123

React

深度理解Redux原理并实现一个redux

夏天的味道123

React

PaddleBox:百度基于GPU的超大规模离散DNN模型训练解决方案

百度Geek说

企业号十月 PK 榜 PaddlePaddl 模型训练框架 大规模离散模型

Vue是怎样监听数组的变化的?

bb_xiaxia1998

Vue

前端高频手写题自测,你能做出几道

helloworld1024fd

JavaScript

应用实践:Paddle分类模型大集成者[PaddleHub、Finetune、prompt]

汀丶人工智能

nlp 文本分类 关系抽取 命名实体识别 11月月更

华为云从入门到实战 | 负载均衡服务原理

TiAmo

华为 华为云 10月月更

从recat源码角度看setState流程

flyzz177

React

京东云开发者|提高IT运维效率,深度解读京东云AIOps落地实践

京东科技开发者

人工智能 异常检测 时序架构 运维‘

Wallys//IPQ8072/IPQ8074/IPQ8072A/IPQ8074A/HighPower 802.11ax SoC for Routers, Gateways and Access Points

Cindy-wallys

802.11AX IPQ8072 IPQ8074 HighPower

React-Hooks源码深度解读

goClient1992

React

11月月更开启啦!冬天到了,不写点东西暖暖身子吗?

InfoQ写作社区官方

热门活动 11月月更

面试官:请实现Javascript发布-订阅模式

helloworld1024fd

JavaScript

React源码分析(一)Fiber

goClient1992

React

怎样刷vue面试题

bb_xiaxia1998

Vue

探究Presto SQL引擎(4)-统计计数

vivo互联网技术

浏览器 presto 引擎

云小课|MRS基础原理之MapReduce介绍

华为云开发者联盟

大数据 华为云 企业号十月 PK 榜

Vue.$nextTick的原理是什么-vue面试进阶

bb_xiaxia1998

Vue

react的useState源码分析

flyzz177

React

Docker不香吗?为什么还要用k8s

源字节1号

微信小程序 软件开发 前端开发 后端开发

案例解读华为隐私计算产品TICS如何实现城市跨部门数据隐私计算

华为云开发者联盟

云计算 华为云 隐私计算 企业号十月 PK 榜

这可能是你需要的vue考点梳理

bb_xiaxia1998

Vue

以开发之名 | 小红书:用年轻人的方式开发年轻人喜欢的应用

HarmonyOS SDK

视频超分 小红书

珠宝加工厂:我的成本下降空间在哪里

华为云开发者联盟

云计算 物联网 华为云 企业号十月 PK 榜

【C语言】前言关键字

謓泽

11月月更

关于“React 和 Vue 该用哪个”我真的栓Q

京东科技开发者

Vue 前端 Vue 3 VUE 3.0 源码 react rout

高频js手写题之实现数组扁平化、深拷贝、总线模式

helloworld1024fd

JavaScript

没想到GoFrame的gcache天然支持缓存淘汰策略

王中阳Go

Go golang 高效工作 学习方法 11月月更

Jakarta EE 11概览:虚拟线程、Record和持久化的未来_编程语言_InfoQ精选文章