Java EE 8 的五大最新特性

備受期待的 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:註解驅動型的認證機制。這個全新的安全API包含了三個優秀新功能:身份儲存的抽象層,新的安全上下文,以及一個註解驅動型的認證機制——這使得用 web.xml 文件聲明的方式過時了。最後一個功能我們將會在今天講到。

2.JAX-RS 2.1: 新的響應式客戶端。JAX-RX 2.1 中新的響應式客戶端,融合了響應式編程風格,允許組合端點結果。

3.新的 JSON 綁定 API:新的 JSON 綁定 API,爲 JSON 的序列化和反序列化提供了一個原生的 Java EE 解決方案。

4.CDI 2.0: 在 Java SE 中使用CDI。CDI 2.0 中的這個有趣的新功能允許在 Java SE 中引導 CDI。

5.Servlet 4.0: 服務器推送。Servlet 4.0 中的服務器推送功能使得 servlet 規範和 HTTP/2 保持一致。

準備好了麼?我們開始吧。

1、新的安全 API

Java EE 8 添加的新安全 API 可能是最重要的新特性之一。

這個新 API 的主要動機是簡化、標準化及現代化跨容器和跨實現的安全問題處理方式。現有成效,盡如人意。

Web 認證的配置因爲三個新的註解而實現了現代化,web.xml 從此變得冗餘。具體稍後再說。

新的安全上下文 API 標準化了 servlet 和EJB 容器執行身份驗證的方式。

新的身份儲存抽象層簡化了身份儲存的使用。

讓我們仔細看看這些新增功能中的第一個。


先不說楚楓的這般年紀,能夠踏入元武一重說明了什麼,最主要的是,楚楓在剛剛踏入核心地帶時,明明只是靈武七重,而在這兩個月不到的時間,連跳兩重修爲,又跳過一個大境界,踏入了元武一重,這般進步速度,簡直堪稱變態啊。

“這楚楓不簡單,原來是一位天才,若是讓他繼續成長下去,絕對能成爲一號人物,不過可惜,他太狂妄了,竟與龔師兄定下生死約戰,一年時間,他再厲害也無法戰勝龔師兄。”有人認識到楚楓的潛力後,爲楚楓感到惋惜。

“哼,何須一年,此子今日就必敗,巫九與龔師兄關係甚好,早就看他不順眼了,如今他竟敢登上生死臺挑戰巫九,巫九豈會放過他?”但也有人認爲,楚楓今日就已是在劫難逃。

“何人挑戰老子?”就在這時,又是一聲爆喝響起,而後一道身影自人羣之中掠出,最後穩穩的落在了比鬥臺上。

這位身材瘦弱,身高平平,長得那叫一個猥瑣,金鉤鼻子蛤蟆眼,嘴巴一張牙帶色兒,說話臭氣能傳三十米,他若是當面對誰哈口氣,都能讓那人跪在地上狂嘔不止。

不過別看這位長得不咋地,他在覈心地帶可是鼎鼎有名,劍道盟創建者,青龍榜第九名,正是巫九是也。

“你就是巫九?”楚楓眼前一亮,第一次發現,世間還有長得如此奇葩的人。

巫九鼻孔一張,大嘴一咧,拍着那乾癟的肚子,得意洋洋的道:“老子就是巫九,你挑戰老子?”

“不是挑戰你,是要宰了你。”楚楓冷聲笑道。

“好,老子滿足你這個心願,長老,拿張生死狀來,老子今日在這裏瞭解了這小子。”巫九扯開嗓子,對着下方吼了一聲。

如果他對內門長老這麼說話,也就算了,但是敢這麼跟核心長老說話的,他可真是算作膽肥的,就連許多核心弟子,都是倒吸了一口涼氣,心想這楚楓夠狂,想不到這巫九更狂。

不過最讓人無言的就是,巫九話音落下不久,真有一位核心長老自人羣走出,緩緩得來到了比鬥臺上,左手端着筆墨,右手拿着生死狀,來到了巫九的身前。

“我去,這巫九什麼身份,竟能這般使喚核心長老?”有人吃驚不已,那長老修爲不低,乃是元武七重,比巫九還要高兩個層次,但卻這般聽巫九的話,着實讓人吃驚不已。

“這你就不知道了吧,巫九在前些時日,拜了鍾離長老爲師尊,已正式得到鍾離長老的親傳。”有人解釋道。

“鍾離長老?可是那位性情古怪的鐘離一護?”

“沒錯,就是他。”

“天哪,巫九竟然拜入了他的門下?”

人們再次大吃一驚,那鍾離一護在青龍宗可是赫赫有名,若要是論其個人實力,在青龍宗內絕對能夠排入前三,連護宗六老單打獨鬥都不會是他的對手。

只不過那鍾離一護,如同諸葛青雲一樣,也是一位客卿長老,所以在青龍宗內只是掛個頭銜,什麼事都不管,更別說傳授宗內弟子技藝了,如今巫九竟然能拜入他老人家門下,着實讓人羨慕不已。

“恩怨生死臺,的確可以決鬥生死,但必須要有所恩怨,你們兩個人,可有恩怨?”那位長老開口詢問道。

註解驅動型的認證機制

這個功能主要用於配置 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 安全了。

2、JAX-RS 2.1:新的響應式客戶端

讓我們來看看 JAX-RS 2.1 中新的響應式客戶端,以及它是怎麼融合響應式編程風格的。

響應式方法的核心概念是數據流以及一個通過流來傳播變化的執行模型。一個典型的例子是 JAX-RS 的方法調用。當調用返回時,將在方法調用的結果上執行下一個操作(可能是繼續,完成或錯誤)。

你可以將其視作:數據變成了一個異步的進程管道,後一個進程根據前一個進程的結果執行,然後將其進程的結果傳遞給鏈中的下一個進程。組件化的流讓你得以組合和轉化多個流到一個結果中。

通過調用 rx()Invocation.Builder 實例中用於構造客戶端實例的方法,以此啓用響應式的功能。此方法返回一個攜帶 Response 類型的 CompletionStage 實例。 CompletionStage 接口在 Java 8 中引入,並提出了一些有趣的可能性。

例如,在這個代碼片段中,兩個調用是對不同的端點進行的,然後將結果合併:

CompletionStagecs1 = ClientBuilder.newClient()

.target(“…/books/history”)

.request()

.rx()

.get();

CompletionStagecs2 = 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);

3、新的 JSON 綁定API

現在讓我們來看看下一個優秀的新特性。新的 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 對象的序列化和反序列化提供了廣泛的功能。

4、CDI 2.0:在 Java SE 中使用CDI

現在讓我們繼續看下一個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 結構自動關閉容器。

5、Servlet 4.0:服務器推送

最後,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需要這些資源,但不必從服務器請求它們,因爲它們已經是瀏覽器緩存了。

相关文章