java与java ee_RxJava + Java8 + Java EE 7 + Arquillian =幸福
java與java ee
微服務是一種體系結構樣式,其中每個服務都實現為一個獨立的系統。 他們可以使用自己的持久性系統(盡管不是強制性的),部署,語言等。
由于系統由一個以上的服務組成,因此每個服務將與其他服務通信,通常使用輕量級協議(如HTTP)并遵循Restful Web方法。 您可以在這里閱讀有關微服務的更多信息: http : //martinfowler.com/articles/microservices.html
讓我們看一個非常簡單的例子。 假設我們有一家售票店,用戶可以在其中瀏覽目錄,當他們找到想要查看更多信息的書時,單擊isbn,然后會打開一個新屏幕,其中包含該書的詳細信息和對此的評論由讀者撰寫。
該系統可能由兩個服務組成:
- 一種獲取書籍詳細信息的服務。 可以從任何傳統系統(如RDBMS)中檢索它們。
- 一種將所有評論寫在書中的服務,在這種情況下,信息可以存儲在文檔庫中。
這里的問題是,對于用戶的每個請求,我們需要打開兩個連接,每個服務一個。 當然,我們需要一種并行執行這些工作的方法來提高性能。 這是一個問題,我們如何處理異步請求? 第一個想法是使用Future類。 對于兩個服務可能很好,但是如果您需要四個或五個服務,代碼將變得越來越復雜,例如,您可能需要從一個服務獲取數據并在另一服務中使用它,或者將一個服務的結果修改為輸入另一個。 因此,存在線程和同步管理的成本。
有一種干凈整潔的方式來解決這個問題的方法真是太棒了。 這正是RxJava所做的。 RxJava是Reactive Extensions的Java VM實現:該庫用于通過使用可觀察的序列來組成異步和基于事件的程序。
使用RxJava而不是從結構中提取數據,而是將數據推送到它,該數據與訂閱者偵聽的事件做出React并一致地起作用。 您可以在https://github.com/Netflix/RxJava中找到更多信息。
因此,在這種情況下,我們要實現的是此處描述的示例,該示例使用RxJava , Java EE 7 , Java 8和Arquillian進行測試。
這篇文章假定您知道如何使用Java EE規范編寫Rest服務。
因此,讓我們從兩個服務開始:
@Singleton @Path("bookinfo") public class BookInfoService {@GET@Path("{isbn}")@Produces(MediaType.APPLICATION_JSON)@Consumes(MediaType.APPLICATION_JSON)public JsonObject findBookByISBN(@PathParam("isbn") String isbn) {return Json.createObjectBuilder().add("author", "George R.R. Martin").add("isbn", "1111").add("title", "A Game Of Thrones").build();}}@Singleton @Path("comments") public class CommentsService {@GET@Path("{isbn}")@Produces(MediaType.APPLICATION_JSON)public JsonArray bookComments(@PathParam("isbn") String isbn) {return Json.createArrayBuilder().add("Good Book").add("Awesome").build();}}@ApplicationPath("rest") public class ApplicationResource extends Application { }最后是創建第三個外觀服務的時候了,該服務從客戶端接收通信,并行向兩個服務發送請求,最后壓縮兩個響應。 zip是將通過指定函數發出的一組項目組合在一起并將其發送回客戶端的過程(不要與壓縮混淆!)。
@Singleton @Path("book") public class BookService {private static final String BOOKSERVICE = "http://localhost:8080/bookservice";private static final String COMMENTSERVICE = "http://localhost:8080/bookcomments";@Resource(name = "DefaultManagedExecutorService")ManagedExecutorService executor;Client bookServiceClient;WebTarget bookServiceTarget;Client commentServiceClient;WebTarget commentServiceTarget;@PostConstructvoid initializeRestClients() {bookServiceClient = ClientBuilder.newClient();bookServiceTarget = bookServiceClient.target(BOOKSERVICE + "/rest/bookinfo");commentServiceClient = ClientBuilder.newClient();commentServiceTarget = commentServiceClient.target(COMMENTSERVICE + "/rest/comments");}@GET@Path("{isbn}")@Produces(MediaType.APPLICATION_JSON)public void bookAndComment(@Suspended final AsyncResponse asyncResponse, @PathParam("isbn") String isbn) {//RxJava code shown below} }基本上,我們創建一個新服務。 在這種情況下,我們將要連接的兩個服務的URL都是硬編碼的。 這是出于學術目的而完成的,但是在類似于生產的代碼中,您將從生產者類或屬性文件或用于此目的的任何系統中注入它。 然后,我們創建javax.ws.rs.client.WebTarget來使用Restful Web Service 。
之后,我們需要使用RxJava API實現bookAndComment方法。
RxJava中使用的主要類是rx.Observabl e。 正如他的名字所暗示的那樣,此類是可觀察的,并且是觸發事件以推動對象的原因。 默認情況下,事件是同步的,開發人員有責任使它們異步。
因此,我們需要為每個服務提供一個異步可觀察實例:
public Observable<JsonObject> getBookInfo(final String isbn) {return Observable.create((Observable.OnSubscribe<JsonObject>) subscriber -> {Runnable r = () -> {subscriber.onNext(bookServiceTarget.path(isbn).request().get(JsonObject.class));subscriber.onCompleted();};executor.execute(r);}); }基本上,我們創建一個Observable ,當訂戶訂閱它時將執行指定的功能。 該函數是使用lambda表達式創建的,以避免創建嵌套的內部類。 在這種情況下,由于調用bookinfo服務,我們將返回JsonObject 。 結果將傳遞到onNext方法,以便訂閱者可以接收結果。 因為我們要異步執行此邏輯,所以代碼被包裝在Runnable塊中。
完成所有邏輯后,還需要調用onCompleted方法。
注意,因為除了創建Runnable之外 ,我們還希望使可觀察的異步發生,所以我們使用Executor在單獨的線程中運行邏輯。 Java EE 7中的一項重大新增功能是在容器內部創建線程的一種托管方式。 在這種情況下,我們使用容器提供的ManagedExecutorService在當前任務的不同線程中異步跨越任務。
public Observable<JsonArray> getComments(final String isbn) {return Observable.create((Observable.OnSubscribe<JsonArray>) subscriber -> {Runnable r = () -> {subscriber.onNext(commentServiceTarget.path(isbn).request().get(JsonArray.class));subscriber.onCompleted();};executor.execute(r);}); }與之前的內容類似,但沒有獲取書籍信息,而是獲得了一系列評論。
然后,我們需要創建一個可觀察者,負責在兩個響應均可用時壓縮兩個響應。 這是通過在Observable類上使用zip方法完成的,該方法接收兩個Observable并應用一個函數來組合兩個結果。 在這種情況下,一個lambda表達式會創建一個新的json對象,附加兩個響應。
@GET @Path("{isbn}") @Produces(MediaType.APPLICATION_JSON) public void bookAndComment(@Suspended final AsyncResponse asyncResponse, @PathParam("isbn") String isbn) {//Calling previous defined functionsObservable<JsonObject> bookInfo = getBookInfo(isbn);Observable<JsonArray> comments = getComments(isbn);Observable.zip(bookInfo, comments, (JsonObject book, JsonArray bookcomments) ->Json.createObjectBuilder().add("book", book).add("comments", bookcomments).build()).subscribe(new Subscriber<JsonObject>() {@Overridepublic void onCompleted() {}@Overridepublic void onError(Throwable e) {asyncResponse.resume(e);}@Overridepublic void onNext(JsonObject jsonObject) {asyncResponse.resume(jsonObject);}}); }讓我們看一下以前的服務。 我們正在使用@Suspended批注來使用Java EE中的新增功能之一,即Jax-Rs 2.0異步REST端點。 基本上,我們正在做的是釋放服務器資源,并使用resume方法在響應可用時生成響應。
最后是測試。 我們將Wildfly 8.1用作Java EE 7服務器和Arquillian 。 因為每個服務可以在不同的服務器上進行部署,我們將在不同的戰爭 ,而是同一個服務器內部署各項服務。
因此,在這種情況下,我們將部署三個戰爭文件,這在Arquillian中非常容易做到。
@RunWith(Arquillian.class) public class BookTest {@Deployment(testable = false, name = "bookservice")public static WebArchive createDeploymentBookInfoService() {return ShrinkWrap.create(WebArchive.class, "bookservice.war").addClasses(BookInfoService.class, ApplicationResource.class);}@Deployment(testable = false, name = "bookcomments")public static WebArchive createDeploymentCommentsService() {return ShrinkWrap.create(WebArchive.class, "bookcomments.war").addClasses(CommentsService.class, ApplicationResource.class);}@Deployment(testable = false, name = "book")public static WebArchive createDeploymentBookService() {WebArchive webArchive = ShrinkWrap.create(WebArchive.class, "book.war").addClasses(BookService.class, ApplicationResource.class).addAsLibraries(Maven.resolver().loadPomFromFile("pom.xml").resolve("com.netflix.rxjava:rxjava-core").withTransitivity().as(JavaArchive.class));return webArchive;}@ArquillianResourceURL base;@Test@OperateOnDeployment("book")public void should_return_book() throws MalformedURLException {Client client = ClientBuilder.newClient();JsonObject book = client.target(URI.create(new URL(base, "rest/").toExternalForm())).path("book/1111").request().get(JsonObject.class);//assertions} }在這種情況下,客戶將要求一本書提供所有信息。 在服務器部分中, zip方法將等待直到并行檢索書和注釋,然后將兩個響應組合到一個對象中并發送回客戶端。
這是RxJava的一個非常簡單的示例。 實際上,在這種情況下,我們僅看到了如何使用zip方法,但是RxJava提供了許多其他有用的方法,例如take() , map() , merge() ,…( https:// github .com / Netflix / RxJava / wiki / Alphabetical-Observable-Operators列表 )
此外,在此示例中,我們僅看到了連接兩個服務并并行檢索信息的示例,您可能想知道為什么不使用Future類。 在此示例中使用Future和Callbacks完全可以,但是在現實生活中,您的邏輯將不會像壓縮兩個服務那樣容易。 也許您將擁有更多的服務,也許您需要從一項服務中獲取信息,然后為每個結果打開一個新的連接。 如您所見,您可能從兩個Future實例開始,但以一堆Future.get()方法,超時等結束,因此,在這些情況下, RxJava確實簡化了應用程序的開發。
此外,我們還看到了如何使用Java EE 7的一些新增功能,例如如何使用Jax-Rs開發異步Restful服務。
在這篇文章中,我們學習了如何處理服務之間的互連以及如何使它們可伸縮并減少資源消耗。 但是,我們沒有談論這些服務之一發生故障時發生的情況。 呼叫者怎么了? 我們有辦法進行管理嗎? 當其中一項服務不可用時,是否有一種方法可以不浪費資源? 我們將在下一篇關于容錯的文章中對此進行介紹。
我們不斷學習,
亞歷克斯
邦迪亞,邦迪亞! Bon dia aldematí! Fem for a la mandra I saltem corrents del llit。 (Bon Dia!–DàmarisGelabert)
翻譯自: https://www.javacodegeeks.com/2014/07/rxjava-java8-java-ee-7-arquillian-bliss.html
java與java ee
總結
以上是生活随笔為你收集整理的java与java ee_RxJava + Java8 + Java EE 7 + Arquillian =幸福的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 电鼓垫app(电鼓垫安卓)
- 下一篇: Netty Java快速指南