WebClient client = WebClient.create(vertx);
HttpRequest request = client.get("/resource");
request.send(ar -> {
if (ar.succeeded()) {
HttpResponse response = ar.result();
} else {
Throwable error = ar.cause();
}
}); 从 Vert.x 3 迁移到 4
本指南介绍了 Eclipse Vert.x 4 版本中的更新。使用这些信息将您的 Vert.x 3.x 应用程序升级到 Vert.x 4。它提供了有关此版本中新增、已弃用和不受支持功能的信息。
根据您的应用程序中使用的模块,您可以阅读相关部分以了解 Vert.x 4 中的更改。
关于 Vert.x
Vert.x 是一个用于创建在 Java 虚拟机 (JVM) 上运行的响应式、非阻塞和异步应用程序的工具包。它包含多个组件,可帮助您创建响应式应用程序。它被设计为云原生。
由于 Vert.x 支持异步应用程序,因此可用于创建具有大量消息、大型事件处理、HTTP 交互等的应用程序。
Vert.x 4 中有哪些变化
本节解释了 Vert.x 4 和 3.x 版本之间的根本区别。
使用 future 方法进行异步操作
Vert.x 4 使用 futures 进行异步操作。每个回调方法都有一个相应的 future 方法。Futures 可用于组合异步操作。您可以使用回调和 future 方法的组合将基于回调的应用程序迁移到 Vert.x 4。但是,您也可以继续使用回调进行异步操作。
以下示例展示了 Vert.x 3.x 版本中如何使用回调进行异步操作。
以下示例展示了 Vert.x 4 中如何将回调和 future 方法一起用于异步操作。
WebClient client = WebClient.create(vertx);
HttpRequest request = client.get("/resource");
Future<HttpResponse> response = request.send();
response.onComplete(ar -> {
if (ar.succeeded()) {
HttpResponse response = ar.result();
} else {
Throwable failure = ar.cause();
}
}); 使用 futures 更好地处理错误。在回调中,您必须在组合的每个阶段处理失败,而在 futures 中,您可以在最后一次性处理失败。在基本应用程序中,您可能不会注意到使用回调和 futures 之间的明显差异。
以下示例展示了如何使用回调组合两个异步操作。您可以看到错误在每次组合时都会被处理。
client.get("/resource1").send(ar1 -> {
if (ar1.succeeded()) {
HttpResponse response = ar.result();
JsonObject json = response.body();
client.put("/resource2").sendJsonObject(ar2 -> {
if (ar2.succeeded()) {
// Handle final result
} else {
Throwable failure2 = ar.cause();
}
});
} else {
Throwable failure1 = ar.cause();
}
}); 以下示例展示了 Vert.x 4 中如何使用回调和 futures 组合两个异步操作。错误仅在最后处理一次。
Future<HttpResponse> fut1 = client.get("/resource1").send();
Future<HttpResponse> fut2 = fut1.compose(response -> client.put("/resource2").sendJsonObject(response.body()));
fut2.onComplete(ar -> {
if (ar.succeeded()) {
// Handle final result
} else {
Throwable failure = ar.cause();
}
}); 不依赖 Jackson Databind 库
Vert.x 中的 JSON 功能依赖于 Jackson 库。Jackson Databind 库支持 JSON 的对象映射。
在 Vert.x 4 中,Jackson Databind 是一个可选的 Maven 依赖项。如果您想使用此依赖项,必须在 classpath 中明确添加它。
-
如果您正在进行 JSON 对象映射,那么您必须在项目描述符中明确添加
com.fasterxml.jackson.core:jackson-databindjar 依赖项。<dependencies> ... <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> </dependency> ... </dependencies>将来,如果您决定不使用 JSON 对象映射,可以删除此依赖项。
-
如果您不进行 JSON 对象映射,则不需要 Jackson Databind 库。您可以在没有此 jar 的情况下运行应用程序。
处理弃用和删除
Vert.x 4 中已弃用或删除了某些功能和函数。在将应用程序迁移到 Vert.x 4 之前,请检查弃用和删除。
-
一些 API 在 Vert.x 3.x 版本中已被弃用,并在该版本中提供了新的等效 API。
-
已弃用的 API 已在 Vert.x 4 中删除。
如果您的应用程序使用已弃用的 API,您应该更新您的应用程序以使用新的 API。这有助于将应用程序迁移到产品的最新版本。
当使用已弃用的 API 时,Java 编译器会生成警告。在将应用程序迁移到 Vert.x 4 时,您可以使用编译器检查已弃用的方法。
以下示例展示了 Vert.x 3.x 版本中已弃用的 EventBus 方法。
// Send was deprecated in Vert.x 3.x release
vertx.eventBus().send("some-address", "hello world", ar -> {
// Handle response here
}); 方法 send(String,String,Handler<AsyncResult<Message>>) 在 Vert.x 4 中已被方法 request(String,String,Handler<AsyncResult<Message>>) 替换。
以下示例展示了如何更新应用程序以使用新方法。
// New method can be used in Vert.x 3.x and Vert.x 4.x releases
vertx.eventBus().request("some-address", "hello world", ar -> {
// Handle response here
}); 常用组件的变更
本节解释了 Vert.x 基本组件中的变化。
消息传递中的变化
本节解释了消息传递方法中的变化。
写入流中的 write 和 end 方法不再是 fluent 的
WriteStream<T>.write() 和 WriteStream<T>.end() 方法不再是 fluent 的。
-
写入和结束回调方法返回
void。 -
其他写入和结束方法返回
Future<Void>。
这是一个破坏性变更。如果您已将 fluent 特性用于写入流,请更新您的应用程序。
MessageProducer 不再扩展 WriteStream
MessageProducer 接口不再扩展 WriteStream 接口。
在 Vert.x 的早期版本中,MessageProducer 接口扩展了 WriteStream 接口。MessageProducer 接口对消息背压提供了有限支持。信用泄漏会导致消息生产者中的信用减少。如果这些泄漏用尽所有信用,消息将不会被发送。
但是,MessageConsumer 将继续扩展 ReadStream。当 MessageConsumer 暂停且待处理消息队列已满时,消息将被丢弃。这继续了与 Rx 生成器的集成,以构建消息消费管道。
从 MessageProducer 中删除了 send 方法
MessageProducer 接口中的 send 方法已删除。
请使用方法 MessageProducer<T>.write(T) 代替 MessageProducer<T>.send(T),以及 EventBus.request(String,Object,Handler) 代替 MessageProducer.send(T,Handler)。
EventBus 中的变化
以下部分描述了 EventBus 中的变化。
EventBus 中已删除请求-响应 send 方法
EventBus.send(…, Handler<AsyncResult<Message<T>>>) 和 Message.reply(…, Handler<AsyncResult<Message<T>>>) 方法已删除。这些方法会在 Vert.x 4 中导致重载问题。返回 Future<Message<T>> 的方法版本会与 fire and forget 版本冲突。
请求-响应消息模式应使用新的 request 和 replyAndRequest 方法。
-
使用方法
EventBus.request(…, Handler<AsyncResult<Message<T>>>)代替EventBus.send(…, Handler<AsyncResult<Message<T>>>)来发送消息。 -
使用方法
Message.replyAndRequest(…, Handler<AsyncResult<Message<T>>>)代替Message.reply(…, Handler<AsyncResult<Message<T>>>)来回复消息。
以下示例展示了 Vert.x 3.x 版本中请求和回复消息的方式。
- 请求
eventBus.send("the-address", body, ar -> ...); - 回复
eventBus.consumer("the-address", message -> {
message.reply(body, ar -> ...);
}); 以下示例展示了 Vert.x 4 中请求和回复消息的方式。
- 请求
eventBus.request("the-address", body, ar -> ...); - 回复
eventBus.consumer("the-address", message -> {
message.replyAndRequest(body, ar -> ...);
}); Future 中的变化
本节解释了 future 中的变化。
支持 futures 的多个处理程序
从 Vert.x 4 开始,一个 future 支持多个处理程序。用于设置单个处理程序的 Future<T>.setHandler() 方法已删除。请改用 Future<T>.onComplete()、Future<T>.onSuccess() 和 Future<T>.onFailure() 方法,以便在操作完成、成功和失败结果时调用处理程序。
以下示例展示了 Vert.x 3.x 版本中如何调用处理程序。
Future<String> fut = getSomeFuture();
fut.setHandler(ar -> ...); 以下示例展示了 Vert.x 4 中如何调用新的 Future<T>.onComplete() 方法。
Future<String> fut = getSomeFuture();
fut.onComplete(ar -> ...); Future 中删除了 completer() 方法
在 Vert.x 的早期版本中,您会使用 Future.completer() 方法来访问与 Future 关联的 Handler<AsyncResult<T>>。
在 Vert.x 4 中,Future<T>.completer() 方法已删除。Future<T> 直接扩展 Handler<AsyncResult<T>>。您可以使用 Future 对象访问所有处理程序方法。Future 对象也是一个处理程序。
HTTP 客户端请求中已删除连接处理程序方法
HttpClientRequest.connectionHandler() 方法已删除。请改用 HttpClient.connectionHandler() 方法来调用应用程序中客户端请求的连接处理程序。
以下示例展示了 Vert.x 3.x 版本中如何使用 HttpClientRequest.connectionHandler() 方法。
client.request().connectionHandler(conn -> {
// Connection related code
}).end(); 以下示例展示了 Vert.x 4 中如何使用新的 HttpClient.connectionHandler() 方法。
client.connectionHandler(conn -> {
// Connection related code
}); verticles 中的变化
本节解释了 verticles 中的变化。
create verticle 方法的更新
在 Vert.x 的早期版本中,VerticleFactory.createVerticle() 方法同步实例化 verticle。从 Vert.x 4 开始,该方法异步实例化 verticle 并返回回调 Callable<Verticle> 而不是单个 verticle 实例。此改进使应用程序能够一次调用此方法并多次调用返回的 callable 以创建多个实例。
以下代码展示了 Vert.x 3.x 版本中 verticles 的实例化方式。
Verticle createVerticle(String verticleName, ClassLoader classLoader) throws Exception; 以下代码展示了 Vert.x 4 中 verticles 的实例化方式。
void createVerticle(String verticleName, ClassLoader classLoader, Promise<Callable<Verticle>> promise); 工厂类和方法的更新
VerticleFactory 类已简化。该类不需要初始解析标识符,因为工厂可以使用嵌套部署来部署 verticle。
如果您的现有应用程序使用工厂,在 Vert.x 4 中,您可以在 promise 完成或失败时更新代码以使用 callable。callable 可以被多次调用。
以下示例展示了 Vert.x 3.x 应用程序中的现有工厂。
return new MyVerticle(); 以下示例展示了如何在 Vert.x 4 中更新现有工厂以使用 promise。
promise.complete(() -> new MyVerticle()); 如果您希望工厂阻塞代码,请使用 Vertx.executeBlocking() 方法。当工厂接收到阻塞代码时,它应该解析 promise 并从 promise 中获取 verticle 实例。
已删除多线程 worker verticles
多线程 worker verticle 部署选项已删除。此功能只能与 Vert.x event-bus 一起使用。其他 Vert.x 组件(如 HTTP)不支持此功能。
使用无序的 Vertx.executeBlocking() 方法来实现与多线程 worker 部署相同的功能。
线程中的变化
本节解释了线程中的变化。
非 Vert.x 线程的上下文亲和性
Vertx.getOrCreateContext() 方法为每个非 Vert.x 线程创建一个单独的上下文。非 Vert.x 线程在第一次创建上下文时与上下文关联。在早期版本中,每次从非 Vert.x 线程调用该方法时都会创建一个新上下文。
new Thread(() -> {
assertSame(vertx.getOrCreateContext(), vertx.getOrCreateContext());
}).start(); 此更改不会影响您的应用程序,除非您的应用程序隐式依赖于每次调用时都创建一个新上下文。
在以下示例中,n 个块并发运行,因为每个阻塞代码都在不同的上下文中调用。
for (int i = 0;i < n;i++) {
vertx.executeBlocking(block, handler);
} 要在 Vert.x 4 中获得相同的结果,您必须更新代码
for (int i = 0;i < n;i++) {
vertx.executeBlocking(block, false, handler);
} HTTP 中的变化
本节解释了 HTTP 方法中的变化。
Vert.x HTTP 方法的通用更新
以下部分描述了 Vert.x HTTP 方法中的杂项更新。
WebSocket HTTP 方法的更新
WebSocket 的变化是
-
方法名称中
WebSocket一词的使用不一致。方法名称的大小写不正确,例如Websocket,而不是WebSocket。以下类中WebSocket使用不一致的方法已删除。请改用大小写正确的新方法。-
HttpServerOptions类中的以下方法已删除。已删除方法 新方法 getMaxWebsocketFrameSize()getMaxWebSocketFrameSize()setMaxWebsocketFrameSize()setMaxWebSocketFrameSize()getMaxWebsocketMessageSize()getMaxWebSocketMessageSize()setMaxWebsocketMessageSize()setMaxWebSocketMessageSize()getPerFrameWebsocketCompressionSupported()getPerFrameWebSocketCompressionSupported()setPerFrameWebsocketCompressionSupported()setPerFrameWebSocketCompressionSupported()getPerMessageWebsocketCompressionSupported()getPerMessageWebSocketCompressionSupported()setPerMessageWebsocketCompressionSupported()setPerMessageWebSocketCompressionSupported()getWebsocketAllowServerNoContext()getWebSocketAllowServerNoContext()setWebsocketAllowServerNoContext()setWebSocketAllowServerNoContext()getWebsocketCompressionLevel()getWebSocketCompressionLevel()setWebsocketCompressionLevel()setWebSocketCompressionLevel()getWebsocketPreferredClientNoContext()getWebSocketPreferredClientNoContext()setWebsocketPreferredClientNoContext()setWebSocketPreferredClientNoContext()getWebsocketSubProtocols()getWebSocketSubProtocols()setWebsocketSubProtocols()setWebSocketSubProtocols()WebSocket子协议的新方法使用List<String>数据类型而不是逗号分隔字符串来存储项目。 -
HttpClientOptions类中的以下方法已删除。已删除方法 替换方法 getTryUsePerMessageWebsocketCompression()getTryUsePerMessageWebSocketCompression()setTryUsePerMessageWebsocketCompression()setTryUsePerMessageWebSocketCompression()getTryWebsocketDeflateFrameCompression()getTryWebSocketDeflateFrameCompression()getWebsocketCompressionAllowClientNoContext()getWebSocketCompressionAllowClientNoContext()setWebsocketCompressionAllowClientNoContext()setWebSocketCompressionAllowClientNoContext()getWebsocketCompressionLevel()getWebSocketCompressionLevel()setWebsocketCompressionLevel()setWebSocketCompressionLevel()getWebsocketCompressionRequestServerNoContext()getWebSocketCompressionRequestServerNoContext()setWebsocketCompressionRequestServerNoContext()setWebSocketCompressionRequestServerNoContext() -
HttpServer类中的以下处理程序方法已删除。已弃用方法 新方法 websocketHandler()webSocketHandler()websocketStream()webSocketStream()
-
-
WebsocketRejectedException已弃用。方法现在抛出UpgradeRejectedException。 -
HttpClient的webSocket()方法使用Handler<AsyncResult<WebSocket>>而不是Handler或Handler<Throwable>。 -
通过使用
WebSocketConnectOptions类中的方法,连接 HTTP 客户端到 WebSocket 的重载方法数量也已减少。 -
HttpServerRequest.upgrade()方法已删除。此方法是同步的。请改用新的
HttpServerRequest.toWebSocket()方法。此新方法是异步的。以下示例展示了 Vert.x 3.x 中同步方法的使用。
// 3.x server.requestHandler(req -> { WebSocket ws = req.upgrade(); });以下示例展示了 Vert.x 4 中异步方法的使用。
// 4.0 server.requestHandler(req -> { Future<WebSocket> fut = req.toWebSocket(); fut.onSuccess(ws -> { }); });
设置 WebSocket 连接数
在 Vert.x 3.x 中,您可以使用 HTTP 客户端池大小来定义应用程序中 WebSocket 连接的最大数量。值访问器方法 HttpClientOptions.maxPoolSize() 用于获取和设置 WebSocket 连接。每个端点的默认连接数设置为 4。
以下示例展示了 Vert.x 3.x 中 WebSocket 连接的设置方式。
// 3.x
options.setMaxPoolSize(30); // Maximum connection is set to 30 for each endpoint 然而,在 Vert.x 4 中,WebSocket TCP 连接不再进行池化,因为连接在使用后会关闭。应用程序为 HTTP 请求使用不同的池。使用值访问器方法 HttpClientOptions.maxWebSockets() 来获取和设置 WebSocket 连接。每个端点的默认连接数设置为 50。
以下示例展示了 Vert.x 4 中如何设置 WebSocket 连接。
// 4.0
options.setMaxWebSockets(30); // Maximum connection is set to 30 for each endpoint HttpMethod 可作为接口使用
HttpMethod 可作为新接口使用。
在 Vert.x 的早期版本中,HttpMethod 被声明为枚举数据类型。作为枚举,它限制了 HTTP 的可扩展性。此外,它阻止了直接使用此类型提供其他 HTTP 方法。您必须在服务器和客户端 HTTP 请求期间使用 HttpMethod.OTHER 值和 rawMethod 属性。
如果您在 switch 块中使用 HttpMethod 枚举数据类型,您可以使用以下代码将您的应用程序迁移到 Vert.x 4。
以下示例展示了 Vert.x 3.x 版本中的 switch 块。
switch (method) {
case GET:
...
break;
case OTHER:
String s = request.getRawMethod();
if (s.equals("PROPFIND") {
...
} else ...
} 以下示例展示了 Vert.x 4 中的 switch 块。
switch (method.name()) {
case "GET":
...
break;
case "PROPFIND";
...
break;
} 您也可以在 Vert.x 4 中使用以下代码。
HttpMethod PROPFIND = HttpMethod.valueOf("PROPFIND");
if (method == HttpMethod.GET) {
...
} else if (method.equals(PROPFIND)) {
...
} else {
...
} 如果您在应用程序中使用 HttpMethod.OTHER 值,请使用以下代码将应用程序迁移到 Vert.x 4。
以下示例展示了 Vert.x 3.x 版本中的代码。
client.request(HttpMethod.OTHER, ...).setRawName("PROPFIND"); 以下示例展示了 Vert.x 4 中的代码。
client.request(HttpMethod.valueOf("PROPFIND"), ...); HTTP 客户端中的变化
本节描述了 HTTP 客户端中的变化。
以下类型的 Vert.x 客户端可用
- Vert.x web 客户端
-
当您的应用程序是面向 Web 的时,例如 REST、HTTP 有效负载的编码和解码、解释 HTTP 状态响应代码等,请使用 Vert.x web 客户端。
- Vert.x HTTP 客户端
-
当您的应用程序用作 HTTP 代理时,例如作为 API 网关,请使用 Vert.x HTTP 客户端。HTTP 客户端在 Vert.x 4 中已更新和改进。
| Vert.x web 客户端基于 Vert.x HTTP 客户端。 |
将应用程序迁移到 Vert.x web 客户端
web 客户端从 Vert.x 3.4.0 版本开始可用。Vert.x 4 中的 web 客户端没有变化。
该客户端提供了简化的 HTTP 交互和一些附加功能,例如 HTTP 会话、JSON 编码和解码、响应谓词,这些功能在 Vert.x HTTP 客户端中不可用。
以下示例展示了 Vert.x 3.x 版本中如何使用 HTTP 客户端。
HttpClientRequest request = client.get(80, "example.com", "/", response -> {
int statusCode = response.statusCode();
response.exceptionHandler(err -> {
// Handle connection error, for example, connection closed
});
response.bodyHandler(body -> {
// Handle body entirely
});
});
request.exceptionHandler(err -> {
// Handle connection error OR response error
});
request.end(); 以下示例展示了如何在 Vert.x 3.x 和 Vert.x 4 版本中将应用程序迁移到 web 客户端。
client.get(80, "example.com", "/some-uri")
.send(ar -> {
if (ar.suceeded()) {
HttpResponse<Buffer> response = ar.result();
// Handle response
} else {
// Handle error
}
}); 将应用程序迁移到 Vert.x HTTP 客户端
HTTP 客户端对 HTTP 交互有细粒度控制,并专注于 HTTP 协议。
HTTP 客户端在 Vert.x 4 中已更新和改进
-
简化的 API,更少的交互
-
健壮的错误处理
-
支持 HTTP/1 的连接重置
HTTP 客户端 API 的更新是
-
HttpClientRequest中的方法,例如get()、delete()、put()已删除。请改用方法HttpClientRequest> request(HttpMethod method, …)。 -
当请求或响应可能时,会创建
HttpClientRequest实例。例如,当客户端连接到服务器或从池中重用连接时,会创建HttpClientRequest实例。
发送简单请求
以下示例展示了 Vert.x 3.x 版本中如何发送 GET 请求。
HttpClientRequest request = client.get(80, "example.com", "/", response -> {
int statusCode = response.statusCode();
response.exceptionHandler(err -> {
// Handle connection error, for example, connection closed
});
response.bodyHandler(body -> {
// Handle body entirely
});
});
request.exceptionHandler(err -> {
// Handle connection error OR response error
});
request.end(); 以下示例展示了 Vert.x 4 中如何发送 GET 请求。
client.request(HttpMethod.GET, 80, "example.com", "/", ar -> {
if (ar.succeeded()) {
HttpClientRequest = ar.result();
request.send(ar2 -> {
if (ar2.succeeded()) {
HttpClientResponse = ar2.result();
int statusCode = response.statusCode();
response.body(ar3 -> {
if (ar3.succeeded()) {
Buffer body = ar3.result();
// Handle body entirely
} else {
// Handle server error, for example, connection closed
}
});
} else {
// Handle server error, for example, connection closed
}
});
} else {
// Connection error, for example, invalid server or invalid SSL certificate
}
}); 您可以看到新的 HTTP 客户端中错误处理更好。
以下示例展示了 Vert.x 4 中如何在 GET 操作中使用 future 组合。
Future<Buffer> fut = client.request(HttpMethod.GET, 80, "example.com", "/")
.compose(request -> request.send().compose(response -> {
int statusCode = response.statusCode();
if (statusCode == 200) {
return response.body();
} else {
return Future.failedFuture("Unexpectd status code");
}
})
});
fut.onComplete(ar -> {
if (ar.succeeded()) {
Buffer body = ar.result();
// Handle body entirely
} else {
// Handle error
}
}); Future 组合改进了异常处理。该示例检查状态码是否为 200,否则返回错误。
当您将 HTTP 客户端与 futures 一起使用时,HttpClientResponse() 方法在收到响应后立即开始发出缓冲区。为避免这种情况,请确保 future 组合发生在事件循环上(如示例所示),或者它应该暂停并恢复响应。 |
发送请求
在 Vert.x 3.x 版本中,您可以使用 end() 方法发送请求。
request.end(); 您也可以在请求中发送正文。
request.end(Buffer.buffer("hello world)); 由于 HttpClientRequest 是一个 Writestream<Buffer>,您也可以使用管道来流式传输请求。
writeStream.pipeTo(request, ar -> {
if (ar.succeeded()) {
// Sent the stream
}
}); 在 Vert.x 4 中,您可以使用 get() 方法执行示例中显示的所有操作。您还可以使用新的 send() 方法执行这些操作。您可以将缓冲区、字符串或 ReadStream 作为输入传递给 send() 方法。该方法返回一个 HttpClientResponse 实例。
// Send a request and process the response
request.onComplete(ar -> {
if (ar.succeeded()) {
HttpClientResponse response = ar.result();
// Handle the response
}
})
request.end();
// The new send method combines all the operations
request.send(ar -> {
if (ar.succeeded()) {
HttpClientResponse response = ar.result();
// Handle the response
}
})); 处理响应
HttpClientResponse 接口已更新和改进,新增以下方法
body()方法-
body()方法返回一个异步缓冲区。使用body()方法而不是bodyHandler()。以下示例展示了如何使用
bodyHandler()方法获取请求正文。response.bodyHandler(body -> { // Process the request body }); response.exceptionHandler(err -> { // Could not get the request body });以下示例展示了如何使用
body()方法获取请求正文。response.body(ar -> { if (ar.succeeded()) { // Process the request body } else { // Could not get the request body } }); end()方法-
当响应完全成功接收或失败时,
end()方法返回一个 future。该方法移除响应体。请使用此方法而不是endHandler()方法。以下示例展示了如何使用
endHandler()方法。response.endHandler(v -> { // Response ended }); response.exceptionHandler(err -> { // Response failed, something went wrong });以下示例展示了如何使用
end()方法。response.end(ar -> { if (ar.succeeded()) { // Response ended } else { // Response failed, something went wrong } });
您还可以使用 onSucces()、compose()、bodyHandler() 等方法处理响应。以下示例演示了使用 onSuccess() 方法处理响应。
以下示例展示了 Vert.x 3.x 版本中如何将 HTTP 客户端与 result() 方法一起使用。
HttpClient client = vertx.createHttpClient(options);
client.request(HttpMethod.GET, 8443, "localhost", "/")
.onSuccess(request -> {
request.onSuccess(resp -> {
//Code to handle HTTP response
});
}); 以下示例展示了 Vert.x 4 中如何将 HTTP 客户端与 result() 方法一起使用。
HttpClient client = vertx.createHttpClient(options);
client.request(HttpMethod.GET, 8443, "localhost", "/")
.onSuccess(request -> {
request.response().onSuccess(resp -> {
//Code to handle HTTP response
});
}); Vert.x HTTP 客户端的改进
本节描述了 HTTP 客户端的改进。
HTTP 客户端请求和响应方法将异步处理程序作为输入参数
HttpClient 和 HttpClientRequest 方法已更新为使用异步处理程序。这些方法将 Handler<AsyncResult<HttpClientResponse>> 作为输入,而不是 Handler<HttpClientResponse>。
在 Vert.x 的早期版本中,HttpClient 方法 getNow()、optionsNow() 和 headNow() 过去会返回 HttpClientRequest,您必须进一步发送它才能执行请求。getNow()、optionsNow() 和 headNow() 方法已删除。在 Vert.x 4 中,您可以使用 Handler<AsyncResult<HttpClientResponse>> 直接发送带有所需信息的请求。
以下示例展示了 Vert.x 3.x 中如何发送请求。
-
执行 GET 操作
Future<HttpClientResponse> f1 = client.get(8080, "localhost", "/uri", HttpHeaders.set("foo", "bar")); -
使用缓冲区正文进行 POST
Future<HttpClientResponse> f2 = client.post(8080, "localhost", "/uri", HttpHeaders.set("foo", "bar"), Buffer.buffer("some-data")); -
使用流式正文进行 POST
Future<HttpClientResponse> f3 = client.post(8080, "localhost", "/uri", HttpHeaders.set("foo", "bar"), asyncFile);
在 Vert.x 4 中,您可以使用 requests 方法创建 HttpClientRequest 实例。这些方法可用于基本交互,例如
-
发送请求头
-
HTTP/2 特定的操作,例如设置推送处理程序、设置流优先级、ping 等。
-
创建 NetSocket 隧道
-
提供细粒度写入控制
-
重置流
-
手动处理 100 continue 头
以下示例展示了如何在 Vert.x 4 中创建 HTTPClientRequest。
client.request(HttpMethod.GET, 8080, "example.com", "/resource", ar -> {
if (ar.succeeded()) {
HttpClientRequest request = ar.result();
request.putHeader("content-type", "application/json")
request.send(new JsonObject().put("hello", "world"))
.onSuccess(response -> {
//
}).onFailure(err -> {
//
});
}
}) 已从 HTTP 客户端请求中删除连接处理程序方法
HttpClientRequest.connectionHandler() 方法已删除。请改用 HttpClient.connectionHandler() 方法来调用应用程序中客户端请求的连接处理程序。
以下示例展示了 Vert.x 3.x 版本中如何使用 HttpClientRequest.connectionHandler() 方法。
client.request().connectionHandler(conn -> {
// Connection related code
}).end(); 以下示例展示了如何使用新的 HttpClient.connectionHandler() 方法。
client.connectionHandler(conn -> {
// Connection related code
}); 使用 net socket 方法进行 HTTP 客户端隧道
HTTP 隧道可以使用 HttpClientResponse.netSocket() 方法创建。在 Vert.x 4 中,此方法已更新。
要获取请求连接的 net socket,请在请求中发送一个 socket 处理程序。当收到 HTTP 响应头时,将调用该处理程序。socket 已准备好进行隧道传输,可以发送和接收缓冲区。
以下示例展示了 Vert.x 3.x 版本中如何获取连接的 net socket。
client.request(HttpMethod.CONNECT, uri, ar -> {
if (ar.succeeded()) {
HttpClientResponse response = ar.result();
if (response.statusCode() == 200) {
NetSocket so = response.netSocket();
}
}
}).end(); 以下示例展示了 Vert.x 4 中如何获取连接的 net socket。
client.request(HttpMethod.CONNECT, uri, ar -> {
}).netSocket(ar -> {
if (ar.succeeded()) {
// Got a response with a 200 status code
NetSocket so = ar.result();
// Go for tunneling
}
}).end(); HttpClient 类中的新 send() 方法
HttpClient 类中新增了一个 send() 方法。
以下代码展示了 Vert.x 4 中如何发送请求。
Future<HttpClientResponse> f1 = client.send(HttpMethod.GET, 8080, "localhost", "/uri", HttpHeaders.set("foo", "bar")); HttpHeaders 是一个接口,包含 MultiMap 方法
在 Vert.x 4 中,HttpHeaders 是一个接口。在 Vert.x 的早期版本中,HttpHeaders 是一个类。
以下新的 MultiMap 方法已添加到 HttpHeaders 接口中。使用这些方法创建 MultiMap 实例。
-
MultiMap.headers() -
MultiMap.set(CharSequence name, CharSequence value) -
MultiMap.set(String name, String value)
以下示例展示了 Vert.x 3.x 版本中如何创建 MultiMap 实例。
MultiMap headers = MultiMap.caseInsensitiveMultiMap(); 以下示例展示了 Vert.x 4 中如何创建 MultiMap 实例。
MultiMap headers = HttpHeaders.headers(); MultiMap headers = HttpHeaders.set("content-type", "application.data"); CaseInsensitiveHeaders 类不再是 public 的
CaseInsensitiveHeaders 类不再是公共的。使用 MultiMap.caseInsensitiveMultiMap() 方法创建具有不区分大小写键的多映射实现。
以下示例展示了 Vert.x 3.x 版本中如何使用 CaseInsensitiveHeaders 方法。
CaseInsensitiveHeaders headers = new CaseInsensitiveHeaders(); 以下示例展示了 Vert.x 4 中如何使用 MultiMap 方法。
MultiMap multiMap = MultiMap#caseInsensitiveMultiMap(); 或
MultiMap headers = HttpHeaders.headers(); 检查服务器上运行的 HTTP 版本
在 Vert.x 的早期版本中,只有当应用程序明确调用 HttpServerRequest.version() 方法时,才会检查服务器上运行的 HTTP 版本。如果 HTTP 版本是 HTTP/1.x,该方法将返回 501 HTTP 状态,并关闭连接。
从 Vert.x 4 开始,在向服务器发送请求之前,通过调用 HttpServerRequest.version() 方法会自动检查服务器上的 HTTP 版本。当发现无效的 HTTP 版本时,该方法返回 HTTP 版本而不是抛出异常。
请求选项中的新方法
在 Vert.x 4 中,RequestOptions 类中提供了以下新方法
-
Header
-
FollowRedirects
-
Timeout
以下示例展示了如何使用新方法。
client.request(HttpMethod.GET, 8080, "example.com", "/resource", ar -> {
if (ar.succeeded()) {
HttpClientRequest request = ar.result();
request.putHeader("content-type", "application/json")
request.send(new JsonObject().put("hello", "world"))
.onSuccess(response -> {
//
}).onFailure(err -> {
//
});
}
}) 连接方法中的变化
本节解释了连接方法中的变化。
检查客户端是否需要身份验证
NetServerOptions.isClientAuthRequired() 方法已删除。使用枚举类型 getClientAuth() == ClientAuth.REQUIRED 来检查是否需要客户端身份验证。
以下示例展示了如何使用 switch 语句检查客户端是否需要身份验证。
switch (options.getClientAuth()) {
case REQUIRED:
// ... behavior same as in releases prior to {VertX} {v4}
break;
default:
// fallback statement...
} 以下示例展示了 Vert.x 4 中如何检查客户端是否需要身份验证。
if (options.getClientAuth() == ClientAuth.REQUIRED) {
// behavior in releases prior to {VertX} {v4} 升级 SSL 方法使用异步处理程序
NetSocket.upgradeToSsl() 方法已更新为使用 Handler<AsyncResult> 而不是 Handler。该处理程序用于检查通道是否已成功升级到 SSL 或 TLS。
日志记录中的变化
本节解释了日志记录中的变化。
已弃用的日志记录类和方法
日志记录类 Logger 和 LoggerFactory 及其方法已弃用。这些日志记录类和方法将在未来的版本中删除。
已删除 Log4j 1 日志记录器
Log4j 1 日志记录器不再可用。但是,如果您想使用 Log4j 1 日志记录器,它可通过 SLF4J 获得。
Vert.x Reactive Extensions (Rx) 中的变化
本节描述了 Vert.x 中 Reactive Extensions (Rx) 的变化。Vert.x 使用 RxJava 库。
支持 RxJava 3
从 Vert.x 4.1.0 开始,支持 RxJava 3。
-
在
io.vertx.rxjava3包中提供了一个新的 rxified API。 -
通过
vertx-junit5-rx-java3绑定提供了与 Vert.x JUnit5 的集成。
要升级到 RxJava 3,您必须进行以下更改
-
在
pom.xml文件中,在<dependency>下,将 RxJava 1 和 2 绑定从vertx-rx-java或vertx-rx-java2更改为vertx-rx-java3。 -
在您的应用程序中,将导入从
io.vertx.reactivex.*更新为io.vertx.rxjava3.*。 -
在您的应用程序中,也请更新 RxJava 3 类型的导入。有关更多信息,请参阅 RxJava 3 文档中的“新增功能”部分。
从写入流中删除了 onComplete 回调
WriteStreamSubscriber.onComplete() 回调已删除。如果 WriteStream 有待写入的数据流,则会调用此回调。
在 Vert.x 4 中,请改用回调 WriteStreamSubscriber.onWriteStreamEnd() 和 WriteStreamSubscriber.onWriteStreamError()。这些回调在 WriteStream.end() 完成后调用。
WriteStreamSubscriber<Buffer> subscriber = writeStream.toSubscriber(); 以下示例展示了 Vert.x 3.x 版本中如何从 WriteStream 创建适配器。
subscriber.onComplete(() -> {
// Called after writeStream.end() is invoked, even if operation has not completed
}); 以下示例展示了 Vert.x 4 版本中如何使用新的回调方法从 WriteStream 创建适配器
subscriber.onWriteStreamEnd(() -> {
// Called after writeStream.end() is invoked and completes successfully
}); subscriber.onWriteStreamError(() -> {
// Called after writeStream.end() is invoked and fails
}); Vert.x 配置中的变化
以下部分描述了 Vert.x 配置中的变化。
检索配置的新方法
ConfigRetriever.getConfigAsFuture() 方法已删除。请改用 retriever.getConfig() 方法。
以下示例展示了 Vert.x 3.x 版本中如何检索配置。
Future<JsonObject> fut = ConfigRetriever. getConfigAsFuture(retriever); 以下示例展示了 Vert.x 4 中如何检索配置。
fut = retriever.getConfig(); JSON 中的变化
本节描述 JSON 中的变化。
Jackson 的封装
JSON 类中实现 Jackson 类型的所有方法都已删除。请改用以下方法
| 已删除字段/方法 | 新方法 |
|---|---|
|
|
|
|
|
|
|
|
例如,使用以下代码
-
使用 Jackson
TypeReference时-
在 Vert.x 3.x 版本中
List<Foo> foo1 = Json.decodeValue(json, new TypeReference<List<Foo>>() {}); -
在 Vert.x 4 版本中
List<Foo> foo2 = io.vertx.core.json.jackson.JacksonCodec.decodeValue(json, new TypeReference<List<Foo>>() {});
-
-
引用
ObjectMapper-
在 Vert.x 3.x 版本中
ObjectMapper mapper = Json.mapper; -
在 Vert.x 4 版本中
mapper = io.vertx.core.json.jackson.DatabindCodec.mapper();
-
-
设置
ObjectMapper-
在 Vert.x 3.x 版本中
Json.mapper = someMapper; -
从 Vert.x 4 开始,您不能写入映射器实例。您应该使用自己的静态映射器或配置
Databind.mapper()实例。
-
对象映射
在早期版本中,Jackson 核心和 Jackson databind 依赖项在运行时是必需的。
从 Vert.x 4 开始,只需要 Jackson 核心依赖项。
仅当您进行 JSON 对象映射时才需要 Jackson databind 依赖项。在这种情况下,您必须在项目描述符中明确添加 com.fasterxml.jackson.core:jackson-databind jar 依赖项。
以下方法支持所述类型。
-
方法
-
JsonObject.mapFrom(Object) -
JsonObject.mapTo(Class) -
Json.decodeValue(Buffer, Class) -
Json.decodeValue(String, Class) -
Json.encode(Object) -
Json.encodePrettily(Object) -
Json.encodeToBuffer(Object)
-
-
类型
-
JsonObject和JsonArray -
Map和List -
Number -
Boolean -
Enum -
byte[]和Buffer -
Instant
-
以下方法仅支持 Jackson bind
-
JsonObject.mapTo(Object) -
JsonObject.mapFrom(Object)
Base64 编码器已更新为 JSON 对象和数组的 Base64URL
Vert.x JSON 类型实现了 RFC-7493。在 Vert.x 的早期版本中,实现错误地使用了 Base64 编码器而不是 Base64URL。这在 Vert.x 4 中已修复,JSON 类型中使用了 Base64URL 编码器。
如果您想在 Vert.x 4 中继续使用 Base64 编码器,可以使用配置标志 legacy。以下示例展示了 Vert.x 4 中如何设置配置标志。
java -Dvertx.json.base64=legacy ... 在您从 Vert.x 3.x 迁移到 Vert.x 4 的过程中,如果您已部分迁移应用程序,那么您将同时拥有版本 3 和 4 的应用程序。在这种情况下,您有两个 Vert.x 版本,您可以使用以下实用程序将 Base64 字符串转换为 Base64URL。
public String toBase64(String base64Url) {
return base64Url
.replace('+', '-')
.replace('/', '_');
}
public String toBase64Url(String base64) {
return base64
.replace('-', '+')
.replace('_', '/');
} 您必须在以下场景中使用实用方法
-
在从 Vert.x 3.x 版本迁移到 Vert.x 4 时处理集成。
-
处理与使用 Base64 字符串的其他系统的互操作性。
使用以下示例代码将 Base64URL 转换为 Base64 编码器。
String base64url = someJsonObject.getString("base64encodedElement")
String base64 = toBase64(base64url); 辅助函数 {toBase64} 和 {toBase64Url} 仅支持 JSON 迁移。如果您在应用程序中使用对象映射来自动将 JSON 对象映射到 {Java} POJO,那么您必须创建一个自定义对象映射器来将 Base64 字符串转换为 Base64URL。
以下示例展示了如何创建带有自定义 Base64 解码器的对象映射器。
// simple deserializer from Base64 to byte[]
class ByteArrayDeserializer extends JsonDeserializer<byte[]> {
ByteArrayDeserializer() {
}
public byte[] deserialize(JsonParser p, DeserializationContext ctxt) {
String text = p.getText();
return Base64.getDecoder()
.decode(text);
}
}
// ...
ObjectMapper mapper = new ObjectMapper();
// create a custom module to address the Base64 decoding
SimpleModule module = new SimpleModule();
module.addDeserializer(byte[].class, new ByteArrayDeserializer());
mapper.registerModule(module);
// JSON to POJO with custom deserializer
mapper.readValue(json, MyClass.class); 已从 trust options 中删除 JSON 转换器方法
TrustOptions.toJSON 方法已删除。
Vert.x Web 中的变化
以下部分描述了 Vert.x Web 中的变化。
用户会话处理程序的功能合并到会话处理程序中
在 Vert.x 的早期版本中,在会话中工作时,您必须同时指定 UserSessionHandler 和 SessionHandler 处理程序。
为了简化该过程,在 Vert.x 4 中,UserSessionHandler 类已删除,其功能已添加到 SessionHandler 类中。在 Vert.x 4 中,要使用会话,您只需指定一个处理程序。
已删除 cookie 接口
以下 cookie 接口已删除
-
io.vertx.ext.web.Cookie -
io.vertx.ext.web.handler.CookieHandler
请改用 io.vertx.core.http.Cookie 接口。
Favicon 和错误处理程序使用 Vertx 文件系统
FaviconHandler 和 ErrorHandler 中的 create 方法已更新。您必须在 create 方法中传递一个 Vertx 实例对象。这些方法访问文件系统。传递 Vertx 对象可确保使用 'Vertx' 文件系统一致地访问文件。
以下示例展示了 Vert.x 3.x 版本中 create 方法的使用方式。
FaviconHandler.create();
ErrorHandler.create(); 以下示例展示了 Vert.x 4 中 create 方法的使用方式。
FaviconHandler.create(vertx);
ErrorHandler.create(vertx); 访问模板引擎
使用方法 TemplateEngine.unwrap() 访问模板引擎。然后您可以对模板应用自定义和配置。
以下用于获取和设置引擎配置的方法已弃用。请改用 TemplateEngine.unwrap() 方法。
-
HandlebarsTemplateEngine.getHandlebars() -
HandlebarsTemplateEngine.getResolvers() -
HandlebarsTemplateEngine.setResolvers() -
JadeTemplateEngine.getJadeConfiguration() -
ThymeleafTemplateEngine.getThymeleafTemplateEngine() -
ThymeleafTemplateEngine.setMode()
已删除 locale 接口
io.vertx.ext.web.Locale 接口已删除。请改用 io.vertx.ext.web.LanguageHeader 接口。
已删除可接受的区域设置方法
RoutingContext.acceptableLocales() 方法已删除。请改用 RoutingContext.acceptableLanguages() 方法。
子路由器挂载方法的更新
在 Vert.x 的早期版本中,Router.mountSubRouter() 方法错误地返回了一个 Router。这已修复,该方法现在返回一个 Route。
已删除 JWT 身份验证处理的 create 方法,其中包含 excluded 字符串
JWTAuthHandler.create(JWTAuth authProvider, String skip) 方法已删除。请改用 JWTAuthHandler.create(JWTAuth authProvider) 方法。
以下示例展示了 Vert.x 3.x 版本中 JWT 认证处理程序的创建方式。
router
// protect everything but "/excluded/path"
.route().handler(JWTAuthHandler(jwtAuth, "/excluded/path") 以下示例展示了 Vert.x 4 中 JWT 认证处理程序的创建方式。
router
.route("/excluded/path").handler(/* public access to "/excluded/path" */)
// protect everything
.route().handler(JWTAuthHandler(jwtAuth) 已删除在 OSGi 环境中使用的 create handler 方法
在 Vert.x 4 中,不再支持 OSGi 环境。StaticHandler.create(String, ClassLoader) 方法已删除,因为该方法用于 OSGi 环境。
如果您在应用程序中使用了此方法,那么在 Vert.x 4 中,您可以将资源添加到应用程序 classpath 或从文件系统提供资源。
已删除桥接选项类
sockjs.BridgeOptions 类已删除。请改用新的 sockjs.SockJSBridgeOptions 类。sockjs.SockJSBridgeOptions 类包含了配置事件总线桥所需的所有选项。
新类的行为没有变化,只是数据对象类的名称已更改。
在早期版本中,当您使用 sockjs.BridgeOptions 类添加新桥时,存在大量重复配置。新类包含所有可能的通用配置,并消除了重复配置。
SockJS socket 事件总线默认不注册集群事件
SockJSSocket 默认不再注册集群事件总线消费者。如果您想使用事件总线写入 socket,必须在 SockJSHandlerOptions 中启用 writeHandler。当您启用 writeHandler 时,事件总线消费者默认设置为本地。
Router router = Router.router(vertx);
SockJSHandlerOptions options = new SockJSHandlerOptions()
.setRegisterWriteHandler(true); // enable the event bus consumer registration
SockJSHandler sockJSHandler = SockJSHandler.create(vertx, options);
router.mountSubRouter("/myapp", sockJSHandler.socketHandler(sockJSSocket -> {
// Retrieve the writeHandlerID and store it (For example, in a local map)
String writeHandlerID = sockJSSocket.writeHandlerID();
})); 您可以将事件总线消费者配置到集群。
SockJSHandlerOptions options = new SockJSHandlerOptions()
.setRegisterWriteHandler(true) // enable the event bus consumer registration
.setLocalWriteHandler(false) // register a clustered event bus consumer 添加身份验证提供程序的新方法
SessionHandler.setAuthProvider(AuthProvider) 方法已弃用。请改用 SessionHandler.addAuthProvider() 方法。新方法允许应用程序与多个身份验证提供程序一起工作,并将会话对象链接到这些身份验证提供程序。
OAuth2 身份验证提供程序的 create 方法需要 vertx 作为构造函数参数
从 Vert.x 4 开始,OAuth2Auth.create(Vertx vertx) 方法需要 vertx 作为构造函数参数。vertx 参数使用安全的非阻塞随机数生成器生成 nonce,这确保了应用程序更好的安全性。
Vert.x Web GraphQL 中的变化
以下部分描述了 Vert.x Web GraphQL 中的变化。
更新了方法以支持多种语言(多语种)环境
以下方法已更新并现在支持多语言环境:* UploadScalar 现在是一个工厂,请改用方法 UploadScalar.create()。
-
VertxBatchLoader现在是一个工厂,请改用方法io.vertx.ext.web.handler.graphql.dataloader.VertxBatchLoader.create()。 -
VertxDataFetcher现在是一个工厂,请改用方法io.vertx.ext.web.handler.graphql.schema.VertxDataFetcher.create()。 -
VertxPropertyDataFetcher现在是一个工厂,请改用方法io.vertx.ext.web.handler.graphql.schema.VertxPropertyDataFetcher.create()。
处理 Vert.x Web GraphQL 中的 POST 请求
在以前的版本中,Vert.x Web GraphQL 处理程序可以处理自己的 POST 请求。它不需要 Vert.x Web BodyHandler 来处理请求。但是,这种实现容易受到 DDoS 攻击。
从 Vert.x 4 开始,处理 POST 请求需要 BodyHandler。您必须在安装 Vert.x Web GraphQL 处理程序之前安装 BodyHandler。
Micrometer 指标中的变化
以下部分描述了 Micrometer 指标中的变化。
TCP 发送和接收字节记录为计数器,并带有等效的 HTTP 请求和响应摘要
在以前的版本中,以下指标被记录为 socket 的分布摘要。从 Vert.x 4 开始,这些指标被记录为计数器,报告交换的数据量。
-
Net 客户端
-
vertx_net_client_bytes_read -
vertx_net_client_bytes_written
-
-
Net 服务器
-
vertx_net_server_bytes_read -
vertx_net_server_bytes_written
-
对于这些计数器,已引入等效的 HTTP 分布摘要。这些摘要用于收集有关请求和响应大小的信息。
-
HTTP 客户端
-
vertx_http_client_request_bytes -
vertx_http_client_response_bytes
-
-
HTTP 服务器
-
vertx_http_server_request_bytes -
vertx_http_server_response_bytes
-
已重命名指标
以下指标已重命名。
| 旧指标名称 | 新指标名称 | 组件中已更新 |
|---|---|---|
|
| Net 客户端和服务器 HTTP 客户端和服务器 |
|
| 数据报 Net 客户端和服务器 HTTP 客户端和服务器 |
|
| 数据报 Net 客户端和服务器 HTTP 客户端和服务器 |
|
| HTTP 客户端 HTTP 服务器 |
|
| HTTP 客户端 HTTP 服务器 |
|
| HTTP 客户端 HTTP 服务器 |
|
| HTTP 客户端 HTTP 服务器 |
|
| HTTP 客户端 HTTP 服务器 |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
|
Vert.x OpenAPI 中的变化
在 Vert.x 4 中,新增了一个模块 vertx-web-openapi。将此模块与 vertx-web 一起使用,以开发契约驱动的应用程序。
新模块与 Vert.x Web Router 配合良好。新模块需要以下 Vert.x 依赖项
-
vertx-json-schema -
vertx-web-validation
新模块位于 io.vertx.ext.web.openapi 包中。
在 Vert.x 4 中,支持旧的 OpenAPI 模块 vertx-web-api-contract,以方便迁移到新模块。建议您迁移到新的模块 vertx-web-openapi 以利用新功能。
新模块使用路由器构建器
vertx-web-openapi 模块使用 RouterBuilder 构建 Vert.x Web 路由器。此路由器构建器类似于 vertx-web-api-contract 模块中的路由器构建器 OpenAPI3RouterFactory。
要开始使用 vertx-web-openapi 模块,请实例化 RouterBuilder。
RouterBuilder.create(vertx, "petstore.yaml").onComplete(ar -> {
if (ar.succeeded()) {
// Spec loaded with success
RouterBuilder routerBuilder = ar.result();
} else {
// Something went wrong during router builder initialization
Throwable exception = ar.cause();
}
}); 您也可以使用 futures 实例化 RouterBuilder。
RouterBuilder.create(vertx, "petstore.yaml")
.onSuccess(routerBuilder -> {
// Spec loaded with success
})
.onFailure(exception -> {
// Something went wrong during router builder initialization
}); vertx-web-openapi 模块使用 Vert.x 文件系统 API 加载文件。因此,您无需为 classpath 资源指定 /。例如,您可以在应用程序中指定 petstore.yaml。RouterBuilder 可以从您的 classpath 资源中识别契约。 |
新路由器构建器方法
在大多数情况下,您可以搜索并替换旧 OpenAPI3RouterFactory 方法的使用,改用新的 RouterBuilder 方法。下表列出了旧方法和新方法的一些示例。
旧 OpenAPI3RouterFactory 方法 | 新 RouterBuilder 方法 |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
使用以下语法访问解析的请求参数
RequestParameters parameters = routingContext.get(io.vertx.ext.web.validation.ValidationHandler.REQUEST_CONTEXT_KEY);
int aParam = parameters.queryParameter("aParam").getInteger(); 处理安全
在 Vert.x 4 中,方法 RouterFactory.addSecurityHandler() 和 OpenAPI3RouterFactory.addSecuritySchemaScopeValidator() 不再可用。
请改用 RouterBuilder.securityHandler() 方法。此方法接受 io.vertx.ext.web.handler.AuthenticationHandler 作为处理程序。该方法自动识别 OAuth2Handler 并设置安全模式。
新的安全处理程序还实现了 OpenAPI 规范中定义的操作。
处理常见故障
在 vertx-web-openapi 模块中,以下故障处理程序不可用。您必须使用 Router.errorHandler(int, Handler) 方法设置故障处理程序。
vertx-web-api-contract 模块中的旧方法 | vertx-web-openapi 模块中的新方法 |
|---|---|
|
|
|
|
访问 OpenAPI 契约模型
在 Vert.x 4 中,OpenAPI 契约不再映射到纯旧 Java 对象 (POJO)。因此,不再需要额外的 swagger-parser 依赖项。您可以使用 getter 和 resolver 来检索契约的特定组件。
以下示例展示了如何使用单个操作检索特定组件。
JsonObject model = routerBuilder.operation("getPets").getOperationModel(); 以下示例展示了如何检索完整契约。
JsonObject contract = routerBuilder.getOpenAPI().getOpenAPI(); 以下示例展示了如何解析契约的部分内容。
JsonObject petModel = routerBuilder.getOpenAPI().getCached(JsonPointer.from("/components/schemas/Pet")); 在没有 OpenAPI 的情况下验证 Web 请求
在 vertx-web-api-contract 模块中,您可以使用 HTTPRequestValidationHandler 验证 HTTP 请求。您无需使用 OpenAPI 进行验证。
在 Vert.x 4 中,要验证 HTTP 请求,请使用 vertx-web-validation 模块。您可以导入此模块并在不使用 OpenAPI 的情况下验证请求。使用 ValidationHandler 验证请求。
Vert.x Web API 服务中的更新
vertx-web-api-service 模块已更新,可与 vertx-web-validation 模块一起使用。如果您正在使用 vertx-web-openapi 模块,则 Web 服务功能没有变化。
但是,如果您不使用 OpenAPI,那么要将 Web 服务模块与 vertx-web-validation 模块一起使用,您必须使用 RouteToEBServiceHandler 类。
router.get("/api/transactions")
.handler(
ValidationHandlerBuilder.create(schemaParser)
.queryParameter(optionalParam("from", stringSchema()))
.queryParameter(optionalParam("to", stringSchema()))
.build()
).handler(
RouteToEBServiceHandler.build(eventBus, "transactions.myapplication", "getTransactionsList")
); vertx-web-api-service 模块不支持 vertx-web-api-contract。因此,当您升级到 Vert.x 4 时,您必须将 Vert.x OpenAPI 应用程序迁移到 vertx-web-openapi 模块。
微服务模式中的变化
本节解释了微服务模式中的变化。
Vert.x 断路器中的变化
以下部分描述了 Vert.x 断路器中的变化。
已从断路器中删除执行命令方法
以下方法已从 CircuitBreaker 类中删除,因为它们不能与 futures 一起使用。
| 已删除方法 | 替换方法 |
|---|---|
|
|
|
|
Vert.x 服务发现中的变化
以下部分描述了 Vert.x 服务发现中的变化。
从服务发现中删除了包含 ServiceDiscovery 参数的创建方法
服务发现中以下以 Handler<ServiceDiscovery> 作为参数的创建方法已删除。这些方法不能与 futures 一起使用。
| 已删除方法 | 替换方法 |
|---|---|
|
|
|
|
服务导入器和导出器方法不再是 fluent 的
ServiceDiscovery.registerServiceImporter() 和 ServiceDiscovery.registerServiceExporter() 方法不再是 fluent 的。这些方法返回 Future<Void>。
Kubernetes 服务导入器不再自动注册
vertx-service-discovery-bridge-kubernetes 添加了 KubernetesServiceImporter 发现桥。该桥将服务从 Kubernetes 或 Openshift 导入到 Eclipse Vert.x 服务发现中。
从 Vert.x 4 开始,此桥不再自动注册。即使您已将该桥添加到项目的 classpath 中,它也不会自动注册。
您必须在创建 ServiceDiscovery 实例后手动注册桥。
以下示例展示了如何手动注册桥。
JsonObject defaultConf = new JsonObject();
serviceDiscovery.registerServiceImporter(new KubernetesServiceImporter(), defaultConf); Vert.x 身份验证和授权中的变化
以下部分描述了 Vert.x 身份验证和授权中的变化。
Vert.x 身份验证模块在 Vert.x 4 中有重大更新。io.vertx.ext.auth.AuthProvider 接口已拆分为两个新接口
-
io.vertx.ext.auth.authentication.AuthenticationProvider -
io.vertx.ext.auth.authorization.AuthorizationProvider
此更新使任何提供程序都能独立执行身份验证和授权。
迁移身份验证应用程序
身份验证机制在结果级别发生了变化。在早期版本中,结果是一个 User 对象,它是特定于提供程序的。在 Vert.x 4 中,结果是 io.vertx.ext.auth.User 的一个通用实现。
以下示例展示了 Vert.x 3.x 版本中用户身份验证的方式。
JsonObject authInfo = new JsonObject()
.put("username", "john")
.put("password", "super$ecret");
// omitting the error handling for brevity
provider.authenticate(authInfo, res -> {
if (res.succeeded()) {
// may require type casting for example on Oauth2
User user = res.result();
}
}); 以下示例展示了 Vert.x 4 中如何验证用户身份。
JsonObject authInfo = new JsonObject()
.put("username", "john")
.put("password", "super$ecret");
// omitting the error handling for brevity
provider.authenticate(authInfo, res -> {
if (res.succeeded()) {
// Never needs type casting
User user = res.result();
}
}); 迁移授权应用程序
授权是 Vert.x 4 中的一个新功能。在早期版本中,您只能检查用户是否被授权在 User 对象上执行任务。这意味着提供程序负责用户的身份验证和授权。
在 Vert.x 4 中,User 对象实例不与特定的身份验证提供程序关联。因此,您可以使用不同的提供程序对用户进行身份验证和授权。例如,您可以使用 OAuth2 对用户进行身份验证,并针对 MongoDB 或 SQL 数据库执行授权检查。
以下示例展示了 Vert.x 3.x 版本中应用程序如何检查用户是否可以使用打印机 #1234。
// omitting the error handling for brevity
user.isAuthorized("printers:printer1234", res -> {
if (res.succeeded()) {
boolean hasAuthority = res.result();
if (hasAuthority) {
System.out.println("User can use the printer");
} else {
System.out.println("User cannot use the printer");
}
}
}); 此授权适用于 JDBC 和 MongoDB。但是,它不适用于 OAuth2 等提供程序,因为该提供程序不执行授权检查。从 Vert.x 4 开始,可以通过使用不同的提供程序执行此类授权检查。
// omitting the error handling for brevity
provider.getAuthorizations(user, res -> {
if (res.succeeded()) {
if (PermissionBasedAuthorization.create("printer1234").match(user)) {
System.out.println("User can use the printer");
} else {
System.out.println("User cannot use the printer");
}
}
}); 您可以检查角色、权限、逻辑操作、通配符以及您添加的任何其他实现的授权。
密钥管理中的变化
在 Vert.x 4 中,密钥处理有重大更新。最重要的变化是,当密钥加载时,公共缓冲区和私有缓冲区之间没有区别。
以下类已更新
-
io.vertx.ext.auth.KeyStoreOptions过去用于处理jce密钥库 -
io.vertx.ext.auth.SecretOptions过去用于处理对称密钥 -
io.vertx.ext.auth.PubSecKeyOptions过去用于处理公共密钥
以下部分描述了密钥管理中的变化。
Secret options 类不再可用
SecretOptions 类不再可用。请改用新的 PubSecKeyOptions 类来处理加密密钥。
以下示例展示了 Vert.x 3.x 版本中 SecretOptions 类方法的使用方式。
new SecretOptions()
.setType("HS256")
.setSecret("password") 以下示例展示了 Vert.x 4 中 PubSecKeyOptions 类方法的使用方式。
new PubSecKeyOptions()
.setAlgorithm("HS256")
.setBuffer("password") 公共密钥管理中的更新
在 Vert.x 3.x 中,公共密钥管理中的配置对象假定
-
密钥配置为密钥对。
-
密钥数据是没有标准分隔符的 PKCS8 编码字符串。
以下示例展示了 Vert.x 3.x 中如何配置密钥对。
new PubSecKeyOptions()
.setPublicKey(
// remove the PEM boundaries
pubPemString
.replaceAll("-----BEGIN PUBLIC KEY----")
.replaceAll("-----END PUBLIC KEY----"))
.setSecretKey(
// remove the PEM boundaries
secPemString
.replaceAll("-----BEGIN PUBLIC KEY----")
.replaceAll("-----END PUBLIC KEY----")); 在 Vert.x 4 中,您必须同时指定公钥和私钥。
以下示例展示了 Vert.x 4 中如何配置密钥对。
PubSecKeyOptions pubKey =
new PubSecKeyOptions()
// the buffer is the exact contents of the PEM file and had boundaries included in it
.setBuffer(pubPemString);
PubSecKeyOptions secKey =
new PubSecKeyOptions()
// the buffer is the exact contents of the PEM file and had boundaries included in it
.setBuffer(secPemString); 您现在可以使用 PubSecKeyOptions 处理 X509 证书。
PubSecKeyOptions x509Certificate =
new PubSecKeyOptions()
// the buffer is the exact contents of the PEM file and had boundaries included in it
.setBuffer(x509PemString); 密钥库管理中的变化
在 Vert.x 3.x 中,KeyStoreOptions 假定密钥库格式为 jceks,并且存储的密码与密钥的密码相同。由于 jceks 是专有格式,建议改用标准格式,例如 JDK。
在 Vert.x 4 中使用 KeyStoreOptions 时,您可以指定存储类型。例如,可以设置 PKCS11、PKCS12 等存储类型。默认存储类型为 jceks。
在 Vert.x 3.x 中,所有密钥库条目都共享相同的密码,即密钥库密码。在 Vert.x 4 中,每个密钥库条目都可以有专用的密码。如果您不想为每个密钥库条目设置密码,可以将密钥库密码配置为所有条目的默认密码。
以下示例展示了 Vert.x 3.x 中如何加载 jceks 密钥库。
new KeyStoreOptions()
.setPath("path/to/keystore.jks")
.setPassword("keystore-password"); 在 Vert.x 4 中,默认格式被假定为 JDK 配置的默认格式。在 Java 9 及更高版本中,格式为 PKCS12。
以下示例展示了 Vert.x 4 中如何加载 jceks 密钥库。
new KeyStoreOptions()
.setPath("path/to/keystore.jks")
// Modern JDKs use `jceks` keystore. But this type is not the default
// If the type is not set to `jceks` then probably `pkcs12` will be used
.setType("jceks")
.setPassword("keystore-password")
// optionally if your keys have different passwords
// and if a key specific id is not provided it defaults to
// the keystore password
.putPasswordProtection("key-id", "key-specific-password"); 已弃用和删除的身份验证和授权方法
以下各节列出了已弃用和删除的身份验证和授权方法。
已删除的身份验证和授权方法列表
以下方法已删除
| 已删除方法 | 替换方法 |
|---|---|
|
|
|
|
|
|
|
|
| 无替换方法 |
|
|
|
|
| 无替换方法 |
| 无替换方法 |
已弃用的身份验证和授权方法列表
以下方法已弃用
| 已弃用方法 | 替换方法 |
|---|---|
|
|
|
|
| 无替换方法 |
|
|
| 无替换方法 |
已弃用的身份验证和授权类列表
以下类已弃用
| 已弃用类 | 替换类 |
|---|---|
| 使用 |
| 无替换类 |
| 用于身份验证的 |
| 无替换类 |
|
|
| 建议使用 |
| 无替换类 |
协议中的变化
本节解释了网络协议中的变化。
Vert.x gRPC 中的变化
以下部分描述了 Vert.x gRPC 中的变化。
新 gRPC 编译器插件
在 Vert.x 4 中,模块 protoc-gen-grpc-java 不再可用。此模块是官方 gRPC 编译器的分支。在 Vert.x 的早期版本中,您必须使用此分支。此分支由 Eclipse 项目维护。使用该分支很复杂。
在以前的版本中,要使用 gRPC,以下详细信息已添加到 pom.xml 文件中。
<!-- Vert.x 3.x -->
<plugin>
<groupId>org.xolstice.maven.plugins</groupId>
<artifactId>protobuf-maven-plugin</artifactId>
<configuration>
<protocArtifact>com.google.protobuf:protoc:3.2.0:exe:${os.detected.classifier}</protocArtifact>
<pluginId>grpc-java</pluginId>
<!-- NOTE: the gav coordinates point to the 3.x only compiler fork -->
<pluginArtifact>io.vertx:protoc-gen-grpc-java:${vertx.grpc.version}:exe:${os.detected.classifier}</pluginArtifact>
</configuration>
...
</plugin> 在 Vert.x 4 中,一个新的 gRPC 编译器插件可用。此插件使用官方 gRPC 编译器而不是分支。要使用新的 gRPC 插件,请将以下详细信息添加到 pom.xml 文件中。
<!-- Vert.x 4.0 -->
<plugin>
<groupId>org.xolstice.maven.plugins</groupId>
<artifactId>protobuf-maven-plugin</artifactId>
<configuration>
<protocArtifact>com.google.protobuf:protoc:3.2.0:exe:${os.detected.classifier}</protocArtifact>
<pluginId>grpc-java</pluginId>
<!-- NOTE: the gav coordinates point to the official compiler -->
<pluginArtifact>io.grpc:protoc-gen-grpc-java:${vertx.grpc.version}:exe:${os.detected.classifier}</pluginArtifact>
<protocPlugins>
<!-- NEW: a plugin is added to generate the Vert.x specific code -->
<protocPlugin>
<id>vertx-grpc-protoc-plugin</id>
<groupId>io.vertx</groupId>
<artifactId>vertx-grpc-protoc-plugin</artifactId>
<version>${vertx.version}</version>
<mainClass>io.vertx.grpc.protoc.plugin.VertxGrpcGenerator</mainClass>
</protocPlugin>
</protocPlugins>
</configuration>
...
</plugin> 迁移生成的代码
在 Vert.x 4 中,使用了新的编译器。当使用新的 gRPC 插件时,生成的代码不会写入同一个源文件。这是因为编译器不允许在其基类上进行自定义代码生成。插件必须生成一个具有不同名称的新类来保存代码。
在 Vert.x 的早期版本中,旧的 gRPC 插件会将生成的代码写入同一个源文件。
例如,如果您有以下描述符
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply) {}
} 在 Vert.x 3.x 中,代码将在 GreeterGrpc 类中生成。
// 3.x
GreeterGrpc.GreeterVertxImplBase service =
new GreeterGrpc.GreeterVertxImplBase() {
...
} 在 Vert.x 4 中,代码将在 VertxGreeterGrpc 类中生成。
// 4.x
VertxGreeterGrpc.GreeterVertxImplBase service =
new VertxGreeterGrpc.GreeterVertxImplBase() {
...
} gRPC API 支持 futures
在 Vert.x 4 中,gRPC API 支持 futures。gRPC 插件生成 promisified API。这些 API 使用标准的 Vert.x 输入和输出参数,这使得创建标准的 Vert.x 应用程序变得更容易。
以下示例展示了 Vert.x 3.x 中 promise 的使用。
// 3.x
GreeterGrpc.GreeterVertxImplBase service =
new GreeterGrpc.GreeterVertxImplBase() {
@Override
public void sayHello(HelloRequest request, Promise<HelloReply> future) {
future.complete(
HelloReply.newBuilder().setMessage(request.getName()).build());
}
} 以下示例展示了 Vert.x 4 中 futures 的使用。
// 4.x
VertxGreeterGrpc.GreeterVertxImplBase service =
new VertxGreeterGrpc.GreeterVertxImplBase() {
@Override
public Future<HelloReply> sayHello(HelloRequest request) {
return Future.succeededFuture(
HelloReply.newBuilder()
.setMessage(request.getName())
.build());
}
} Vert.x MQTT 中的变化
以下部分描述了 Vert.x MQTT 中的变化。
MQTT 客户端中的某些 fluent 方法返回 future
MqttClient 类中的一些 fluent 方法返回 Future 而不是 fluent。例如,诸如 MqttClient.connect()、MqttClient.disconnect()、MqttClient.publish() 等方法在 Vert.x 4 中返回 future。
以下示例展示了 Vert.x 3.x 版本中 publish() 方法的使用。
client
.publish("hello", Buffer.buffer("hello"), MqttQoS.EXACTLY_ONCE, false, false)
.publish("hello", Buffer.buffer("hello"), MqttQoS.AT_LEAST_ONCE, false, false); 以下示例展示了 Vert.x 4 版本中 publish() 方法的使用。
client.publish("hello", Buffer.buffer("hello"), MqttQoS.EXACTLY_ONCE, false, false);
client.publish("hello", Buffer.buffer("hello"), MqttQoS.AT_LEAST_ONCE, false, false); MqttWill 消息返回缓冲区
MqttWill 数据对象将字符串消息包装为 Vert.x 缓冲区,而不是字节数组。
已从 MQTT 中删除已弃用的 MqttWill 和授权方法
以下 MQTT 方法已删除
已删除方法 | 替换方法 |
|
|
|
|
|
|
|
|
|
|
|
|
Vert.x Service Proxy 中的变化
以下部分描述了服务代理中的变化。
使用服务代理代码生成器
ServiceProxyProcessor 类已删除。
要使用服务代理代码生成器,您必须在 classpath 中导入带有处理器分类器的 vertx-codegen
<dependencies>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-codegen</artifactId>
<classifier>processor</classifier>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-service-proxy</artifactId>
</dependency>
</dependencies> 服务代理重用 vertx-codegen 中的 io.vertx.codegen.CodeGenProcessor 来启动服务代理和处理程序的代码生成。
客户端组件中的变化
本节解释了 Vert.x 客户端中的变化。
Vert.x Kafka 客户端中的变化
以下部分描述了 Vert.x Kafka 客户端中的变化。
AdminUtils 类不再可用
AdminUtils 类不再可用。请改用新的 KafkaAdminClient 类来对 Kafka 集群执行管理操作。
Flush 方法使用异步处理程序
KafkaProducer 类中的 flush 方法使用 Handler<AsyncResult<Void>> 而不是 Handler<Void>。
Vert.x JDBC 客户端中的变化
从 Vert.x 4 开始,JDBC 客户端支持 SQL 客户端。SQL common 模块也已合并到 JDBC 客户端中,即 io.vertx:vertx-sql-common 合并到 io.vertx:vertx-jdbc-client 模块中。您将不得不删除 io.vertx:vertx-sql-common 依赖文件,因为 io.vertx:vertx-jdbc-client 将包含它。随着 SQL common 客户端的合并,所有数据库 API 都已整合到 JDBC 客户端中。
在 Vert.x 4 中,SQL 客户端已更新,包含以下客户端
-
响应式 PostgreSQL 客户端。在早期版本中,它包含一个响应式 PostgreSQL 客户端。
-
响应式 MySQL 客户端
-
响应式 DB2 客户端
-
继续包含响应式 PostgreSQL 客户端。此客户端在 Vert.x 3.x 版本中也可用。
-
现有 JDBC 客户端现在同时包含 JDBC 客户端 API 和 SQL 客户端 API
响应式实现使用数据库网络协议。这使得它们资源高效。
对数据库的 JDBC 调用是阻塞调用。JDBC 客户端使用 worker 线程使这些调用变为非阻塞。
以下部分描述了 Vert.x JDBC 客户端中的变化。
创建连接池
在 Vert.x 4 中,您可以使用 JDBC 客户端 API 创建连接池。在早期版本中,您只能创建客户端,无法创建连接池。
以下示例展示了 Vert.x 3.x 中如何创建客户端。
// 3.x
SQLClient client = JDBCClient.create(vertx, jsonConfig); 以下示例展示了 Vert.x 4 中如何创建连接池。
// 4.x
JDBCPool pool = JDBCPool.pool(vertx, jsonConfig); | 尽管 Vert.x 3.x API 在 Vert.x 4 中受支持,但建议您在应用程序中使用新的 JDBC 客户端 API。 |
连接池使您能够执行简单查询。您不需要为简单查询管理连接。但是,对于复杂查询或多个查询,您必须管理您的连接。
以下示例展示了 Vert.x 3.x 中如何管理查询的连接。
// 3.x
client.getConnection(res -> {
if (res.succeeded()) {
SQLConnection connection = res.result();
// Important, do not forget to return the connection
connection.close();
} else {
// Failed to get connection
}
}); 以下示例展示了 Vert.x 4 中如何管理查询的连接。
// 4.x
pool
.getConnection()
.onFailure(e -> {
// Failed to get a connection
})
.onSuccess(conn -> {
// Important, do not forget to return the connection
conn.close();
}); 支持 Typesafe Config
您可以使用 jsonConfig 进行配置。但是,使用 jsonConfig 有时可能会导致错误。为避免这些错误,JDBC 客户端引入了 Typesafe Config。
以下示例展示了 Typesafe Config 的基本结构。
// 4.x ONLY!!!
JDBCPool pool = JDBCPool.pool(
vertx,
// configure the connection
new JDBCConnectOptions()
// H2 connection string
.setJdbcUrl("jdbc:h2:~/test")
// username
.setUser("sa")
// password
.setPassword(""),
// configure the pool
new PoolOptions()
.setMaxSize(16)
); 要使用 Typesafe Config,您必须在项目中包含 agroal 连接池。该连接池不公开许多配置选项,使得配置易于使用。 |
运行 SQL 查询
本节展示了如何在 JDBC 客户端中运行查询。
运行一次性查询
以下示例展示了 Vert.x 3.x 中如何在不管理连接的情况下运行查询。
// 3.x
client.query("SELECT * FROM user WHERE emp_id > ?", new JsonArray().add(1000), res -> {
if (res.succeeded()) {
ResultSet rs = res2.result();
// You can use these results in your application
}
}); 以下示例展示了 Vert.x 4 中如何在不管理连接的情况下运行查询。
// 4.x
pool
.preparedQuery("SELECT * FROM user WHERE emp_id > ?")
// the emp id to look up
.execute(Tuple.of(1000))
.onSuccess(rows -> {
for (Row row : rows) {
System.out.println(row.getString("FIRST_NAME"));
}
}); 在托管连接上运行查询
以下示例展示了 Vert.x 4 中如何在托管连接上运行查询。
pool
.getConnection()
.onFailure(e -> {
// Failed to get a connection
})
.onSuccess(conn -> {
conn
.query("SELECT * FROM user")
.execute()
.onFailure(e -> {
// Handle the failure
// Important, do not forget to return the connection
conn.close();
})
.onSuccess(rows -> {
for (Row row : rows) {
System.out.println(row.getString("FIRST_NAME"));
}
// Important, do not forget to return the connection
conn.close();
});
}); 支持存储过程
JDBC 客户端支持存储过程。
以下示例展示了 Vert.x 3.x 中如何传递 IN 参数。
// 3.x
connection.callWithParams(
"{ call new_customer(?, ?) }",
new JsonArray().add("John").add("Doe"),
null,
res -> {
if (res.succeeded()) {
// Success!
} else {
// Failed!
}
}); 以下示例展示了 Vert.x 4 中如何传递 IN 参数。
// 4.0
client
.preparedQuery("{call new_customer(?, ?)}")
.execute(Tuple.of("Paulo", "Lopes"))
.onSuccess(rows -> {
...
}); 在 Vert.x 3.x 中,由于可用类型的限制,对 IN 和 OUT 参数组合的支持非常有限。在 Vert.x 4 中,连接池是类型安全的,可以处理 IN 和 OUT 参数的组合。您还可以在应用程序中使用 INOUT 参数。
以下示例展示了 Vert.x 3.x 中参数的处理。
// 3.x
connection.callWithParams(
"{ call customer_lastname(?, ?) }",
new JsonArray().add("John"),
new JsonArray().addNull().add("VARCHAR"),
res -> {
if (res.succeeded()) {
ResultSet result = res.result();
} else {
// Failed!
}
}); 以下示例展示了 Vert.x 4 中参数的处理。
// 4.x
client
.preparedQuery("{call customer_lastname(?, ?)}")
.execute(Tuple.of("John", SqlOutParam.OUT(JDBCType.VARCHAR)))
.onSuccess(rows -> {
...
}); 在 JDBC 客户端中,数据类型已更新。
-
对于类型为
OUT的参数,您可以指定其返回类型。在示例中,OUT参数被指定为VARCHAR类型,这是一个 JDBC 常量。 -
类型不受 JSON 限制。您现在可以使用特定于数据库的类型,而不是类型名称的文本常量。
Vert.x 邮件客户端中的变化
以下部分描述了 Vert.x 邮件客户端中的变化。
MailAttachment 可作为接口使用
从 Vert.x 4 开始,MailAttachment 可作为接口使用。它使您能够在流中使用邮件附件功能。在 Vert.x 的早期版本中,MailAttachment 可作为类使用,邮件附件表示为数据对象。
邮件配置接口扩展了 net 客户端选项
MailConfig 接口扩展了 NetClientOptions 接口。由于此扩展,邮件配置还支持 NetClient 的代理设置。
Vert.x AMQP 客户端中的变化
以下部分描述了 Vert.x AMQP 客户端中的变化。
AMQP 客户端中包含 AmqpMessage 参数的方法已删除
AMQP 客户端中以 Handler<AmqpMessage> 作为参数的方法已删除。在早期版本中,您可以将此处理程序设置在 ReadStream<AmqpMessage> 上。但是,如果您将应用程序迁移到使用 futures,则无法使用此类方法。
已删除方法 | 替换方法 |
|
|
|
|
|
|
Vert.x MongoDB 客户端中的变化
以下部分描述了 Vert.x MongoDB 客户端中的变化。
从 MongoDB 客户端中删除的方法
以下方法已从 MongoClient 类中删除。
| 已删除方法 | 替换方法 |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
EventBus JavaScript 客户端中的变化
在 Vert.x 4 中,EventBus JavaScript 客户端模块已移至新位置。您必须更新构建系统以从新位置使用该模块。
在 Vert.x 3.x 中,事件总线 JavaScript 客户端可在各种位置获得,例如
在 Vert.x 4 中,JavaScript 客户端仅在 npm 中可用。EventBus JavaScript 客户端模块可从以下位置访问
JavaScript 客户端的版本控制
在 Vert.x 4 之前,每个 Vert.x 版本都包含一个新的 JavaScript 客户端版本。
然而,从 Vert.x 4 开始,只有当客户端发生变化时,npm 中才会提供新版本的 JavaScript 客户端。除非版本发生变化,否则您无需为每个 Vert.x 版本更新您的客户端应用程序。
Vert.x Redis 客户端中的变化
在 Vert.x 4 中,请使用 Redis 类来处理 Redis 客户端。RedisClient 类不再可用。
- 注意
-
为了帮助您将应用程序从
RedisClient迁移到Redis类,提供了一个辅助类RedisAPI。RedisAPI使您能够复制类似于RedisClient类的功能。
新类包含协议和 Redis 服务器功能的所有增强。使用新类来
-
处理所有 Redis 命令
-
连接到单个服务器
-
连接到启用 Redis Sentinel 的高可用性服务器
-
连接到 Redis 的集群配置
-
执行 Redis 扩展中的请求
-
与 RESP2 和 RESP3 服务器协议服务器通信
将现有 Redis 客户端应用程序迁移到新客户端
您可以直接将现有应用程序迁移到新的 Redis 客户端,或者使用辅助类 RedisAPI 分两步迁移应用程序。
在迁移应用程序之前,您必须创建客户端。
创建客户端
以下示例展示了 Vert.x 3.x 版本中 Redis 客户端的创建方式。
// Create the redis client (3.x)
RedisClient client = RedisClient
.create(vertx, new RedisOptions().setHost(host)); 以下示例展示了 Vert.x 4 中如何创建 Redis 客户端。
// Create the redis client (4.x)
Redis client = Redis
.createClient(
vertx,
"redis://server.address:port"); 在 Vert.x 4 中,客户端使用以下标准连接字符串语法
redis[s]://[[user]:password@]server[:port]/[database] 将应用程序迁移到 RedisAPI
使用 'RedisAPI',您现在可以决定如何管理连接
-
您可以让客户端使用连接池为您管理连接。
或
-
您可以通过请求新连接来控制连接。您必须确保在使用完毕后关闭或返回连接。
您必须先创建客户端,然后更新应用程序以处理请求。
以下示例展示了 Vert.x 3.x 版本中创建客户端后如何处理请求。
// Using 3.x
// omitting the error handling for brevity
client.set("key", "value", s -> {
if (s.succeeded()) {
System.out.println("key stored");
client.get("key", g -> {
if (s.succeeded()) {
System.out.println("Retrieved value: " + s.result());
}
});
}
}); 以下示例展示了 Vert.x 4 中创建客户端后如何处理请求。该示例使用列表设置键值对,而不是硬编码选项。有关命令可用参数的更多信息,请参阅 Redis SET 命令。
// Using 4.x
// omitting the error handling for brevity
// 1. Wrap the client into a RedisAPI
api = RedisAPI.api(client);
// 2. Use the typed API
api.set(
Arrays.asList("key", "value"), s -> {
if (s.succeeded()) {
System.out.println("key stored");
client.get("key", g -> {
if (s.succeeded()) {
System.out.println("Retrieved value: " + s.result());
}
});
}
}); 将应用程序直接迁移到 Redis 客户端
当您直接迁移到新的 Redis 客户端时
-
您可以使用所有新的 Redis 命令。
-
您可以使用扩展。
-
您可以减少从辅助类到新客户端的一些转换,这可能会提高应用程序的性能。
您必须先创建客户端,然后更新应用程序以处理请求。
以下示例展示了 Vert.x 3.x 版本中创建客户端后如何设置和获取请求。
// Using 3.x
// omitting the error handling for brevity
client.set("key", "value", s -> {
if (s.succeeded()) {
System.out.println("key stored");
client.get("key", g -> {
if (s.succeeded()) {
System.out.println("Retrieved value: " + s.result());
}
});
}
}); 以下示例展示了如何在 Vert.x 4 中创建客户端后处理请求。
// Using 4.x
// omitting the error handling for brevity
import static io.vertx.redis.client.Request.cmd;
import static io.vertx.redis.client.Command.*;
client.send(cmd(SET).arg("key").arg("value"), s -> {
if (s.succeeded()) {
System.out.println("key stored");
client.send(cmd(GET).arg("key"), g -> {
if (s.succeeded()) {
System.out.println("Retrieved value: " + s.result());
}
});
}
}); 在 Vert.x 4 中,所有交互都使用 send(Request) 方法。
迁移响应
在 Vert.x 3.x 中,客户端会硬编码所有已知的 Redis 5 命令,并且响应也会根据命令进行类型化。
在新客户端中,命令不再是硬编码的。响应的类型为 Response。新的有线协议具有更广泛的类型范围。
在旧客户端中,响应可以是以下类型:
-
null -
Long -
String -
JsonArray -
JsonObject(用于INFO和HMGET数组响应)
在新客户端中,响应是以下类型:
-
null -
Response
Response 对象具有类型转换器。例如,以下转换器:
-
toString() -
toInteger() -
toBoolean() -
toBuffer()
如果接收到的数据不是请求的类型,则类型转换器会将其转换为最接近的可能数据类型。当无法转换为特定类型时,将抛出 UnsupportedOperationException。例如,无法将 String 转换为 List 或 Map。
您还可以处理集合,因为 Response 对象实现了 Iterable 接口。
以下示例展示了如何执行 MGET 请求。
// Using 4.x
// omitting the error handling for brevity
import static io.vertx.redis.client.Request.cmd;
import static io.vertx.redis.client.Command.*;
client.send(cmd(MGET).arg("key1").arg("key2").arg("key3"), mget -> {
mget.result()
.forEach(value -> {
// Use the single value Vert.x Redis 客户端的更新
本节介绍 Redis 客户端中的更改。
从 Redis 角色和节点选项中删除了已弃用的术语“slave”
在 Redis 角色和节点选项中,已弃用的术语“slave”已替换为“replica”。
- 角色
-
以下示例展示了
SLAVE角色在 Vert.x 3.x 版本中的用法。
// Before (3.x)
Redis.createClient(
rule.vertx(),
new RedisOptions()
.setType(RedisClientType.SENTINEL)
.addConnectionString("redis://:5000")
.setMasterName("sentinel7000")
.setRole(RedisRole.SLAVE)); 以下示例展示了 REPLICA 角色在 Vert.x 4 中的用法。
// After (4.0)
Redis.createClient(
rule.vertx(),
new RedisOptions()
.setType(RedisClientType.SENTINEL)
.addConnectionString("redis://:5000")
.setMasterName("sentinel7000")
.setRole(RedisRole.REPLICA)); - 节点选项
-
以下示例展示了节点类型
RedisSlaves在 Vert.x 3.x 版本中的用法。
// Before (3.9)
options.setUseSlaves(RedisSlaves); 以下示例展示了节点类型 RedisReplicas 在 Vert.x 4 中的用法。
// After (4.0)
options.setUseReplicas(RedisReplicas); Vert.x Cassandra 客户端中的更改
Vert.x Cassandra 客户端使应用程序能够与 Apache Cassandra 服务进行交互。
以下部分描述了 Vert.x Cassandra 客户端中的更改。
驱动程序版本中的更改
在 Vert.x 4 中,Cassandra 客户端使用 4.x 版本的 Datastax Java 驱动程序。此驱动程序版本不向后兼容。您将需要将 Vert.x 3.x 应用程序迁移到 Vert.x 4。作为迁移过程的一部分,您应该导入新的 Datastax 驱动程序类并更改创建语句的方式。
以下示例展示了 Datastax Java 驱动程序类和 Vert.x 3.x 版本中的创建语句。
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.Row;
import com.datastax.driver.core.SimpleStatement;
import io.vertx.cassandra.CassandraClient;
SimpleStatement statement =
new SimpleStatement("SELECT release_version FROM system.local");
cassandraClient.execute(statement, done -> {
ResultSet results = done.result();
Row row = resultSet.one();
System.out.println(row.getString("release_version"));
}); 以下示例展示了 Datastax Java 驱动程序类和 Vert.x 4 中的创建语句。
import com.datastax.oss.driver.api.core.cql.ResultSet;
import com.datastax.oss.driver.api.core.cql.Row;
import com.datastax.oss.driver.api.core.cql.SimpleStatement;
import io.vertx.cassandra.CassandraClient;
SimpleStatement statement =
SimpleStatement.newInstance("SELECT release_version FROM system.local");
cassandraClient.execute(statement, done -> {
ResultSet results = done.result();
Row row = resultSet.one();
System.out.println(row.getString("release_version"));
}); 不支持对象映射器
由于 Datastax Java 驱动程序 4.x 中的更改,不再支持对象映射器。
Vert.x 4 版本不支持以下映射构造
@Table(keyspace = "test", name = "names")
public class MappedClass {
@PartitionKey
private String name;
...
} Cassandra 客户端选项的更新
CassandraClientOptions.setPort()、CassandraClientOptions.getContactPoints() 和 CassandraClientOptions.setContactPoints() 方法已被移除。请改用 CassandraClientOptions.addContactPoint() 方法。
以下示例展示了 Vert.x 3.x 版本中旧方法的使用。
import io.vertx.cassandra.CassandraClient;
import io.vertx.cassandra.CassandraClientOptions;
CassandraClientOptions options = new CassandraClientOptions()
.setContactPoints(List.of("node1.address", "node2.address", "node3.address"))
.setPort(9142)
.setKeyspace("my_keyspace");
CassandraClient client = CassandraClient.create(vertx, options); 以下示例展示了如何在 Vert.x 4 中使用 CassandraClientOptions.addContactPoint() 方法。
import io.vertx.cassandra.CassandraClient;
import io.vertx.cassandra.CassandraClientOptions;
CassandraClientOptions options = new CassandraClientOptions()
.addContactPoint("node1.address", 9142)
.addContactPoint("node2.address", 9142)
.addContactPoint("node3.address", 9142)
.setKeyspace("my_keyspace");
CassandraClient client = CassandraClient.create(vertx, options); RabbitMQ 客户端
RabbitMQOptions 更改
在 Vert.x 4 中,RabbitMQ 选项继承自 NetClientOptions,以利用包括 SSL 在内的通用连接选项。有两个选项已被移除,以支持其基类等效项,因此它们已被重命名。
// Vert.x RabbitMQOptions 3.x:
RabbitMQOptions options = new RabbitMQOptions()
.setConnectionRetries(42)
.setConnectionRetryDelay(500);
// Vert.x RabbitMQOptions 4.x:
RabbitMQOptions options = new RabbitMQOptions()
.setReconnectAttempts(42)
.setReconnectInterval(500); 集群中的更改
本节解释了集群中的更改。
从选项类中移除了集群标志
用于在 Vert.x 应用程序中指定、获取和设置集群的方法和布尔值已从 VertxOptions 和 EventBusOptions 类中移除。
Hazelcast 集群管理器中的更改
以下部分描述了 Hazelcast 集群管理器中的更改。
自定义配置的更新
Hazelcast 集群管理器基于 Hazelcast 4。
在 Vert.x 4 中,集群 SPI 已重新设计。订阅数据模型已更改。因此,Vert.x 3.x 节点和 Vert.x 4 节点无法在同一个 Hazelcast 集群中一起添加。
Vert.x 应用程序不受此更改的影响,因为 EventBus 和 SharedData API 保持不变。
如果您的 Vert.x 3.x 应用程序中有一个自定义的 Hazelcast 配置文件
-
添加映射
__vertx.nodeInfo。
<map name="__vertx.nodeInfo">
<backup-count>1</backup-count>
</map> Infinispan 集群管理器中的更改
以下部分描述了 Infinispan 集群管理器中的更改。
自定义配置的更新
Infinispan 集群管理器基于 Infinispan 12。
在 Vert.x 4 中,集群 SPI 已重新设计。订阅数据模型已更改。因此,Vert.x 3.x 节点和 Vert.x 4 节点无法在同一个 Infinispan 集群中一起添加。
Vert.x 应用程序不受此更改的影响,因为 EventBus 和 SharedData API 保持不变。
如果您的 Vert.x 3.x 应用程序中有一个自定义的 Infinispan 配置文件
-
将
__vertx.subs缓存类型更改为复制(replicated)而不是分布式(distributed)。 -
添加复制缓存
__vertx.nodeInfo。
<cache-container default-cache="distributed-cache">
<distributed-cache name="distributed-cache"/>
<replicated-cache name="__vertx.subs"/>
<replicated-cache name="__vertx.haInfo"/>
<replicated-cache name="__vertx.nodeInfo"/>
<distributed-cache-configuration name="__vertx.distributed.cache.configuration"/>
</cache-container> 如果您在 Openshift 上运行 Vert.x 集群,则不再需要 infinispan-cloud JAR。该 JAR 已从构建文件的依赖项部分中移除。此 JAR 中捆绑的配置文件现已包含在 infinispan-core JAR 中。
Apache Ignite 集群管理器中的更改
Vert.x Ignite 集群管理器已重写以支持 Vert.x 4 中的新集群 SPI。这对于开发人员来说应该没有任何显著差异。
第二个变化是关于配置。这样做的原因是为了减少由用于解析 XML 配置的 ignite-spring 扩展引入的瞬态依赖项。此更改从依赖项中移除了超过 10MB 的资产。
如果集群管理器在没有任何配置更改的情况下使用,则无需迁移;但如果使用了自定义的 ignite.xml,则可以切换到新的 ignite.json 格式,或者将 ignite-spring 依赖项重新添加到您的类路径中。
迁移到自定义 ignite.json
要覆盖 default-ignite.json,您只需将 ignite.json 添加到您的类路径中。JSON 格式支持自定义 Ignite 选项、缓存选项、发现选项和 SSL 选项。如需进一步自定义,您需要退回使用旧的 XML 格式。
在以下示例中,默认配置已扩展以激活集群通信的 TLS。
{
"cacheConfiguration": [{
"name": "__vertx.*",
"cacheMode": "REPLICATED",
"readFromBackup": false,
"atomicityMode": "ATOMIC",
"writeSynchronizationMode": "FULL_SYNC"
}, {
"name": "*",
"cacheMode": "PARTITIONED",
"backups": 1,
"readFromBackup": false,
"atomicityMode": "ATOMIC",
"writeSynchronizationMode": "FULL_SYNC"
}],
"sslContextFactory": {
"protocol": "TLSv1.2",
"keyStoreFilePath": "server.jks",
"keyStorePassword": "changeme",
"trustStoreFilePath": "server.jks",
"trustStorePassword": "changeme",
"trustAll": false
},
"includeEventTypes": ["EVT_CACHE_OBJECT_PUT", "EVT_CACHE_OBJECT_REMOVED"],
"metricsLogFrequency": 0
} 使用 ignite-spring 迁移回 ignite.xml
添加 ignite-spring 依赖项并将 ignite.xml 配置提供给您的类路径。
-
Maven(在您的
pom.xml中)
<dependency>
<groupId>org.apache.ignite</groupId>
<artifactId>ignite-spring</artifactId>
<version>${ignite.version}</version>
</dependency> -
Gradle(在您的
build.gradle文件中)
compile 'org.apache.ignite:ignite-spring:${ignite.version}' 此 ClusterManager 的原始 default-ignite.xml 示例
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<bean class="org.apache.ignite.configuration.IgniteConfiguration">
<property name="discoverySpi">
<bean class="org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi">
<property name="ipFinder">
<bean class="org.apache.ignite.spi.discovery.tcp.ipfinder.multicast.TcpDiscoveryMulticastIpFinder"/>
</property>
</bean>
</property>
<property name="cacheConfiguration">
<list>
<bean class="org.apache.ignite.configuration.CacheConfiguration">
<property name="name" value="__vertx.*"/>
<property name="cacheMode" value="REPLICATED"/>
<property name="readFromBackup" value="false"/>
<property name="atomicityMode" value="ATOMIC"/>
<property name="writeSynchronizationMode" value="FULL_SYNC"/>
</bean>
<bean class="org.apache.ignite.configuration.CacheConfiguration">
<property name="name" value="*"/>
<property name="cacheMode" value="PARTITIONED"/>
<property name="backups" value="1"/>
<property name="readFromBackup" value="false"/>
<property name="atomicityMode" value="ATOMIC"/>
<property name="affinity">
<bean class="org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction">
<property name="partitions" value="128"/>
</bean>
</property>
<property name="writeSynchronizationMode" value="FULL_SYNC"/>
</bean>
</list>
</property>
<property name="includeEventTypes">
<list>
<util:constant static-field="org.apache.ignite.events.EventType.EVT_CACHE_OBJECT_PUT"/>
<util:constant static-field="org.apache.ignite.events.EventType.EVT_CACHE_OBJECT_REMOVED"/>
</list>
</property>
<property name="gridLogger">
<bean class="io.vertx.spi.cluster.ignite.impl.VertxLogger"/>
</property>
<property name="metricsLogFrequency" value="0"/>
</bean>
</beans> 迁移集群
决定代码库的迁移策略很重要。这是因为您无法在单个集群中同时添加 Vert.x 3.x 节点和 Vert.x 4 节点,原因如下:
-
集群管理器升级 - 集群管理器的主要版本升级会阻止向后兼容性。
-
订阅数据更改 - Vert.x 已更改存储在集群管理器中的 EventBus 订阅数据的格式。
-
传输协议更改 - Vert.x 已更改集群中消息传输协议中的一些字段。
如果您有一个用于单个应用程序或某些密切相关的微服务的 Vert.x 集群,您可以一次性将整个代码库迁移到新集群。
但是,如果您无法一次性迁移代码库,请使用本节中的建议将 Vert.x 3.x 代码库迁移到 Vert.x 4。
拆分集群
如果您的集群中不同的团队已为其应用程序部署了 verticles,您可以考虑将 Vert.x 3.x 集群拆分为更小的集群。请注意,拆分集群后,分离的组件将无法使用集群功能进行通信。您可以使用以下组件拆分集群:
-
EventBus 请求和回复 - HTTP 或 RESTful Web 服务、gRPC
-
EventBus 发送和发布 - 消息系统、Postgres
LISTEN和NOTIFY、Redis 发布和订阅 -
共享数据 - Redis, Infinispan
拆分集群后,每个团队可以在准备好或有需要时迁移到 Vert.x 4。
使用 Vert.x EventBus Link
如果您无法拆分集群,则可以使用 Vert.x EventBus Link 逐步迁移您的代码库。
Vert.x EventBus Link 是一个将 Vert.x 3.x 集群 EventBus 连接到 Vert.x 4 集群 EventBus 的工具。
| 不支持共享数据 API(即映射、计数器和锁)的迁移。 |
该工具创建一个实现 EventBus 接口的 EventBusLink 对象。在每个集群的至少一个节点上创建一个 EventBusLink 实例。通过提供一组地址来创建该实例,其行为取决于消息范式:
-
即发即弃 (fire and forget) 和 请求与回复 (request and reply) - 消息被发送到远程集群。
-
发布 (publish) - 消息被发送到此集群和远程集群。
Vert.x EventBus Link 创建一个 WebSocket 服务器来接收消息,并使用 WebSocket 客户端发送消息。
Vert.x 中的其他更改
以下部分描述了 Vert.x 4 中的其他更改。
移除了 Starter 类
Starter 类已被移除。请改用 Launcher 类来启动您的 Vert.x 应用程序,而无需 main() 方法。
Java 8 的独立部署
Vert.x 4 支持 Java 11。此 Java 版本不支持独立的类加载。在 Vert.x 4 中,将支持 Java 8 的独立类加载。
从 Vert.x 上下文中移除了钩子方法
Context.addCloseHook() 和 Context.removeCloseHook() 方法已从 Context 类中移除。这些方法已移至内部接口 InternalContext。
从选项中移除了克隆方法
KeyCertOptions.clone()、TrustOptions.clone() 和 SSLEngineOptions.clone() 方法已被移除。请改用 KeyCertOptions.copy()、TrustOptions.copy() 和 SSLEngineOptions.copy() 方法。
从选项中移除了 equals 和 hashcode 方法
VertxOptions.equals() 和 VertxOptions.hashCode() 方法已被移除。
检查文件缓存的新方法
VertxOptions.fileResolverCachingEnabled() 方法已被移除。请改用 FileSystemOptions.isFileCachingEnabled() 方法来检查是否已启用文件缓存以解析类路径。
服务提供商接口 (SPI) 指标
Metrics.isEnabled() 方法已被移除。服务提供商接口 (SPI) 指标将返回一个 null 对象以指示指标未启用。
移除了池化缓冲区方法
池化缓冲区方法 TCPSSLOptions.isUsePooledBuffers() 和 TCPSSLOptions.setUsePooledBuffers() 已被移除。
创建没有共享数据源的客户端的方法
使用以下新方法创建不与其他客户端共享数据源的客户端。这些方法维护自己的数据源。
| 已弃用方法 | 新方法 |
|---|---|
|
|
|
|
|
|
|
|
Vert.x JUnit5 中的更改
以下部分描述了 Vert.x JUnit5 中的更改。
支持 vertx-core 模块和扩展中的更新
vertx-core 模块已更新为使用服务提供商接口进行参数注入。此更改导致 JUnit5 中出现以下更新:
-
您必须在任何需要
Vertx参数进行创建的参数之前调用它。例如,当注入WebClient时。 -
vertx-junit5模块仅支持vertx-core模块。 -
reactiverse-junit5-extensions模块托管包含额外参数类型(例如WebClient)的扩展。 -
RxJava 1 和 2 绑定现在作为
vertx-junit5-rx-java和vertx-junit5-rx-java2模块在vertx-junit5-extensions仓库中提供。从 Eclipse Vert.x 4.1.0 开始,RxJava 3 绑定
vertx-junit5-rx-java3可用。
Vert.x 文本上下文中已弃用的成功和失败方法
VertxTestContext.succeeding() 和 VertxTestContext.failing() 方法已被弃用。请改用 VertxTestContext.succeedingThenComplete() 和 VertxTestContext.failingThenComplete() 方法。
Kotlin 更改
生成的协程扩展方法
Vert.x 3 生成扩展挂起扩展方法,例如 get(Handler<AsyncResult<Result>> 生成 getAwait() 扩展方法。
// getSomethingAwait() is a generated extension method
// and is deprecated
var result = getSomethingAwait(); Vert.x 4 提供了一个基于 Future 的模型,并且 Vert.x Future 具有一个执行相同操作的 await() 扩展方法。上述代码可以简单地重写为:
var result = getSomething().await(); 脚本编译器
Vert.x 3 提供了一个基于 Kotlin 编译器 API 的 Kotlin 脚本编译器。
该 API 经常中断,并为升级 Kotlin 版本带来障碍。
此功能已在 Vert.x 4.0 中移除。
此类脚本现在应由 Kotlin 工具处理,例如 Kotlin 编译器具有编译这些脚本的选项。
测试 MongoDB 代码
vertx-embedded-mongo-db 模块在 Vert.x 4 中不再受支持。替代方案可以是 vertx-wiremongo,尽管它采用了不同的方法。vertx-embedded-mongo-db 启动了一个完整的 Mongo 服务器,而 vertx-wiremongo 是 Vert.x 的 MongoClient 接口的替代内存实现,允许特定的模拟。
假设我们要测试持久层中的 findApples 方法,以确保它创建正确的 Mongo 查询。以下是使用 vertx-wiremongo 进行此类测试的示例:
@Test
public void testFindApples(TestContext ctx) {
wiremongo.find()
.inCollection("warehouse")
.withQuery(q -> q.getString("type").equals("apple"))
.returns(List.of(new JsonObject()
.put("type", "apple")
.put("mass", 161)
.put("expiration", new JsonObject()
.put("$date", Instant.now().plus(7, DAYS)))));
db.findApples()
.onSuccess(l -> {
ctx.assertEquals(1, l.size());
ctx.assertEquals(161, l.get(0).getInteger("mass"));
})
.onComplete(ctx.asyncAssertSuccess());
} 完整文档可在此处找到。