1. Overview
In this quick article, we’ll discuss the integration of Spring with Vert-x and leverage the best of both worlds: the powerful and well-known Spring feature, and the reactive single-event loop from Vert.x.
To understand more about Vert.x, please refer to our introductory article here.
2. Setup
First, let’s get our dependencies in place:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>io.vertx</groupId> <artifactId>vertx-web</artifactId> <version>3.4.1</version> </dependency>
Notice that we’ve excluded the embedded Tomcat dependency from spring-boot-starter-web since we are going to deploy our services using verticles.
You may find the latest dependencies here.
3. Spring Vert.x Application
Now, we’ll build a sample application with two verticles deployed.
The first Verticle routes requests to the handler that sends them as messages to the given address. The other Verticle listens at a given address.
Let’s look at these in action.
3.1. Sender Verticle
ServerVerticle accepts HTTP requests and sends them as messages to a designated address. Let’s create a ServerVerticle class extending the AbstractVerticle, and override the start() method to create our HTTP Server:
@Override public void start() throws Exception { super.start(); Router router = Router.router(vertx); router.get("/api/baeldung/articles") .handler(this::getAllArticlesHandler); vertx.createHttpServer() .requestHandler(router::accept) .listen(config().getInteger("http.port", 8080)); }
In the server request handler, we passed a router object, which redirects any incoming request to the getAllArticlesHandler handler:
private void getAllArticlesHandler(RoutingContext routingContext) { vertx.eventBus().<String>send(ArticleRecipientVerticle.GET_ALL_ARTICLES, "", result -> { if (result.succeeded()) { routingContext.response() .putHeader("content-type", "application/json") .setStatusCode(200) .end(result.result() .body()); } else { routingContext.response() .setStatusCode(500) .end(); } }); }
In the handler method, we’re passing an event to the Vert.x Event bus, with an event id as GET_ALL_ARTICLES. Then we process the callback accordingly for success and error scenarios.
The message from the event bus will be consumed by the ArticleRecipientVerticle, discussed in the following section.
3.2. Recipient Verticle
ArticleRecipientVerticle listens for incoming messages and injects a Spring bean. It acts as the rendezvous point for Spring and Vert.x.
We’ll inject Spring service bean into a Verticle and invoke respective methods:
@Override public void start() throws Exception { super.start(); vertx.eventBus().<String>consumer(GET_ALL_ARTICLES) .handler(getAllArticleService(articleService)); }
Here, articleService is an injected Spring bean:
@Autowired private ArticleService articleService;
This Verticle will keep listening to the event bus on an address GET_ALL_ARTICLES. Once it receives a message, it delegates it to the getAllArticleService handler method:
private Handler<Message<String>> getAllArticleService(ArticleService service) { return msg -> vertx.<String> executeBlocking(future -> { try { future.complete( mapper.writeValueAsString(service.getAllArticle())); } catch (JsonProcessingException e) { future.fail(e); } }, result -> { if (result.succeeded()) { msg.reply(result.result()); } else { msg.reply(result.cause().toString()); } }); }
This performs the required service operation and replies to the message with the status. The message reply is being referenced at the ServerVerticle and the callback result as we saw in the earlier section.
4. Service Class
The service class is a simple implementation, providing methods to interact with the repository layer:
@Service public class ArticleService { @Autowired private ArticleRepository articleRepository; public List<Article> getAllArticle() { return articleRepository.findAll(); } }
The ArticleRepository extends, org.springframework.data.repository.CrudRepository and provides basic CRUD functionalities.
5. Deploying Verticles
We will be deploying the application, just the way we would do for a regular Spring Boot application. We have to create a Vert.X instance, and deploy verticles in it, after the Spring context initialization in completed:
public class VertxSpringApplication { @Autowired private ServerVerticle serverVerticle; @Autowired private ArticleRecipientVerticle articleRecipientVerticle; public static void main(String[] args) { SpringApplication.run(VertxSpringApplication.class, args); } @PostConstruct public void deployVerticle() { Vertx vertx = Vertx.vertx(); vertx.deployVerticle(serverVerticle); vertx.deployVerticle(articleRecipientVerticle); } }
Notice that, we are injecting verticle instances into the Spring application class. So, we will have to annotate the Verticle classes,
So, we will have to annotate the Verticle classes, ServerVerticle and ArticleRecipientVerticle with @Component.
Let’s test the application:
@Test public void givenUrl_whenReceivedArticles_thenSuccess() { ResponseEntity<String> responseEntity = restTemplate .getForEntity("http://localhost:8080/api/baeldung/articles", String.class); assertEquals(200, responseEntity.getStatusCodeValue()); }
6. Conclusion
In this article, we learned about how to build a RESTful WebService using Spring and Vert.x.
As usual, the example is available over on GitHub.