Vert.x Core
repository·master·Indexed 12 days ago
https://github.com/eclipse-vertx/vert.xA toolkit for building reactive applications on the JVM. Vert.x Core provides fundamental low-level networking (HTTP, TCP), file system, and I/O capabilities, including support for UDP via DatagramSocket, SSL/TLS configuration, and efficient data handling with Buffers.
What's inside Vert.x
- Vert.x Core provides low-level functionality essential for building reactive applications. It includes support for HTTP, TCP, file system access, and other fundamental networking and I/O features. Vert.x Core serves as the foundation for many other Vert.x components and can be used directly in your applications.
Handle HTTP 100-Continue on Client and Server
masterThe
Expect: 100-Continueheader allows a client to send request headers and wait for a100 (Continue)response from the server before sending a large request body. This saves bandwidth if the server intends to reject the request.Client Side
Use
HttpClientRequest#continueHandler(Handler)to receive the signal from the server. This must be used in conjunction withwriteHead().Server Side
- Automatic: Set
HttpServerConfig#setHandle100ContinueAutomatically(true)to automatically respond with100 Continuewhen the header is detected. - Manual: Set the option to
false(default) to inspect headers manually. UseHttpServerResponse#writeContinue()to allow the client to proceed, or send a failure status code to reject the request.
// Client side example request.continueHandler(ctx -> { // logic to handle 100-Continue }); request.writeHead(status, headers); // Server side manual example if (shouldContinue) { response.writeContinue(); } else { response.setStatusCode(403).end(); }- Automatic: Set
Configure DNS resolver options
masterThe Vert.x DNS resolver provides several configuration options via
io.vertx.core.dns.AddressResolverOptions:- Failover: If a server does not respond in time, the resolver tries the next one. The search is limited by
setMaxQueries(int)(default:4). A query fails if no answer is received withingetQueryTimeout()milliseconds (default:5seconds). - Server list rotation: By default, the first server is used and others are for failover. Set
setRotateServers(true)to use round-robin selection to spread load. - Hosts mapping: Vert.x uses the OS
hostsfile by default, but you can provide an alternative. - Search domains: You can provide an explicit list of search domains. When a list is used, the dot threshold is
1(or from/etc/resolv.confon Linux), which can be adjusted usingsetNdots(int).
You can also use the JVM system property
-Dvertx.disableDnsResolver=trueto use the JVM's built-in resolver instead of the Vert.x resolver.- Failover: If a server does not respond in time, the resolver tries the next one. The search is limited by
Implement Request-Response pattern
masterTo perform a request-response exchange, use
sendwith a reply handler. The recipient processes the message and then callsmessage.reply(replyBody)to send a response back to the original sender.Example Workflow:
- Sender: Calls
eb.request(address, message, ar -> { ... })oreb.request(address, message).onComplete(ar -> { ... }). - Receiver: Receives the
Message, processes it, and callsmessage.reply(result). - Sender: Receives the reply in its handler.
// Sender eb.request("service.address", "request data", reply -> { if (reply.succeeded()) { System.out.println("Received reply: " + reply.result().body()); } }); // Receiver eb.consumer("service.address", message -> { // Process logic... message.reply("response data"); });- Sender: Calls
Use Asynchronous Shared Maps for clustered data storage
masterAn
AsyncMapallows you to store and retrieve data locally or from any other node in a Vert.x cluster. This is ideal for session state in a farm of servers.Key Characteristics:
- Asynchronous: Getting the map and performing operations returns a
Futureor uses a handler. - Clustered: In clustered mode, data is accessible across all cluster members. Note that latency may be higher than local maps due to network overhead.
- Data Types: Keys and values must be immutable, implement
io.vertx.core.shareddata.ClusterSerializable, or implementjava.io.Serializable.
Operations:
put(key, value): Asynchronously puts data into the map.get(key): Asynchronously retrieves data from the map.remove(key): Removes an entry.clear(): Clears the map.size(): Returns the number of entries.
If you only need an asynchronous map that is restricted to the local node, use
localAsyncMapinstead.// Example of getting an asynchronous shared map // See examples.SharedDataExamples#asyncMap for implementation details- Asynchronous: Getting the map and performing operations returns a
Parse delimited or fixed-size records with RecordParser
masterThe
RecordParseris used to transform a stream of input buffers into a sequence of structured buffers. It supports two primary modes:- Delimited Records: Parses records separated by a specific sequence of bytes (e.g., a newline
\n). - Fixed-size Records: Parses records based on a constant number of bytes.
This is particularly useful for protocols where messages are separated by delimiters or have a known length, allowing you to handle fragmented data arriving over a network.
// Example of delimited parsing logic (conceptual based on documentation description) // If input is: "HELLO\nHOW ARE Y", "OU?\nI AM", " DOING OK\n" // RecordParser produces: "HELLO", "HOW ARE YOU?", "I AM DOING OK"- Delimited Records: Parses records separated by a specific sequence of bytes (e.g., a newline
Handle QUIC connections and streams
masterQUIC multiplexes streams within a single connection. To interact with data, you must navigate the hierarchy: Server -> Connection -> Stream.
- Connections: Set a
connectHandleron theQuicServerto be notified of newQuicConnectioninstances. - Streams: On a
QuicConnection, set astreamHandlerto handle incomingQuicStreaminstances. Alternatively, you can set a stream handler directly on the server. - Data: On a
QuicStream, set ahandlerto receive data asio.vertx.core.buffer.Bufferinstances.
- Connections: Set a
Implement a Hybrid HTTP Server (HTTP/1, 2, and 3)
masterA hybrid server can handle both TCP (HTTP/1.x and HTTP/2) and QUIC (HTTP/3) by binding to two ports:
- A TCP port for HTTP/1.x and/or HTTP/2 traffic.
- A QUIC port (UDP) for HTTP/3 traffic.
Each port can be configured independently or can use the same port number (since TCP and UDP ports are distinct). To advertise HTTP/3 support to clients, it is recommended to emit an HTTP Alternative Services (Alt-Svc) notification using
io.vertx.core.http.HttpServerResponse#writeAltSvc.Graceful shutdown and immediate close of TCP servers/clients
masterVert.x provides two ways to stop a
NetServerorNetClient:shutdown()(Graceful): Initiates a shutdown phase allowing protocol-level cleanup. It waits until all sockets are closed or a timeout occurs (default is 30 seconds). Each socket can be notified via a shutdown handler to perform a protocol-level close.close()(Immediate): Immediately closes all open connections and releases resources without a grace period. This is asynchronous; use the returnedFutureto know when the close is complete.
If you create TCP servers/clients inside Verticles, they are automatically closed when the verticle is undeployed.
The Golden Rule: Don't Block the Event Loop
masterVert.x relies on non-blocking event loops to achieve high concurrency. If you execute blocking code inside an event loop handler, that loop cannot process any other events, potentially grinding your application to a halt.
Examples of blocking behavior to avoid:
Thread.sleep()- Waiting on locks, mutexes, or monitors (e.g.,
synchronizedblocks) - Long-lived database operations
- Complex, CPU-intensive calculations
- Spinning in a loop
Vert.x automatically logs warnings and provides stack traces if it detects an event loop has been blocked for a significant amount of time. You can configure these warning settings via
VertxOptions.Handle incoming TCP connections
masterTo handle new connections on a
NetServer, set aconnectHandler. This handler is called with aNetSocketinstance representing the connection.With the
NetSocket, you can:- Read data: Set a
handleron the socket. It will be called with aBufferevery time data is received. - Write data: Use
writemethods (operations are asynchronous). - Get addresses: Use
localAddress()andremoteAddress(). - Send files: Use
sendFileto efficiently stream files or classpath resources directly via the OS kernel. - Handle lifecycle: Use
closeHandlerto be notified when a socket closes andexceptionHandlerto catch errors on the socket. - Stream data:
NetSocketimplementsReadStreamandWriteStream, allowing it to be used with Vert.x pipes.
server.connectHandler(socket -> { socket.handler(buffer -> { System.out.println("Received: " + buffer.toString()); }); socket.write("Hello!"); });- Read data: Set a
Use AsyncFile for streaming and random access
masterThe
io.vertx.core.file.AsyncFileabstraction allows you to manipulate files asynchronously. Because it implements bothReadStreamandWriteStream, you can use thepipemethod to stream data between files and other stream objects like net sockets, HTTP requests/responses, or WebSockets.Random Access Writes
Use
AsyncFile#write(Buffer buffer, long position)to write data at a specific offset. If thepositionis greater than or equal to the current file size, the file will be enlarged to accommodate the offset.Random Access Reads
Use
AsyncFile#read(Buffer buffer, int offset, long position, int length, Handler<AsyncFile> handler)to read a specific number of bytes from a specific position into a buffer at a given offset.// Random access write asyncFile.write(buffer, position, handler); // Random access read asyncFile.read(buffer, bufferOffset, filePosition, length, handler);