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-databind
jar 依赖项。<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());
}
完整文档可在此处找到。