This project contains the proof-of-concept framework used at the Brazilian Federal Budget Office to convert its legacy monolith application, based on J2EE 1.4, into a modern microservices based architecture.
The main motivation for implementing this framework instead of using some existing library is to provide a familiar programming interface (based on JAX-RS and EJB annotations), while leveraging the advantages of asynchronous I/O, green threads, and containerization.
This implementation uses Vert.x to manage handler registration and event delivery and Hazelcast to manage node discovery, addressing and consensus.
-
duna-core
: defines the building blocks of Duna. Exposes interfaces to declare service contracts and identify implementations; -
duna-annotations
: basic annotations used in service interfaces; used to identify service contracts, handler address and service dependencies; -
duna-cluster
: used to orchestrate services in a cluster by injecting remote proxies, registering services into the cluster manager, and routing events to service handlers; -
duna-gradle-plugin
: plugin used to assist in code generation; -
duna-http-port-api
: API used to declare exposed HTTP endpoints in services; -
duna-http-port
: creates an HTTP server whose endpoints are detected at runtime by annotations provided induna-http-port-api
; -
duna-persistence
: assists the creation of entity managers and database streams; -
duna-agent
: Java agent used to generate bytecode at runtime in order to implement and inject dynamic proxies to remote services.
This project depends on Java and Gradle and works better with Oracle JVM. To install Gradle, please refer to its documentation.
Assuming Gradle and Java are available, to install the artifacts into your local maven repository, run this command:
$ gradle publishToMavenLocal
Add a dependency to duna-core
in your project. If you want your services
to be clustered, add duna-cluster
also:
dependency {
compile 'io.duna:duna-core:0.4.4'
compile 'io.duna:duna-cluster:0.4.4' (1)
}
-
duna-cluster
is required only if clustering support is needed.
To create a service, you need to create an interface, containing the service operations and HTTP endpoints, and a class implementation:
@Contract
public interface EchoService {
String echo(String shout);
}
@Service
public class EchoServiceImpl implements EchoService {
@Override
public String echo(String shout) {
return shout;
}
}
To inject a service into another, you should annotate a field with
@javax.inject.Inject
.
public class ShoutServiceImpl extends ShoutService {
@Inject
private EchoService echoService;
public String shout(String message) {
return echoService.echo(message);
}
}