1. 概述
在本文中,我們將討論 Vert.x,涵蓋其核心概念並使用它創建一個簡單的 RESTfull Web 服務。
我們首先將涵蓋工具包的基準概念,然後逐步過渡到 HTTP 服務器,最後構建 RESTfull 服務。
2. 關於 Vert.x
Vert.x 是 Eclipse 開發團隊開發的開源、響應式和多語種軟件開發工具包。
響應式編程是一種編程範式,與異步流相關聯,能夠響應任何更改或事件。
類似地,Vert.x 使用事件總線與應用程序的不同部分進行通信,並在處理程序可用時異步地傳遞事件。
我們稱之為多語種,因為它支持 Java、Groovy、Ruby、Python 和 JavaScript 等多種 JVM 和非 JVM 語言。
3. 安裝
要使用 Vert.x,我們需要添加 Maven 依賴:
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-core</artifactId>
<version>3.9.15</version>
</dependency>
最新版本的依賴可以找到 這裏。
3. 虛擬實例
虛擬實例是 Vert.x 引擎執行的代碼片段。該工具包提供了許多抽象虛擬實例類,可以進行擴展和自定義實現。
由於其多語言特性,虛擬實例可以採用任何受支持的語言編寫。一個應用程序通常由多個虛擬實例在同一 Vert.x 實例中運行,並通過事件總線進行互通。
要創建 JAVA 中的虛擬實例,該類必須實現 io.vertx.core.Verticle 接口,或其任何子類。
4. Event Bus
它是任何 Vert.x 應用程序的神經系統。
由於其反應性,Verticle 在接收到消息或事件時保持休眠狀態。Verticle 通過事件總線與其他 Verticle 進行通信。消息可以是字符串到複雜對象。
消息處理應理想情況下是異步的,消息被排隊到事件總線上,並返回到發送方。稍後它被從偵聽 Verticle 中取出。響應使用 Future 和 callback 方法。
5. 簡單的 Vert.x 應用程序
讓我們創建一個簡單的應用程序,其中包含一個 Verticle,並使用 vertx 實例進行部署。要創建我們的 Verticle,我們將擴展 io.vertx.core.AbstractVerticle 類並覆蓋 start() 方法:
public class HelloVerticle extends AbstractVerticle {
@Override
public void start(Future<Void> future) {
LOGGER.info("Welcome to Vertx");
}
}
start() 方法將在 Verticle 部署時由 vertx 實例調用。該方法接受 io.vertx.core.Future 作為參數,可用於發現 Verticle 的異步部署狀態。
現在讓我們部署 Verticle:
public static void main(String[] args) {
Vertx vertx = Vertx.vertx();
vertx.deployVerticle(new HelloVerticle());
}
類似於地,我們可以覆蓋 AbstractVerticle 類中的 stop() 方法,該方法將在關閉 Verticle 時被調用:
@Override
public void stop() {
LOGGER.info("Shutting down application");
}
6. HTTP 服務器
現在讓我們使用 verticle 創建一個 HTTP 服務器:
@Override
public void start(Future<Void> future) {
vertx.createHttpServer()
.requestHandler(r -> r.response().end("歡迎使用 Vert.x 介紹"));
})
.listen(config().getInteger("http.port", 9090),
result -> {
if (result.succeeded()) {
future.complete();
} else {
future.fail(result.cause());
}
});
}
我們已經覆蓋了 start() 方法來創建 HTTP 服務器並附加了一個請求處理程序到它上。 requestHandler()方法在每次服務器收到請求時都會被調用。
最後,服務器綁定到一個端口,並且一個 AsyncResult<HttpServer> 處理程序被傳遞到 listen()方法,無論連接或服務器啓動是否成功,都使用 future.complete() 或 future.fail()在任何錯誤的情況下。
請注意:config.getInteger() 方法正在讀取 HTTP 端口配置的值,該值從外部 conf.json文件中加載。
現在讓我們測試我們的服務器:
@Test
public void whenReceivedResponse_thenSuccess(TestContext testContext) {
Async async = testContext.async();
vertx.createHttpClient()
.getNow(port, "localhost", "/", response -> {
response.handler(responseBody -> {
testContext.assertTrue(responseBody.toString().contains("Hello"));
async.complete();
});
});
}
為了測試,讓我們使用 vertx-unit 及其與 JUnit 配合使用:
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-unit</artifactId>
<version>3.9.15</version>
<scope>test</scope>
</dependency>
我們可以從這裏獲取最新版本 這裏。
Verticle 已部署並在 vertx實例中,在 setup()方法中的 setup()方法中。
@Before
public void setup(TestContext testContext) {
vertx = Vertx.vertx();
vertx.deployVerticle(SimpleServerVerticle.class.getName(),
testContext.asyncAssertSuccess());
}
同樣,@AfterClass tearDown() 方法中 vertx 實例在 @After方法中關閉。
@After
public void tearDown(TestContext testContext) {
vertx.close(testContext.asyncAssertSuccess());
}
請注意:@BeforeClass setup() 方法接受 TestContext 參數。 這有助於我們控制和測試測試中的異步行為。 例如,verticle 部署是異步的,因此我們基本上不能測試任何內容,除非它已正確部署。
我們有一個 deployVerticle() 方法中的第二個參數,testContext.asyncAssertSuccess(). T 他的目的是要知道服務器是否已正確部署或是否發生任何失敗。 它等待 future.complete() 或 future.fail() 在服務器 verticle 中被調用。 在發生錯誤的情況下,它會失敗測試。
7. RESTful WebService
我們已經創建了一個 HTTP 服務器,現在讓我們使用它來託管一個 RESTful WebService。為了做到這一點,我們需要另一個 Vert.x 模塊,叫做
我們需要將依賴項添加到我們的
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-web</artifactId>
<version>3.9.15</version>
</dependency>
我們可以從這裏找到最新版本 here
7.1. Router and Routes
讓我們為我們的 WebService 創建一個
Router router = Router.router(vertx);
router.get("/api/baeldung/articles/article/:id")
.handler(this::getArticles);
private void getArticles(RoutingContext routingContext) {
String articleId = routingContext.request()
.getParam("id");
Article article = new Article(articleId,
"This is an intro to vertx", "baeldung", "01-02-2017", 1578);
routingContext.response()
.putHeader("content-type", "application/json")
.setStatusCode(200)
.end(Json.encodePrettily(article));
}
一個
在我們的例子中,處理方法會調用
在方法末尾,我們調用
7.2. Adding Router to Server
現在,讓我們將創建的
vertx.createHttpServer()
.requestHandler(router::accept)
.listen(config().getInteger("http.port", 8080),
result -> {
if (result.succeeded()) {
future.complete();
} else {
future.fail(result.cause());
}
});
請注意,我們已經將
現在,讓我們測試我們的 WebService:
@Test
public void givenId_whenReceivedArticle_thenSuccess(TestContext testContext) {
Async async = testContext.async();
vertx.createHttpClient()
.getNow(8080, "localhost", "/api/baeldung/articles/article/12345",
response -> {
response.handler(responseBody -> {
testContext.assertTrue(
responseBody.toString().contains("\"id\" : \"12345\""));
async.complete();
});
});
}
8. 包裝 Vert.x 應用程序
為了將應用程序打包為可部署的 Java 存檔 (.jar),我們使用 Maven Shade 插件以及在 execution 標籤中的配置:<configuration>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<manifestEntries>
<Main-Class>io.vertx.core.Starter</Main-Class>
<Main-Verticle>com.baeldung.SimpleServerVerticle</Main-Verticle>
</manifestEntries>
</transformer>
</transformers>
<artifactSet />
<outputFile>
${project.build.directory}/${project.artifactId}-${project.version}-app.jar
</outputFile>
</configuration>
在 manifestEntriesMain-Verticle 指示應用程序的啓動點,而 Main-Class 是一個 Vert.x 類,它創建了 vertx 實例並部署了 Main-Verticle。
9. 結論
在本文檔中,我們討論了 Vert.x 工具包及其基本概念。演示瞭如何創建 HTTP 服務器,使用 Vert.x 以及如何使用 vertx-unit 測試它們。
最後,將應用程序打包為可執行的 JAR 文件。