Tip
|
The corresponding source code is in the step-3 folder of the guide repository.
|
The previous refactoring was a big step forward compared to our initial implementation, as we extracted independent and configurable verticles connected using asynchronous messages on the event bus. We also saw that we could deploy several instances of a given verticle to better cope with load and to better leverage CPU cores.
In this section we see how to design and use Vert.x services. The main advantage of a service is that it defines an interface for doing certain operations that a verticle exposes. We also leverage code generation for all the event bus messaging plumbing, instead of crafting it ourselves like we did in the previous section.
We are also going to refactor the code into different Java packages:
step-3/src/main/java/ └── io └── vertx └── guides └── wiki ├── MainVerticle.java ├── database │ ├── ErrorCodes.java │ ├── SqlQuery.java │ ├── WikiDatabaseService.java │ ├── WikiDatabaseServiceImpl.java │ ├── WikiDatabaseVerticle.java │ └── package-info.java └── http └── HttpServerVerticle.java
io.vertx.guides.wiki
will now contain the main verticle, io.vertx.guides.wiki.database
the database verticle and service, and io.vertx.guides.wiki.http
the HTTP server verticle.
First, we need to add the following 2 dependencies to our project.
Obviously we need the vertx-service-proxy
APIs:
link:pom.xml[role=include]
We need the Vert.x code generation module as a compilation-time only dependency (hence the provided
scope):
link:pom.xml[role=include]
Next we have to tweak the maven-compiler-plugin
configuration to use code generation, which is done via a javac
annotation processor:
link:pom.xml[role=include]
Note that the generated code is put in src/main/generated
, which some integrated development environments like IntelliJ IDEA will automatically pick up on the classpath.
It is also a good idea to update the maven-clean-plugin
to remove those generated files:
link:pom.xml[role=include]
Tip
|
The full documentation on Vert.x services is available at http://vertx.io/docs/vertx-service-proxy/java/ |
Defining a service interface is as simple as defining a Java interface, except that there are certain rules to respect for code generation to work and also to ensure inter-operability with other code in Vert.x.
The beginning of the interface definition is:
link:src/main/java/io/vertx/guides/wiki/database/WikiDatabaseService.java[role=include]
-
The
ProxyGen
annotation is used to trigger the code generation of a proxy for clients of that service. -
The
Fluent
annotation is optional, but allows fluent interfaces where operations can be chained by returning the service instance. This is mostly useful for the code generator when the service shall be consumed from other JVM languages. -
Parameter types need to be strings, Java primitive types, JSON objects or arrays, any enumeration type or a
java.util
collection (List
/Set
/Map
) of the previous types. The only way to support arbitrary Java classes is to have them as Vert.x data objects, annotated with@DataObject
. The last opportunity to pass other types is service reference types. -
Since services provide asynchronous results, the last argument of a service method needs to be a
Handler<AsyncResult<T>>
whereT
is any of the types suitable for code generation as described above.
It is a good practice that service interfaces provide static methods to create instances of both the actual service implementation and proxy for client code over the event bus.
We define create
as simply delegating to the implementation class and its constructor:
link:src/main/java/io/vertx/guides/wiki/database/WikiDatabaseService.java[role=include]
The Vert.x code generator creates the proxy class and names it by suffixing with VertxEBProxy
.
Constructors of these proxy classes need a reference to the Vert.x context as well as a destination address on the event bus:
link:src/main/java/io/vertx/guides/wiki/database/WikiDatabaseService.java[role=include]
Note
|
The SqlQuery and ErrorCodes enumeration types that were inner classes in the previous iteration have been extracted to package-protected types, see SqlQuery.java and ErrorCodes.java .
|
The service implementation is a straightforward port of the previous WikiDatabaseVerticle
class code.
The essential difference is the support of the asynchronous result handler in the constructor (to report the initialization outcome) and in the service methods (to report the operation success).
The class code is the following:
link:src/main/java/io/vertx/guides/wiki/database/WikiDatabaseServiceImpl.java[role=include]
There is one last step required before the proxy code generation works: the service package needs to have a package-info.java
annotated to define a Vert.x module:
link:src/main/java/io/vertx/guides/wiki/database/package-info.java[role=include]
As most of the database handling code has been moved to WikiDatabaseServiceImpl
, the WikiDatabaseVerticle
class now consists of 2 methods: the start
method to register the service and a utility method to load SQL queries:
link:src/main/java/io/vertx/guides/wiki/database/WikiDatabaseVerticle.java[role=include]
-
We register the service here.
Registering a service requires an interface class, a Vert.x context, an implementation and an event bus destination.
The WikiDatabaseServiceVertxEBProxy
generated class handles receiving messages on the event bus and then dispatching them to the WikiDatabaseServiceImpl
.
What it does is actually very close to what we did in the previous section: messages are being sent with a action
header to specify which method to invoke, and parameters are encoded in JSON.
The final steps to refactoring to Vert.x services is to adapt the HTTP server verticle to obtain a proxy to the database service and use it in the handlers instead of the event bus.
First, we need to create the proxy when the verticle starts:
link:src/main/java/io/vertx/guides/wiki/http/HttpServerVerticle.java[role=include]
-
We just need to make sure to use the same event bus destination as the service that was published by
WikiDatabaseVerticle
.
Then, we need to replace calls to the event bus with calls to the database service:
link:src/main/java/io/vertx/guides/wiki/http/HttpServerVerticle.java[role=include]
The WikiDatabaseServiceVertxProxyHandler
generated class deals with forwarding calls as event bus messages.
Tip
|
It is still perfectly possible to consume a Vert.x service directly via event bus messages since this is what generated proxys do. |