使用Vert.x开发响应式微服务
响应式系统是一种建立分布式应用程序新方式,利用现代的处理器架构的优势,更有效地使用资源。结合微服务,它提供了一个惊人的灵活性,每个组件单独开发,发布,部署,更新和退出。建设微服架构却不容易。需要管理许多方面,如部署设施、服务发现、服务之间的相互作用、弹性模式、可扩展性等。
Eclipse Vert.x是一个建立微服务的工具。它给你塑造你的系统的自由,确保其响应性,弹性。你的组件之间通信是异步的,利用非堵塞异步性Vert.x。
Vert.x是一个简单的,可扩展的,类似actor模型的可部署和并发模型。Verticles是一些代码块,能部署和运行在Vert中。Vert.x应用程序通常是由许多Verticles实例运行在同一个Vert.x实例中。Vert.x实例彼此之间通过事件总线发送消息实现异步交互。
默认Verticles是运行在Vert.x事件循环中,必须不能有堵塞代码,Vert.x确保每个Verticles总是被同样线程执行。
Verticles可由许多语言支持,Java需要拓展AbstractVerticle,它的start和stop方法对应Verticles部署和卸载的生命周期阶段。
import io.vertx.core.AbstractVerticle;
public class MyVerticle extends AbstractVerticle {
@Override
public void start() throws Exception {
// Executed when the verticle is deployed
}
@Override
public void stop() throws Exception {
// Executed when the verticle is undeployed
}
}
一个verticle 能通过传入配置部署其他verticle ,可以创建很多verticle 实例,每个实例运行在不同的event loop事件循环中,Vert.x会平衡这些实例负载,这样就能充分利用你的CPU多核威力。
public class MyDeployingVerticle extends AbstractVerticle {
@Override
public void start() throws Exception {
// Pass a configuration
JsonObject config = new JsonObject().put("key", "value");
vertx.deployVerticle(io.vertx.starter.MyVerticle.class.getName(),
new DeploymentOptions().setConfig(config));
// Set the number of instances vertx.deployVerticle(io.vertx.starter.MyVerticle.class.getName(), new DeploymentOptions().setInstances(2)); } }
创建第一个Vert.x项目
创建Maven项目:
git clone https://github.com/vert-x3/vertx-maven-starter.git PROJECT_NAME
解压目录运行:./redeploy.sh(redeploy.bat),浏览器打开 http://localhost:8080, 你会看到第一个Vert.x项目。
实现REST API
看看使用 Vert.x Web如何实现简单REST API ,增加依赖到你的pom.xml:
‹dependency› ‹groupId›io.vertx‹/groupId› ‹artifactId›vertx-web‹/artifactId› ‹/dependency›
Vert.x Web是一个基于Vert.x让你方便实现REST API的组件,提供服务器端模板 静态文件支持 错误页面。提供路由Router概念,每个route有一个处理器处理请求建立响应。
下面是以讹增加名称的简单案例:
package io.vertx.starter;
import io.vertx.core.AbstractVerticle; import io.vertx.core.json.Json; import io.vertx.ext.web.Router; import io.vertx.ext.web.handler.BodyHandler; import java.util.ArrayList; import java.util.List;
public class MyRestAPIVerticle extends AbstractVerticle {
// Maintain a simple list of names维持名称简单列表 private List names = new ArrayList<>();
@Override
public void start() {
// Create a Vert.x web router
Router router = Router.router(vertx);
// Register a simple first route on / 注册一个简单首个route在根路径/
router.get("/").handler(rc -> {
rc.response().end("Welcome");
});
// Register a second router retrieving all stored names as JSON注册第二个router返回名称列表
router.get("/names").handler(
// Just encode the list as JSON and return.
rc -> rc.response()
.putHeader("content-type", "application/json")
.end(Json.encode(names)));
// Register a body handler indicating that other routes need // to read the request body router.route().handler(BodyHandler.create());
// Register a third route to add names注册第三个router增加名称
router.post("/names").handler(
rc -> {
// Read the body
String name = rc.getBody().toString();
if (name.isEmpty()) {
// Invalid body -> Bad request
rc.response().setStatusCode(400).end();
} else if (names.contains(name)) {
// Already included name -> Conflict
rc.response().setStatusCode(409).end();
} else {
// Add the name to the list -> Created
names.add(name);
rc.response().setStatusCode(201).end(name);
}
});
vertx.createHttpServer() // Pass the router's accept method as request handler .requestHandler(router::accept) .listen(8080); } }
消费REST API
当建立微服务时,你需要使用调用服务,也就是需要消费REST API,vert.x提供异步HTTP客户端。
package io.vertx.starter;
import io.vertx.core.AsyncResult;
import io.vertx.core.Future;
import io.vertx.core.Handler;
import io.vertx.core.Vertx;
import io.vertx.core.http.HttpClient;
import io.vertx.core.http.HttpClientOptions;
import io.vertx.core.json.JsonArray;
public class MyRestAPIClient {
private HttpClient client;
public MyRestAPIClient(Vertx vertx) {
// Create the HTTP client and configure the host and post.
client = vertx.createHttpClient(new HttpClientOptions()
.setDefaultHost("localhost")
.setDefaultPort(8080)
);
}
public void close() {
// Don't forget to close the client when you are done.
client.close();
}
public void getNames(Handler<asyncresult> handler) {
// Emit a HTTP GET
client.get("/names",
response ->
// Handler called when the response is received
// We register a second handler to retrieve the body
response.bodyHandler(body -> {
// When the body is read, invoke the result handler
handler.handle(Future.succeededFuture(body.toJsonArray()));
}))
.exceptionHandler(t -> {
// If something bad happen, report the failure to the passed handler
handler.handle(Future.failedFuture(t));
})
// Call end to send the request
.end();
}
public void addName(String name, Handler<asyncresult> handler) {
// Emit a HTTP POST
client.post("/names",
response -> {
// Check the status code and act accordingly
if (response.statusCode() == 200) {
handler.handle(Future.succeededFuture());
} else {
handler.handle(Future.failedFuture(response.statusMessage()));
}
})
.exceptionHandler(t -> handler.handle(Future.failedFuture(t)))
// Pass the name we want to add
.end(name);
}
}
下面代码显示上面客户端代码是具体如何被调用:
Vertx vertx = Vertx.vertx();
MyRestAPIClient client = new MyRestAPIClient(vertx);
client.getNames(ar -> {
if (ar.succeeded()) {
System.out.println("Names: " + ar.result().encode());
} else {
System.out.println("Unable to retrieve the list of names: "
+ ar.cause().getMessage());
}
});