拥抱模块化Java平台:Java 10上的Apache CXF
Java 9版本終于將Project Jigsaw交付給大眾已經(jīng)過去了一年多的時(shí)間。 這是一段漫長(zhǎng)的旅程,但是在那里,所以發(fā)生了什么變化? 這是一個(gè)很好的問題,答案并不明顯和直接。
總的來(lái)說, 拼圖項(xiàng)目是一種顛覆性的變化,其原因很多。 盡管我們幾乎所有現(xiàn)有應(yīng)用程序都將在Java 10上運(yùn)行(很快將由JDK 11取代),幾乎沒有變化,但Jigsaw項(xiàng)目給Java開發(fā)人員帶來(lái)了深遠(yuǎn)的影響:擁抱Java的模塊化應(yīng)用程序平臺(tái)方式。
由于存在無(wú)數(shù)出色的框架和庫(kù),因此將它們轉(zhuǎn)換為Java模塊肯定會(huì)花費(fèi)很多時(shí)間,(很多人永遠(yuǎn)不會(huì)這樣做)。 這條路是棘手的,但是即使在今天,某些事情也已經(jīng)成為可能。 在這篇簡(jiǎn)短的文章中,我們將學(xué)習(xí)如何使用出色的Apache CXF項(xiàng)目,使用最新的JDK 10以真正的模塊化方式構(gòu)建JAX-RS 2.1 Web API 。
從3.2.5版本開始,所有Apache CXF工件的清單都帶有Automatic-Module-Name偽指令。 它不會(huì)使它們成為完整的模塊 ,但這是朝著正確方向邁出的第一步。 因此,讓我們開始吧……
如果您使用Apache Maven作為選擇的構(gòu)建工具,在這里沒有做太多更改,則依賴項(xiàng)的聲明方式與以前相同。
<dependencies><dependency><groupId>org.apache.cxf</groupId><artifactId>cxf-rt-frontend-jaxrs</artifactId><version>3.2.5</version></dependency><dependency><groupId>com.fasterxml.jackson.jaxrs</groupId><artifactId>jackson-jaxrs-json-provider</artifactId><version>2.9.6</version></dependency><dependency><groupId>org.eclipse.jetty</groupId><artifactId>jetty-server</artifactId><version>9.4.11.v20180605</version></dependency><dependency><groupId>org.eclipse.jetty</groupId><artifactId>jetty-webapp</artifactId><version>9.4.11.v20180605</version></dependency> </dependencies>uber-jar或fat-jar打包實(shí)際上不適用于模塊化Java應(yīng)用程序,因此我們必須自己收集模塊,例如,在target / modules文件夾中。
<plugin><artifactId>maven-jar-plugin</artifactId><version>3.1.0</version><configuration><outputDirectory>${project.build.directory}/modules</outputDirectory></configuration> </plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-dependency-plugin</artifactId><version>3.1.1</version><executions><execution><phase>package</phase><goals><goal>copy-dependencies</goal></goals><configuration><outputDirectory>${project.build.directory}/modules</outputDirectory><includeScope>runtime</includeScope></configuration></execution></executions> </plugin>很好,下一步是創(chuàng)建module-info.java并在其中列出我們模塊的名稱(在本例中為com.example.cxf ),并列出其中所有必需的模塊以使其正常運(yùn)行。
module com.example.cxf {exports com.example.rest;requires org.apache.cxf.frontend.jaxrs;requires org.apache.cxf.transport.http;requires com.fasterxml.jackson.jaxrs.json;requires transitive java.ws.rs;requires javax.servlet.api;requires jetty.server;requires jetty.servlet;requires jetty.util;requires java.xml.bind; }您可能會(huì)馬上發(fā)現(xiàn), org.apache.cxf.frontend.jaxrs和org.apache.cxf.transport.http來(lái)自Apache CXF發(fā)行版( 完整列表可在文檔中找到 ),而java.ws.rs是JAX。 -RS 2.1 API模塊。 之后,我們可以像以前一樣繼續(xù)實(shí)現(xiàn)我們的JAX-RS資源。
@Path("/api/people") public class PeopleRestService {@GET@Produces(MediaType.APPLICATION_JSON)public Collection<Person> getAll() {return List.of(new Person("John", "Smith", "john.smith@somewhere.com"));} }這看起來(lái)很簡(jiǎn)單,例如,添加一些辣醬,例如服務(wù)器發(fā)送的事件 ( SSE )和RxJava呢? 從依賴關(guān)系開始,讓我們看看它有多容易。
<dependency><groupId>org.apache.cxf</groupId><artifactId>cxf-rt-rs-sse</artifactId><version>3.2.5</version> </dependency><dependency><groupId>io.reactivex.rxjava2</groupId><artifactId>rxjava</artifactId><version>2.1.14</version> </dependency>同樣,我們不要忘記通過將requires指令添加到這些新模塊來(lái)更新我們的module-info.java 。
module com.example.cxf {...requires org.apache.cxf.rs.sse;requires io.reactivex.rxjava2;requires transitive org.reactivestreams;...}為了簡(jiǎn)單起見,我們的SSE端點(diǎn)只會(huì)廣播通過API添加的每個(gè)新用戶。 這是實(shí)現(xiàn)的代碼段。
private SseBroadcaster broadcaster; private Builder builder; private PublishSubject<Person> publisher;public PeopleRestService() {publisher = PublishSubject.create(); }@Context public void setSse(Sse sse) {this.broadcaster = sse.newBroadcaster();this.builder = sse.newEventBuilder();publisher.subscribeOn(Schedulers.single()).map(person -> createEvent(builder, person)).subscribe(broadcaster::broadcast); }@POST @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) public Response add(@Context UriInfo uriInfo, Person payload) {publisher.onNext(payload);return Response.created(uriInfo.getRequestUriBuilder().path(payload.getEmail()).build()).entity(payload).build(); }@GET @Path("/sse") @Produces(MediaType.SERVER_SENT_EVENTS) public void people(@Context SseEventSink sink) {broadcaster.register(sink); }現(xiàn)在,當(dāng)我們構(gòu)建它時(shí):
mvn clean package并使用模塊路徑運(yùn)行它:
java --add-modules java.xml.bind \--module-path target/modules \--module com.example.cxf/com.example.Starter我們應(yīng)該能夠?qū)ξ覀兊腏AX-RS API進(jìn)行測(cè)試。 使預(yù)期確保一切工作的最簡(jiǎn)單方法是在瀏覽谷歌Chrome瀏覽器的SSE端點(diǎn)的http://本地主機(jī):8686 / API /人/ SSE ,并通過添加一些隨機(jī)的人POST請(qǐng)求,使用老伙計(jì)卷曲從命令行:
curl -X POST http://localhost:8686/api/people \-d '{"email": "john@smith.com", "firstName": "John", "lastName": "Smith"}' \-H "Content-Type: application/json"curl -X POST http://localhost:8686/api/people \-d '{"email": "tom@tommyknocker.com", "firstName": "Tom", "lastName": "Tommyknocker"}' \-H "Content-Type: application/json"在Google Chrome瀏覽器中,我們應(yīng)該能夠看到由服務(wù)器推送的原始SSE事件(它們看起來(lái)不漂亮,但足以說明流程)。
那么,應(yīng)用程序打包呢? Docker和容器當(dāng)然是一個(gè)可行的選擇,但是在Java 9及更高版本中,我們還有另一個(gè)參與者: jlink 。 它將一組模塊及其依賴項(xiàng)組裝并優(yōu)化為一個(gè)自定義的,足夠的運(yùn)行時(shí)映像。 讓我們嘗試一下。
jlink --add-modules java.xml.bind,java.management \--module-path target/modules \--verbose \--strip-debug \--compress 2 \--no-header-files \--no-man-pages \--output target/cxf-java-10-app在這里,我們正在碰壁。 不幸的是,由于我們應(yīng)用程序的大多數(shù)依賴項(xiàng)都是自動(dòng)模塊 ,因此對(duì)于jlink來(lái)說是個(gè)問題,并且從運(yùn)行時(shí)映像運(yùn)行時(shí),我們?nèi)匀槐仨氾@式包括模塊路徑:
target/cxf-java-10-app/bin/java \--add-modules java.xml.bind \--module-path target/modules \--module com.example.cxf/com.example.Starter最終,事實(shí)并非如此可怕。 我們肯定處于JPMS采納的初期,這僅僅是開始。 當(dāng)我們使用的每個(gè)庫(kù),每個(gè)框架都在其工件(JAR)中添加module-info.java ,使它們成為真正的模塊,盡管有許多怪癖 ,然后我們才能宣告勝利。 但是,小小的勝利已經(jīng)在發(fā)生,請(qǐng)成為您的勝利!
該項(xiàng)目的完整資源可在Github上找到 。
翻譯自: https://www.javacodegeeks.com/2018/08/modular-java-platform-apache-cxf.html
總結(jié)
以上是生活随笔為你收集整理的拥抱模块化Java平台:Java 10上的Apache CXF的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 手机被不法分子改成“偷拍神器”,耳机插孔
- 下一篇: 戏剧性拉满 演员刘金怒摔iPhone后仍