备受期待的 Java Enterprise Edition 8 发布了两个令人兴奋的全新 API (JSON-Binding 1.0 和 Java EE Security 1.0),并改进了现有的API(JAX-RS 2.1,Bean Validation 2.0,JSF 2.3,CDI 2.0,JSON-P 1.1,JPA 2.2 以及 Servlet 4.0)。这是 Oracle 的企业级 Java 平台近四年以来第一次发布新版本,其中包含了数百项新特性、功能升级和错误修复。
哪些新特性是最棒的?我试图在这篇文章中回答这个非常主观的问题。
准备好了么?我们开始吧。
1、新的安全 API
Java EE 8 添加的新安全 API 可能是最重要的新特性之一。
这个新 API 的主要动机是简化、标准化及现代化跨容器和跨实现的安全问题处理方式。现有成效,尽如人意。
让我们仔细看看这些新增功能中的第一个。
这个功能主要用于配置 Web 安全。旧的方式要求在 web.xml 文件中声明。
得益于 HttpAuthenticationMechanism 接口,我们不必再使用旧方式。HttpAuthenticationMechanism 接口代表了一个 HTTP 身份验证,并附带了三个内置的 CDI 支持的实现,每个实现都代表了可配置的三种 Web 安全方式之一。
使用以下的注解之一触发特定的实现。
@BasicAuthenticationMechanismDefinition @FormAuthenticationMechanismDefinition @CustomFormAuthenticationMechanismDefinition
它们复制了 servlet 容器中已有的传统 HTTP 基本认证,表单和基于表单的自定义认证功能。
举个例子来说,若要启用基本认证,所要做的仅是把 BasicAuthenticationMechanismDefinition 注解添加到你的 servlet 中。
@BasicAuthenticationMechanismDefinition(realmName="${'user-realm'}") @WebServlet("/user") @DeclareRoles({ "admin", "user", "demo" }) @ServletSecurity(@HttpConstraint(rolesAllowed = "user")) public class UserServlet extends HttpServlet { ... }
现在你可以抛弃 XML 配置,并使用上面的注解来驱动 Web 安全了。
让我们来看看 JAX-RS 2.1 中新的响应式客户端,以及它是怎么融合响应式编程风格的。
响应式方法的核心概念是数据流以及一个通过流来传播变化的执行模型。一个典型的例子是 JAX-RS 的方法调用。当调用返回时,将在方法调用的结果上执行下一个操作(可能是继续,完成或错误)。
你可以将其视作:数据变成了一个异步的进程管道,后一个进程根据前一个进程的结果执行,然后将其进程的结果传递给链中的下一个进程。组件化的流让你得以组合和转化多个流到一个结果中。
通过调用 rx()Invocation.Builder 实例中用于构造客户端实例的方法,以此启用响应式的功能。此方法返回一个携带 Response 类型的 CompletionStage 实例。 CompletionStage 接口在 Java 8 中引入,并提出了一些有趣的可能性。
例如,在这个代码片段中,两个调用是对不同的端点进行的,然后将结果合并:
CompletionStage<Response> cs1 = ClientBuilder.newClient() .target(".../books/history") .request() .rx() .get(); CompletionStage<Response> cs2 = ClientBuilder.newClient() .target(".../books/geology") .request() .rx() .get(); cs1.thenCombine(cs2, (r1, r2) -> r1.readEntity(String.class) + r2.readEntity(String.class)) .thenAccept(System.out::println);
现在让我们来看看下一个优秀的新特性。新的 JSON 绑定 API为 JSON 的序列化和反序列化提供了一个原生的 Java EE 解决方案。
在此之前,如果你想对 JSON 进行序列化和反序列化,则必须依赖类似 Jackson 或是 GSON 这样的第三方 API。现在不一样了,使用新的 JSON 绑定 API,你可能需要的所有功能都有了原生支持。
从 Java 对象生成一个 JSON 文档非常简单。只需要调用 toJson() 方法,并传递你想要序列化的实例即可。
String bookJson = JsonbBuilder.create().toJson(book);
将 JSON 文档反序列化为 Java 对象也同样简单。只需要将 JSON 文档和目标类传递给 fromJson 方法,即可获得 Java 对象。
Book book = JsonbBuilder.create().fromJson(bookJson, Book.class);
但其功能不止于此。
可以通过注解字段,JavaBean 方法和类来自定义默认的序列化和反序列化行为。
例如,你可以使用 @JsonbNillable 来自定义空处理和 @JsonbPropertyOrder 注解来自定义在类级别指定的属性顺序。 也可以使用 @JsonbNumberFormat() 注解指定数字格式,并使用 @JsonbProperty() 注解更改字段的名称。
@JsonbNillable @JsonbPropertyOrder(PropertyOrderStrategy.REVERSE) public class Booklet { @JsonbProperty("cost") @JsonbNumberFormat("#0.00") private Float price; }
或者,你可以选择使用运行时自定义构建器 JsonbConfig 来处理自定义:
JsonbConfig jsonbConfig = new JsonbConfig() .withPropertyNamingStrategy( PropertyNamingStrategy.LOWER_CASE_WITH_DASHES) .withNullValues(true) .withFormatting(true); Jsonb jsonb = JsonbBuilder.create(jsonbConfig);
无论哪种方式,JSON 绑定 API 都为 Java 对象的序列化和反序列化提供了广泛的功能。
现在让我们继续看下一个API。 CDI 2.0 API。该版本拥有许多新功能,其中一个较为有趣的功能是在 Java SE 应用程序中引导 CDI 的能力。
要在 Java SE 中使用 CDI,必须明确引导 CDI 容器。这是通过调用 SeContainerInitializer 抽象类的静态方法 newInstance() 来实现的。此方法返回一个 SeContainer 实例,该实例是 CDI 运行时的句柄,你可以使用该实例执行 CDI 解析,如代码片段中所示。它可以访问 BeanManager,是 CDI 的核心入口点。
SeContainer seContainer = SeContainerInitializer.newInstance().initialize(); Greeting greeting = seContainer.select(Greeting.class).get(); greeting.printMessage("Hello World"); seContainer.close();
传递想要检索和使用的 bean 的类名给 select() 方法,以此检索 CDI bean。
可以添加 Interceptors, Extensions, Alternatives, Properties, 和 Decorators 来进一步配置 SeContext 。
.enableInterceptors() .addExtensions() .selectAlternatives() .setProperties() .enableDecorators()
在 SeContainer 上调用 close() 方法手动关闭容器,因为 SeContainer 扩展了 AutoCloseable 接口,也可以使用 try-with-resources 结构自动关闭容器。
最后,Servlet 4.0 中的服务器推送功能。这使得 servlet 规范和HTTP/2 保持一致。
为了理解这个特性,你首先需要知道服务器推送是什么。
服务器推送是HTTP/2协议中的许多新功能之一,旨在通过预测客户端资源需求,将这些资源推送到浏览器的缓存中,客户端发送网页请求并接收服务器的响应时,它需要的资源已经在缓存中。这是一项提高网页加载速度的性能增强功能。
这一功能在 Servlet 4.0 中是如何暴露的?
在 Servlet 4.0 中,服务器推送功能通过 PushBuilder 实例暴露,该实例从 HttpServletRequest 实例中获得。
看看这段代码片段。你可以看到,通过 path() 方法在 PushBuilder 实例上设置了 header.png 的路径,并通过调用 push() 将其推送到客户端。当方法返回时,路径和条件头将被清除,以便构建器重用。接着将 menu.css 文件,JavaScript 文件 ajax.js 推送到客户端。
protected void doGet(HttpServletRequest request, HttpServletResponse response) { PushBuilder pushBuilder = request.newPushBuilder(); pushBuilder.path("images/header.png").push(); pushBuilder.path("css/menu.css").push(); pushBuilder.path("js/ajax.js").push(); // Return JSP that requires these resources }
Servlet的 doGet() 方法执行完毕时,资源将会到达浏览器。从JSP生成的HTML需要这些资源,但不必从服务器请求它们,因为它们已经是浏览器缓存了。
原文链接: dzone 翻译:ImportNew.com -enigma
译文链接:[]