宣布 RESTEasy Reactive
Quarkus 和 RESTEasy 团队非常高兴地宣布,RESTEasy Reactive 集成到 Quarkus 中已进入 Quarkus 的主仓库 [1],并将成为下一个 Quarkus 版本 1.11 的一部分。
我们期待大家对其进行测试并提供尽可能多的反馈。按照 Quarkus 的常规做法,该项目可以作为一组新的扩展来使用。
它是什么?
正如您从名称中可能猜到的那样,这项工作是**新的 JAX-RS 实现**,从头开始编写,以便在我们的通用 **Vert.x** 层上运行,因此是完全**响应式**的,同时还**与 Quarkus 紧密集成**,并因此将许多框架特定的工作(如注解扫描和元模型生成)移至**构建时**。
我为什么应该关心?
最简单的答案是,您可以继续利用广泛使用且非常强大的 JAX-RS API 为您的应用程序公开 REST 层,同时在应用程序可以达到的最大吞吐量方面获得显著改进。应用程序的启动速度也应该稍快一些,内存消耗也稍少一些。
我们的基准测试显示,使用这个新扩展的可衡量性能几乎与我们使用 Quarkus 的 Reactive Routes API(这本身就是一个非常有趣的 API,但通常更底层——更不用说开发者需要学习一个新 API 了)所能达到的性能相同。
此外,与提供基于注解的 REST 层的其他竞争性企业 Java 框架相比,Quarkus 的吞吐量高达其两倍,具体取决于基准测试。
还有哪些其他好处?
如果熟悉的 API 和新扩展大大改进的运行时特性还不够,我们还添加了一些非常令人兴奋且方便的新功能(这些功能不是 JAX-RS 规范的一部分),这些功能要么是社区请求的,要么是我们认为可以改善开发者体验并缓解规范的一些生硬之处。这些新功能包括:
- 默认非阻塞
-
所有端点现在默认在 IO 线程上运行。您可以使用 `@Blocking` 来更改此设置。
- 评分系统
-
在开发模式启动时,应用程序将向您显示端点列表,以及一个性能评分,告诉您为什么您的端点比最优版本慢。这对于找出如何提高 REST 性能非常有帮助。
- 新的请求/响应过滤器设计
-
JAX-RS 过滤器需要实现接口并将上下文对象注入为字段,这既昂贵又不灵活。基于我们在 Quarkus 构建系统中的成功,过滤器现在只是被注解的方法,任何参数都会被自动注入。
public class CustomContainerRequestFilter {
@ServerRequestFilter
public void whatever(UriInfo uriInfo, HttpHeaders httpHeaders, ContainerRequestContext requestContext) {
String customHeaderValue = uriInfo.getPath() + "-" + httpHeaders.getHeaderString("some-input");
requestContext.getHeaders().putSingle("custom-header", customHeaderValue);
}
}
此外,如果过滤器需要执行阻塞操作,那么它们可以返回 `Uni
最后,虽然我们还没有这样做,但这种方法可以轻松地扩展到其他类型的 JAX-RS 提供者,从而完全无需在其代码中使用 `@Context`。
- 新的 `*Param` 注解
-
这些注解用于替代 JAX-RS 的 `@PathParam`, `@QueryParam` 等注解,而无需指定名称。我们选择不重用相同的注解名称是为了避免与 JAX-RS 或其他 EE 规范冲突。
@POST
@Path("params/{p}")
public String params(@RestPath String p,
@RestQuery String q,
@RestHeader int h,
@RestForm String f,
@RestMatrix String m,
@RestCookie String c) {
return "params: p: " + p + ", q: " + q + ", h: " + h + ", f: " + f + ", m: " + m + ", c: " + c;
}
- 更简单的参数和上下文注入
-
使用 RESTEasy Reactive,如果您的参数名称与路径参数相同,您甚至不需要使用 `@PathParam` 或 `@RestPath`,同样,您可以跳过所有已知上下文类型的 `@Context`,这使其更加简单。
@POST
@Path("params/{p}")
public String params(String p, UriInfo info) {
return "params: p: " + p + ", info: " + info;
}
- 新的最佳消息体读取器/写入器
-
如果在服务某个端点时没有调用过滤器和拦截器,您可以使用更高效的消息体写入器,它们直接写入 vert.x,并且不需要反射和注解。
@Provider
public class ServerVertxBufferMessageBodyWriter extends VertxBufferMessageBodyWriter
implements ServerMessageBodyWriter<Buffer> {
@Override
public boolean isWriteable(Class<?> type, ResteasyReactiveResourceInfo target, MediaType mediaType) {
return true;
}
@Override
public void writeResponse(Buffer buffer, ServerRequestContext context) {
context.serverResponse().end(buffer.getBytes());
}
}
- 默认内容类型
-
返回 String 的端点默认生成 text/plain。我们计划对 JSON 和其他类型也这样做。
- CDI 集成
-
所有通过 JAX-RS 的 @Context 的注入都委托给 Arc。这使用户能够获得 Arc 为 Quarkus 所有其他部分带来的构建时注入的优势。
- 每个类的异常映射器
-
在 JAX-RS 规范中,没有办法为特定的 JAX-RS 资源类以不同的方式处理异常——所有异常映射都是全局进行的。
然而,在 RESTEasy Reactive 中,您只需执行类似的操作
@Path("first")
public class FirstResource {
@GET
@Produces("text/plain")
public String throwsVariousExceptions(@RestQuery String name) {
if (name.startsWith("IllegalArgument")) {
throw new IllegalArgumentException();
} else if (name.startsWith("IllegalState")) {
throw new IllegalStateException("IllegalState");
} else if (name.startsWith("My")) {
throw new MyException();
}
throw new RuntimeException();
}
@ServerExceptionMapper({ IllegalStateException.class, IllegalArgumentException.class })
public Response handleIllegal() {
return Response.status(409).build();
}
@ServerExceptionMapper(MyException.class)
public Response handleMy(SimpleResourceInfo simplifiedResourceInfo, MyException myException,
ContainerRequestContext containerRequestContext, UriInfo uriInfo, HttpHeaders httpHeaders, Request request) {
return Response.status(410).entity(uriInfo.getPath() + "->" + simplifiedResourceInfo.getMethodName()).build();
}
}
即可自定义某些资源类的异常处理。
另请注意,`@ServerExceptionMapper` 可以用于以全局方式处理异常,就像 JAX-RS 使用 `ExceptionMapper` 一样。为此,只需将一个不属于资源类的所有者的方法注解为 `@ServerExceptionMapper` 即可。
其他扩展是否与其一起工作?
当然!
与现有 quarkus-resteasy 扩展集成的扩展也与 quarkus-resteasy-reactive 扩展集成。因此,您可以继续使用 *CDI*、*Security*、*Metrics*、*JSON*、*Qute*、*Bean Validation*、*OpenAPI*,并享受出色的开箱即用和完整的开发体验。
我如何尝试?
此外,您还可以使用 Maven Snapshots(因为 Quarkus 快照构建每天都会上传到 Sonatype),通过将版本 `999-SNAPSHOT` 指定为 Quarkus 版本,并使用 `quarkus-bom` 而不是 `quarkus-universe-bom` 作为 BOM。有多种方法可以在 Maven 中启用快照版本。此 StackOverflow 回答显示了可以在每个项目或全局使用的配置。
可用的 RESTEasy Reactive 扩展是:
-
quarkus-resteasy-reactive
-
quarkus-resteasy-reactive-jackson
-
quarkus-resteasy-reactive-jsonb
-
quarkus-resteasy-reactive-qute
这些扩展相当于现有的 *quarkus-resteasy* 扩展,因此,只需在您的应用程序中从 *quarkus-resteasy-jackson* 切换到 *quarkus-resteasy-reactive-jackson*,就可以让您尝试 RESTEasy Reactive 与 Jackson 集成。
此外,如果您需要使用 JAX-RS 客户端(这不是声明式的 MicroProfile REST Client,而是 JAX-RS 规范指定的编程客户端),可以使用 `quarkus-jaxrs-client` 扩展。
我应该注意什么?
-
首先要注意的是,目前这套扩展被认为是实验性的。尽管该项目通过了几乎所有的 JAX-RS TCK,但这只是第一个版本,所以请记住,它可能比典型的久经考验的库有更多的错误,而一些新的 API 和 SPI 可能会被破坏。尽管这是第一个版本,但我们确实希望这项工作在不久的将来成为 Quarkus 的默认 REST 层。
-
如新功能部分所述,请求默认由事件循环线程提供服务。这确保了最大的吞吐量,但也意味着不应该在这些线程上执行任何阻塞操作。如果您使用阻塞 IO(例如,通过 Hibernate Panache 访问数据库),请务必在方法或类上使用 `@Blocking` 注解。这将确保请求由工作线程提供服务。不言而喻,我们也对您关于此默认设置的反馈非常感兴趣。
-
还没有文档。文档将在正式发布 1.11 版本之前添加,并将逐步改进。此电子邮件应包含您入门所需的所有信息,但如果您遇到任何麻烦,我们可以在任何通常的渠道(Zulip 聊天、邮件列表、GitHub Issues、StackOverflow)提供帮助。
缺少哪些 JAX-RS 功能?
我们决定专注于现代 REST 层所需的大多数用户功能,而不是实现 JAX-RS TCK 所需的每项功能。因此,RESTEasy Reactive 不支持 XML,并且该规范的各种晦涩的功能也不支持(例如 *javax.activation.DataSource*、*javax.annotation.ManagedBean*、*javax.ws.rs.core.StreamingOutput*)。
此外,值得注意的是,第一个版本将不包含基于新的 JAX-RS 客户端(有一个专用的扩展)的 MicroProfile REST Client 的实现。这在不久的将来很可能会改变。
下一步是什么?
尽管新扩展将随常规的 *1.11* 版本一起提供,但我们正在考虑发布一个 `1.11.0.Alpha1` 版本,以便您尽可能轻松地尝试新扩展并提供早期反馈。
我们非常期待听到您对 RESTEasy Reactive 在 Quarkus 中的使用及其体验的看法,并计划将其好好利用以进一步改进项目。