Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

@Inject Boosts Vert.x Apps

DZone's Guide to

@Inject Boosts Vert.x Apps

Take a look at what the Weld team has done with Vert.x, bringing together the reactive nature of Vert.x with traditional, synchronous models of Java EE development.

· Java Zone
Free Resource

Learn how to troubleshoot and diagnose some of the most common performance issues in Java today. Brought to you in partnership with AppDynamics.

Last year, the Weld team announced the weld-vertx project with the goal of bringing the CDI programming model into the Vert.x ecosystem. But wait, Vert.x defines itself as "a toolkit for building reactive applications on the JVM". If you look into the docs, you'll come across words like asynchronous, reactive, and non-blocking. Weld (a CDI reference implementation), on the other hand, comes from the Java EE world, which is based on standards and traditional (mostly synchronous) concepts.

So what is the point?

Well, the idea was to combine the two worlds and get the best of each of them. Ok, but why would I need this? The reality is that in most cases, developers do not start from scratch. Instead, new applications need to live side by side with existing components. And very often, there are also non-technical requirements, such as to reusing the available know-how. There is no doubt that CDI is robust and well-known amongst Java EE developers. Therefore, I think it's a good idea to try to put this together and build an effective dream team.

The Need for a Component Model

Of course, you don't need a proper component model for a simple hello world application. Nevertheless, for larger applications, a reasonable component model is a necessity. It helps make your applications maintainable and scalable in terms of development and reusability.

Vert.x works with components called Verticles. Verticles have a well-defined lifecycle and can be deployed and then communicate with other Verticles by sending messages over the event bus. Furthermore, when working with Vert.x, you can rely on callback-style or Rx-ified (using RxJava) APIs. Callbacks (and especially nested callbacks) are sometimes hard to read and difficult to debug. Reactive streams are neat but require a completely different mindset.

But what if you feel comfortable with the traditional concept of dependencies and synchronous calls? In this case, you can choose a partial upgrade, i.e. make use of new APIs but switch to DI and synchronous calls on the business logic level.

And this is the primary intention — to connect the business logic implemented as CDI beans to Vert.x APIs.

weld-vertx Modules and Features

So far, there are four modules available: Core, Web, Service Proxy, and Probe.

The Core module starts/stops the Weld SE container and notifies CDI observer methods when a message is sent via Vert.x event bus. You can also @Inject io.vertx.core.Vertx and io.vertx.core.Context into any CDI bean. Furthermore, asynchronous helpers such as AsyncReference and AsyncWorker are provided. AsyncReference can be used to obtain an injectable reference of a bean whose creation involves potentially blocking operations (such as reading data from a DB). AsyncWorker allows us to wrap a synchronous invocation of a CDI bean as an asynchronous computation. And finally, it's possible to deploy Verticles produced and injected by Weld.

The Web module allows us to configure the router (a component responsible for HTTP requests handling) in a declarative way, using the @org.jboss.weld.vertx.web.WebRoute annotation. Of course, you can still register routes programmatically, but that quickly becomes unmaintainable when you have hundreds of routes.

The Service Proxy module makes it possible to inject and invoke service proxies (as defined in https://github.com/vert-x3/vertx-service-proxy).

The Probe module enables the Weld Probe development tool in a Vert.x application.

How To Build a Simple weld-vertx Web App

All code shown below is stored in this GitHub repository — feel free to clone and experiment.

1. Project Configuration

Just add the following dependency to your pom.xml and beans.xml descriptor in src/main/resources/META-INF (this will enable CDI).

<dependency>
    <groupId>org.jboss.weld.vertx</groupId>
    <artifactId>weld-vertx-web</artifactId>
    <version>${version.weld-vertx}</version>
</dependency>


Note: This also brings in org.jboss.weld.vertx:weld-vertx-core, the Vert.x and Weld dependencies.

2. Start CDI Container and Vert.x

We will use a WeldWebVerticle to start/stop the Weld container and configure the Router.

import org.jboss.weld.vertx.web.WeldWebVerticle;
import io.vertx.core.Vertx;

public class MyVertxApp {

    public static void main(String[] args) {
        Vertx vertx = Vertx.vertx();
        WeldWebVerticle weldVerticle = new WeldWebVerticle();
        vertx.deployVerticle(weldVerticle, result -> {
            if (result.succeeded()) {
                vertx.createHttpServer().requestHandler(weldVerticle.createRouter()::accept).listen(8080);
            } else {
                throw new IllegalStateException("Weld verticle failure: " + result.cause());
            }
        });
    }
}


Tip: See also MyVertxApp.java on GitHub.

3. Define Routes

We will define io.vertx.ext.web.Routes in a declarative way, using the @org.jboss.weld.vertx.web.WebRoute annotation. The target can be a class that implements Handler<RoutingContext>:

import javax.inject.Inject;
import org.jboss.weld.vertx.web.WebRoute;
import io.vertx.core.Handler;
import io.vertx.ext.web.RoutingContext;

@WebRoute("/hello-handler")
class HelloHandler implements Handler<RoutingContext> {

    @Inject
    NameService nameService;

    @Override
    public void handle(RoutingContext ctx) {
        ctx.response().setStatusCode(200).end("Hello " + nameService.getName(ctx.request().getParam("name")) + "!");
    }
}


Tip: See HelloHandler.java on GitHub.

Or an observer method, which observes RoutingContext:

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.event.Observes;

@ApplicationScoped
class HelloObserver {

    @WebRoute("/hello-observer")
    void hello(@Observes RoutingContext ctx, NameService nameService) {
        ctx.response().setStatusCode(200).end("Hello " + nameService.getName(ctx.request().getParam("name")) + "!");
    }
}


Tip: See HelloObserver.java on GitHub.

Note: It's possible to declare multiple route observers in a single bean class and thus share some logic and data.

4. Event Bus

Vert.x makes use of a lightweight distributed messaging system to allow application components to communicate in a loosely coupled way. This should sound familiar to all CDI users, where beans may produce and consume events as well. You can send messages from CDI beans:

@ApplicationScoped
public class HelloEventBus {

    @WebRoute("/hello-event-bus")
    void hello(@Observes RoutingContext ctx, Vertx vertx) {
        // Send the message via event bus and process the reply asynchronously
        vertx.eventBus().send("name.service.address", ctx.request().getParam("name"), r -> {
            if (r.succeeded())
                ctx.response().setStatusCode(200).end("Hello " + r.result().body().toString() + "!");
            else
                ctx.fail(r.cause());
        });
    }
}


Tip: See HelloEventBus.java on GitHub.

Or consume messages in CDI beans:

import org.jboss.weld.vertx.VertxConsumer;
import org.jboss.weld.vertx.VertxEvent;

@ApplicationScoped
public class NameService {

    String getName(String name) {
        return name != null ? name : "courageous developer";
    }

    void getName(@Observes @VertxConsumer("name.service.address") VertxEvent event) {
        Object body = event.getMessageBody();
        event.setReply(getName(body != null ? body.toString() : null));
    }
}


Tip: See NameService.java on GitHub.

5. Run and Enjoy

And that’s it. Run the MyVertxApp application and try to access the HTTP endpoints at localhost:8080/hello-handler, localhost:8080/hello-observer, and localhost:8080/hello-event-bus.

Conclusion

We have shown that Weld and Vert.x play well together. weld-vertx can help Java EE developers leverage Vert.x APIs without needing to change the way they're used to write business logic. It's an open source project, so feel free to create issues, share ideas, throw feature requests, and send pull requests!

Links

Understand the needs and benefits around implementing the right monitoring solution for a growing containerized market. Brought to you in partnership with AppDynamics.

Topics:
cdi ,weld ,java ,dependency injection ,vert.x ,tutorial

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}