I can’t get enough of Vetrx these days. I can’t wait to introduce you.
What is the Vertx
- Vertx is a toolset that runs on the JVM for building responsive applications.
- Netty – based high-performance, asynchronous network library.
- Netty has been packaged to provide a more user-friendly API.
- At the same time, some asynchronous call based libraries are implemented, including Database Connection, monitoring, authentication, logging, Service Discovery, clustering support, etc.
Why do I recommend learning
In fact, as technology develops. Asynchronous calls are actually becoming more common.
1. Now with the popularity of RPC. Frameworks like Dubbo are based on NIO concepts, and understanding asynchronous programming helps you learn and understand frameworks.
2, responsive programming gradually by the client side, front-end and back-end penetration.
3. It’s easier to write high-performance asynchronous services.
Several important concepts of Vertx
Event Loop
An Event Loop, as its name implies, is an Event Loop. Over the life of Vertx, query events are constantly polled.
In the traditional multithreaded programming model, each request forks a new thread to process the request. Such a programming model is relatively simple to implement, one connection corresponds to one thread, if a large number of requests need to be processed, it is necessary to fork out a large number of threads for processing, for the operating system scheduling a large number of threads causes the system load increase.
So in order to be able to handle a large number of requests, you need to transition to the Event Loop based on the Roactor model.
The picture on the official website is very graphic. Eventloop is constantly rotated, retrieving events and assigning different handlers to handle the corresponding events.
The important thing to note here is that events must be non-blocking in order for the program to run properly. Otherwise, eventLoop will block and affect Vertx performance. However, real programs are not guaranteed to be non-blocking, and Vertx also provides a mechanism for handling blocking methods. We’ll talk more about that below.
Verticle
In Vertx we often see the Vertical component.
Verticle is a block of code deployed and run by vert.x. By default a vert. x instance maintains N (by default N = number of CPU cores x 2) Event Loop threads. Verticle instances can be written in any vert.x supported programming language, and a simple application can contain Verticle in multiple languages.
You can think of Verticle as the Actor in the Actor Model.
An application is typically composed of many Verticle instances running simultaneously in the same vert. x instance. Different Verticle instances communicate with each other by sending messages to the Event Bus.
Event bus
The Event Bus in Vertx is easier to understand if compared to MQ, which is commonly used on the back end. In fact, the Event Bus is a bridge between Verticle to transfer information.
In other words, the Listening pattern in the Java Common Design Pattern, or what we often call the MQ message-based development pattern.
Back to the Vertx
We discussed the verTX model and mechanism above, now people will see how to develop a program using VerTX.
I will explain it in combination with what I wrote before, starting with Vertx.
val vertx = Vertx.vertx()
Copy the code
Vertx is the core of the vert.x framework. In general, all the behavior of Vertx is generated from this class.
Don’t call us, we’ll call you
Vert.x is an event-driven framework. Event-driven means when something happens, you do it.
Let’s go back to the title, “Don’t call us, we’ll call you,” which basically means that when we find out that you can do the job, we’ll call you. You don’t have to reach out to me.
Let’s see how Vertx implements this principle in code:
server.requestHandler(request -> {
request.response().end("hello world!");
});
Copy the code
This code block means that a Hello World is returned every time the server’s request is called.
So ‘you ‘j ‘in Vertx is all sorts of handlers. Most of the time when we’re writing Vertx programs, we’re actually writing Handler behavior. Then tell Vertx that you call the XXX Handler every time the XXX event is triggered.
Don ‘t block me
Vertx is based on events. We mentioned EventLoop above. In Vertx, EventLoop is like a busy bee constantly looking for the events that are triggered. The corresponding Handler is then executed. If the Hanlder thread executes, it is the Event Loop thread. For example, the Handler execution takes a long time. It blocks the Event Loop. Cause another event to trigger. The Event Loop also handles handlers that take longer. The Event loop does not respond to other events in a timely manner.
But in reality, not all events are non-blocking. Such as query database, call remote interface, and so on, how to do?
In event-driven models, there are probably two ways to solve this problem, such as in Redis, where Redis takes great care to maintain a time sharding. When a person executes an Event for too long, the state of the current Event is saved, the current Event is paused, and the Event loop is scheduled again. Prevent Event Loop from being blocked by events.
There is also the practice of handing a blocked event to another thread to execute. The Event Loop can continue the Loop of events to prevent blocking. That’s actually how Vertx works.
vertx.executeBlocking(promise -> {
// Call some blocking API that takes a significant amount of time to return
String result = someAPI.blockingMethod("hello");
promise.complete(result);
}, res -> {
System.out.println("The result is: " + res.result());
});
Copy the code
If we realize that this Handler is Blocking during development, we need to tell Vertx that it is Blocking and give it to another thread.
Coordinate asynchronous processing
As mentioned above, Vertx uses a Handler to handle events, but in many cases, an operation usually requires more than one Handler to process data. If you write callback all the time, you get arrow code. The problem of creating a hell callback.
As an asynchronous framework, Vertx generally uses Futures to solve callback hell. Understanding the Future in Vertx is central to writing good code.
A Future is usually understood as a placeholder representing the result of an operation at some point in the Future. Not quite clear can see I used to write articles.
It is important to point out that Vertx’s Future is similar to CompletableFuture in Jdk in principle and concept, but there is a big difference in use.
The CompletableFuture in the Jdk is a waiting result that can be blocked directly with result(), whereas the Future in Vertx, if it is blocked directly with result(), will immediately fetch the result from the Future instead of blocking the waiting result. It’s easy to harvest a Null.
Once you know this distinction, you can write code error-free.
Event Bus
The Event Bus in Vertx is easy to understand if you have used a messaging system in your daily development. The official document compares Event Bus to the nervous system of Vertx. In fact, we just think that Event Bus is the message system of Vertx.
Nailing the development of Intranet penetration agent
This small Demo sparrow is small but contains the use of several key components of Vertx. When I wrote this Demo, I happened to be studying Kotlin so I just wrote it in Kotlin. If you’ve written Java or Typescript, it’s easy to read.
The project contains
- The Http Service is used to receive the callback for the pin
- The WebSocket Service is used to push the received callback to the Client to penetrate the Intranet.
- Vertx Config is used to set project parameters for easy use
- The use of the Event Bus for sending messages between Http Services and Websockets.
Start with a Verticle
Gradle configuration files are introduced as follows:
implementation ("IO. Vertx: vertx - core: 3.8.5")
implementation ("IO. Vertx: vertx - web: 3.8.5")
implementation ("IO. Vertx: vertx - lang - kotlin: 3.8.5")
Copy the code
We have already introduced what Verticle is. Vertx provides an AbstractVerticle class for easy development. Direct inheritance:
class DingVerticle : AbstractVerticle() {}Copy the code
AbstractVerticle contains some of the methods used by Vericle.
We can override the start() method to initialize our Verticle behavior.
The HttpService create
override fun start(a) {
val httpServer = vertx.createHttpServer()
val router = Router.router(vertx)
router.post("/ding/api").handler{event ->
val request = event.request()
request.bodyHandler { t ->
println(t)
}
event.response().end();
}
httpServer.requestHandler(router);
httpServer.listen(8080);
}
Copy the code
The code is relatively simple:
- Create an httpService
- Set up a Router if you’ve written Spring Mvc code. The Router here is like RequestMapping in Controller. Use to specify a Handler corresponding to the Http request URI and Method. The Handler here is a lambda expression. Simply print out the requested body.
- Add Router to httpService and listen on port 8080.
WebSocketService
The webSocket protocol is the key to this proxy because webSocket, unlike Http, is two-way communication. With this feature we can “push” messages to the Intranet. Achieve the purpose of Intranet “penetration”.
httpServer.webSocketHandler { webSocket: ServerWebSocket ->
val binaryHandlerID = webSocket.binaryHandlerID()
webSocket.endHandler() {
log.info("end", binaryHandlerID)
}
webSocket.writeTextMessage("Welcome to xilidou stapling agent")
webSocket.writeTextMessage("Connection successful")}Copy the code
The code is also relatively simple, which is to register a WebSocket Handler with Vertx.
Use of the Event Bus
The core function of the proxy is to forward the pinned callback message. As I mentioned earlier, the Event Bus plays a “nervous system role” in Vertx. In fact, in other words, the HTTP service can send a message through the Event Bus when it receives a callback. When the WebSocket receives the message from the Event Bus, it pushes the message to the client. See the picture below:
For ease of understanding, we use the usual concepts of producer and consumer in MQ.
So we use HttpService to register a producer and forward the message after receiving the pinned callback.
We can write a separate HttpHandler for ease of writing
/ / 1
class HttpHandler(private val eventBus: EventBus) : Handler<RoutingContext> {
private val log = LoggerFactory.getLogger(this.javaClass);
override fun handle(event: RoutingContext) {
val request = event.request()
request.bodyHandler { t->
val jsonObject = JsonObject(t)
val toString = jsonObject.toString()
log.info("request is {}",toString);
/ / 2
eventBus.publish("callback", toString)
}
event.response().end("ok")}}Copy the code
Here are a few things to note:
- We need to use the Event Bus to send messages, so we need to pass an Event Bus inside the constructor
- After receiving the message, we can first convert the data to a Json string and then send the message. Note the use of
publish()
“Broadcast” means broadcast, so that all subscribed clients can receive new messages.
So once we have the producer and we send the data, we can consume the message in the WebSocket and push it to the client
Let’s write a WebSocket Handler
/ / 1
class WebSocketHandler(private val eventBus: EventBus) : Handler<ServerWebSocket> {
private val log = LoggerFactory.getLogger(this.javaClass)
override fun handle(webSocket: ServerWebSocket) {
val binaryHandlerID = webSocket.binaryHandlerID()
/ / 2
val consumer = eventBus.consumer<String>("callback") { message ->
val body = message.body()
log.info("send message {}", body)
/ / 3
webSocket.writeTextMessage(body)
}
webSocket.endHandler() {
log.info("end", binaryHandlerID)
/ / 4
consumer.unregister();
}
webSocket.writeTextMessage("Welcome to xilidou stapling agent")
webSocket.writeTextMessage("Connection successful")}}Copy the code
Here are a few things to note:
- EventBus needs to be injected during initialization
- Write a
consumer()
Consuming a message from HttpHandler - The message is written to the webSocket and sent to the Client
- The consumer needs to be reclaimed after the WebSocket is disconnected
Initialize the Vertx
After all this preparation we were finally able to initialize our Vertx
class DingVerticleV2: AbstractVerticle() {override fun start(a) {
/ / 2
val eventBus = vertx.eventBus()
val httpServer = vertx.createHttpServer()
val router = Router.router(vertx);
/ / 3
router.post("/api/ding").handler(HttpHandler(eventBus));
httpServer.requestHandler(router);
/ / 4
httpServer.webSocketHandler(WebSocketHandler(eventBus));
httpServer.listen(8080); }}/ / 1
fun main(a) {
val vertx = Vertx.vertx()
vertx.deployVerticle(DingVerticleV2())
}
Copy the code
Here are a few things to note:
- Initialize Vertx and deploy it
- Initialize the eventBus
- Register an HttpHandler
- Registered WebSocketHandler
conclusion
- Vertx is a tool, not a framework, so it can be easily combined with other frameworks.
- Vertx is an asynchronous framework based on Netty. We can write asynchronous code just as we write synchronous code.
- Vertx has two main functions in code. One is to initialize components, such as:
val eventBus = vertx.eventBus()
val httpServer = vertx.createHttpServer()
Copy the code
There is also a registration Handler:
httpServer.webSocketHandler(WebSocketHandler(eventBus));
Copy the code
- The Event Bus is a messaging system. For different handlers to pass data directly, simplifying development.
Related links
- Using the tutorial nail robot callback Intranet penetration proxy – Use the article
- Github address: Github
- A gentle Guide to Asynchronous programming with Eclipse vert. x for Java developers;
- Vert.x Core Manual