http://vertx.io/blog/my-first-vert-x-3-application/
My first Vert.x 3 Application
Let’s say, you heard someone saying that Vert.x is awesome. Ok great, but you may want to try it by yourself. Well, the next natural question is “where do I start ?”. This post is a good starting point. It shows how is built a very simple vert.x application (nothing fancy), how it is tested and how it is packaged and executed. So, everything you need to know before building your own groundbreaking application.
The code developed in this post is available on github. This post is part of the Introduction to Vert.x series. The code of this post in in the post-1 branch.
Let’s start !
First, let’s create a project. In this post, we use Apache Maven, but you can use Gradle or the build process tool you prefer. You could use the Maven jar archetype to create the structure, but basically, you just need a directory with:
- a
src/main/java
directory - a
src/test/java
directory - a
pom.xml
file
So, you would get something like:
.
├── pom.xml
├── src
│ ├── main
│ │ └── java
│ └── test
│ └── java
Let’s create the
pom.xml
file with the following content:<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>io.vertx.blog</groupId>
<artifactId>my-first-app</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-core</artifactId>
<version>3.0.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
This
pom.xml
file is pretty straightforward:- it declares a dependency on
vertx-core
- it configures the maven-compiler-plugin to use Java 8.
This second point is important, Vert.x applications require Java 8.
Let’s code !
Ok, now we have made the
pom.xml
file. Let’s do some real coding… Create the src/main/java/io/vertx/blog/first/MyFirstVerticle.java
file with the following content:package io.vertx.blog.first;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.Future;
public class MyFirstVerticle extends AbstractVerticle {
@Override
public void start(Future<Void> fut) {
vertx
.createHttpServer()
.requestHandler(r -> {
r.response().end("<h1>Hello from my first " +
"Vert.x 3 application</h1>");
})
.listen(8080, result -> {
if (result.succeeded()) {
fut.complete();
} else {
fut.fail(result.cause());
}
});
}
}
This is actually our not fancy application. The class extends
AbstractVerticle
. In the Vert.x world, a verticle is a component. By extending AbstractVerticle
, our class gets access to the vertx
field.
The
start
method is called when the verticle is deployed. We could also implement a stop
method, but in this case Vert.x takes care of the garbage for us. The start
method receives a Future
object that will let us inform Vert.x when our start sequence is completed or report an error. One of the particularity of Vert.x is its asynchronous / non-blocking aspect. When our verticle is going to be deployed it won’t wait until the start method has been completed. So, the Future
parameter is important to notify of the completion.
The
start
method creates a HTTP server and attaches a request handler to it. The request handler is a lambda, passed in the requestHandler
method, called every time the server receives a request. Here, we just reply Hello ...
(nothing fancy I told you). Finally, the server is bound to the 8080 port. As this may fails (because the port may already be used), we pass another lambda expression checking whether or not the connection has succeeded. As mentioned above it calls either fut.complete
in case of success or fut.fail
to report an error.
Let’s try to compile the application using:
mvn clean compile
Fortunately, it should succeed.
That’s all for the application.
Let’s test
Well, that’s good to have developed an application, but we can never be too careful, so let’s test it. The test uses JUnit and vertx-unit - a framework delivered with vert.x to make the testing of vert.x application more natural.
Open the
pom.xml
file to add the two following dependencies:<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-unit</artifactId>
<version>3.0.0</version>
<scope>test</scope>
</dependency>
Now create the
src/test/java/io/vertx/blog/first/MyFirstVerticleTest.java
with the following content:package io.vertx.blog.first;
import io.vertx.core.Vertx;
import io.vertx.ext.unit.Async;
import io.vertx.ext.unit.TestContext;
import io.vertx.ext.unit.junit.VertxUnitRunner;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(VertxUnitRunner.class)
public class MyFirstVerticleTest {
private Vertx vertx;
@Before
public void setUp(TestContext context) {
vertx = Vertx.vertx();
vertx.deployVerticle(MyFirstVerticle.class.getName(),
context.asyncAssertSuccess());
}
@After
public void tearDown(TestContext context) {
vertx.close(context.asyncAssertSuccess());
}
@Test
public void testMyApplication(TestContext context) {
final Async async = context.async();
vertx.createHttpClient().getNow(8080, "localhost", "/",
response -> {
response.handler(body -> {
context.assertTrue(body.toString().contains("Hello"));
async.complete();
});
});
}
}
This is a JUnit test for our verticle. The test uses vertx-unit, so we use a custom runner. vert.x-unit makes easy to test asynchronous interactions, which are the basis of vert.x applications.
In the
setUp
method, we creates an instance of Vertx
and deploy our verticle. You may have noticed that unlike the traditional JUnit @Before
method, it receives a TestContext
. This object lets us control the asynchronous aspect of our test. For instance, when we deploy our verticle, it starts asynchronously, as most Vert.x interactions. We cannot check anything until it gets started correctly. So, as second argument of the deployVerticle
method, we pass a result handler: context.asyncAssertSuccess()
. It fails the test if the verticle does not start correctly. In addition it waits until the verticle has completed its start sequence. Remember, in our verticle, we call fut.complete()
. So it waits until this method is called, and in the case of a failures, fails the test.
Well, the
tearDown
method is straightforward, and just terminates the vertx
instance we created.
Let’s now have a look to the test of our application: the
testMyApplication
method. The test emits a request to our application and checks the result. Emitting the request and receiving the response is asynchronous. So we need a way to control this. As the setUp
and tearDown
methods, the test method receives a TestContext
. From this object we creates an async handle (async
) that lets us notify the test framework when the test has completed (using async.complete()
).
So, once the async handle is created, we create a HTTP client and emits a HTTP request handled by our application with the
getNow()
method (getNow
is just a shortcut for get(...).end()
). The response is handled by a lambda. In this lambda we retrieves the response body by passing another lambda to the handler
method. The body
argument is the response body (as a buffer
object). We check that the body contains the "Hello"
String and declare the test complete.
Let’s take a minute to mention the assertions. Unlike in traditional JUnit tests, it uses
context.assert...
. Indeed, if the assertion fails, it will interrupt the test immediately. So it’s pretty important to always uses these assertion methods because of the asynchronous aspect of the Vert.x application and so tests.
Our test can be run from an IDE, or using Maven:
mvn clean test
Packaging
So, let’s sum up. We have an application and a test. Well, let’s now package the application. In this post we package the application in a fat jar. A fat jar is a standalone executable Jar file containing all the dependencies required to run the application. This is a very convenient way to package Vert.x applications as it’s only one file. It also make them easy to execute.
To create a fat jar, edit the
pom.xml
file and add the following snippet just before </plugins>
:<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<manifestEntries>
<Main-Class>io.vertx.core.Starter</Main-Class>
<Main-Verticle>io.vertx.blog.first.MyFirstVerticle</Main-Verticle>
</manifestEntries>
</transformer>
</transformers>
<artifactSet/>
<outputFile>${project.build.directory}/${project.artifactId}-${project.version}-fat.jar</outputFile>
</configuration>
</execution>
</executions>
</plugin>
It uses the maven-shade-plugin to create the
fat jar
. In the manifestEntries
it indicates the name of our verticle. You may wonder from where comes the Starter
class. It’s actually a class from vert.x, that is going to create the vertx
instance and deploy our verticle.
So, with this plugin configured, let’s launch:
mvn clean package
This is going to create
target/my-first-app-1.0-SNAPSHOT-fat.jar
embedding our application along with all the dependencies (including vert.x itself).Executing our application
Well, it’s nice to have a fat jar, but we want to see our application running! As said above, thanks to the fat jar packaging, running Vert.x application is easy as:
java -jar target/my-first-app-1.0-SNAPSHOT-fat.jar
Then, open a browser to http://localhost:8080.
To stop the application, hit
CTRL+C
.Conclusion
This Vert.x 3 crash class has presented how you can develop a simple application using Vert.x 3, how to test it, package it and run it. So, you now know everything you need to build amazing system on top of Vert.x 3. Next time we will see how to configure our application.
Happy coding & Stay tuned !
http://tutorials.jenkov.com/vert.x/
Vert.x comes with a TCP server which makes it easy to create TCP servers in your application. You can create one or more TCP servers, depending on your need. In this tutorial I will look at how to create a TCP server from inside a verticle and how to handle incoming connections and data.
The
The
http://tutorials.jenkov.com/vert.x/
Vert.x TCP Server
Jakob Jenkov
Last update: 2015-04-29 |
Creating a TCP Server
You create a Vert.x TCP server by calling thecreateNetServer()
method on the Vertx
object. Here is how that looks:NetServer server = vertx.createNetServer();You will often create a TCP server from inside a verticle. Here is how you create a Vert.x TCP server from inside a verticle:
import io.vertx.core.AbstractVerticle; import io.vertx.core.net.NetServer; public class VertxTcpServerVerticle extends AbstractVerticle { @Override public void start() throws Exception { NetServer server = vertx.createNetServer(); } }
Starting the TCP Server
Once you have created the TCP server, you can start it using itslisten()
method. Here is how starting the TCP server looks:public class VertxTcpServerVerticle extends AbstractVerticle { @Override public void start() throws Exception { NetServer server = vertx.createNetServer(); server.listen(10000); } }This example starts the server and instructs it to listen on TCP port 10.000 .
The
NetServer
class contains more versions of the listen()
method which gives you different options for starting the TCP server.Setting a Connect Handler on the TCP Server
In order to handle incoming TCP connections you need to set a connect handler on the TCP server. This is normally done before starting the TCP server. Here is a Vert.x TCP server connect handler example:public class VertxTcpServerVerticle extends AbstractVerticle { @Override public void start() throws Exception { NetServer server = vertx.createNetServer(); server.connectHandler(new Handler<NetSocket>() { @Override public void handle(NetSocket netSocket) { System.out.println("Incoming connection!"); } }); server.listen(10000); } }The
handle()
method of the connect handler is called whenever a new TCP connection is created by a client of the TCP server. The NetSocket
object passed as parameter to the handle()
method gives access to the incoming connection (socket etc.).Reading Data From The Socket
In order to read data from the incoming connections you need to set a handler on theNetSocket
object for the connection. Here is how that is done:public class VertxTcpServerVerticle extends AbstractVerticle { @Override public void start() throws Exception { NetServer server = vertx.createNetServer(); server.connectHandler(new Handler<NetSocket>() { @Override public void handle(NetSocket netSocket) { System.out.println("Incoming connection!"); netSocket.handler(new Handler<Buffer>() { @Override public void handle(Buffer buffer) { System.out.println("incoming data: "+buffer.length()); buffer.getString(0,buffer.length()); } }); } }); server.listen(10000); } }
Writing Data to The Socket
Once you have processed the incoming data you may want to write a response back to the client. You can do so via theNetSocket
instance passed to the connect handler's handle()
method. Here is an example of writing data back to the client via the NetSocket
:public class VertxTcpServerVerticle extends AbstractVerticle { @Override public void start() throws Exception { NetServer server = vertx.createNetServer(); server.connectHandler(new Handler<NetSocket>() { @Override public void handle(NetSocket netSocket) { System.out.println("Incoming connection!"); netSocket.handler(new Handler<Buffer>() { @Override public void handle(Buffer inBuffer) { System.out.println("incoming data: " + inBuffer.length()); String data = inBuffer.getString(0, inBuffer.length()); Buffer outBuffer = Buffer.buffer(); outBuffer.appendString("response..."); netSocket.write(outBuffer); } }); } }); server.listen(10000); } }The
write()
method of the NetSocket
method is asynchronous. Thus, it returns immediately. The data will be written to the underlying socket at a later time.The
NetSocket
class contains more versions of the write()
method which enables you to write e.g. a String directly to the socket without using a Buffer
. See the Vert.x JavaDoc for more details.Closing The TCP Server
When you are finished with the TCP server you can close it using itsclose()
method. Here is how closing a Vert.x TCP server looks:server.close();Closing the TCP server is an asynchronous actions, so the
close()
method may exit before the TCP server is actually closed. If you need to be notified of when the TCP server has shut down, you can pass aHandler
to the close()
method. This handler will then be called when the TCP server is fully closed. Here is how that looks:server.close(new Handler<AsyncResult<Void>>() { @Override public void handle(AsyncResult result) { if(result.succeeded()){ //TCP server fully closed } } });
댓글 없음:
댓글 쓰기