© Excellent backgrounds/Shutterstock.com
Teil 2: Microservices mit Java EE, Application Server und Docker

Ein Taschenrechner


Mit Standard-Java-8-, Java-EE-7-Bordmitteln, einem Application-Server und Docker bauen wir eine Microservices-Architektur, die schnell und leichtgewichtig ist. Und das Ganze ohne Abhängigkeiten zu Third-Party Libraries. Als Beispiel implementieren wir einen Taschenrechner.

Video: „Wer testet schon gerne?“ Kugelsicheres Java EE mit möglichst wenig Entwicklerfrustration

Die Effizienz von Java-EE-basierten Microservices lässt sich in der Theorie schwer beschreiben, ein Beispiel soll helfen. Ein Taschenrechner wird mit Java-EE-7-Microservices implementiert und mit Docker in Betrieb genommen. Der Taschenrechner wird dabei in einem Thin WAR mit einer einzigen provided-Abhängigkeit zu javax:javaee-api:7.0 realisiert. Dazu starten wir mit der Implementierung der Addition in einem POJO:

public class OperationService { public int add(int a, int b) { return a + b; } }

Damit hätten wir schon die erste CDI Bean implementiert. Die Veröffentlichung der Logik übernimmt die OperationsResource:

import javax.ejb.Stateless; import javax.inject.Inject; import javax.json.Json; import javax.json.JsonObject; import javax.ws.rs.POST; import javax.ws.rs.Path; @Stateless @Path("operations") public class OperationsResource { @Inject OperationService operations; @POST @Path("addition") public JsonObject addition(JsonObject input) { int a = input.getJsonNumber("a").intValue(); int b = input.getJsonNumber("b").intValue(); int result = operations.add(a, b); return Json.createObjectBuilder(). add("result", result). build(); } }

Die Trennung der beiden Klassen ist zwar technisch nicht nötig, in der Praxis wird allerdings das Testen dadurch erleichtert. Die Resource-Klassen enthalten keine Geschäftslogik und dürfen deswegen nicht getestet werden. Bei dem OperationService handelt es sich dagegen um eine gewöhnliche Java-Klasse, die mit JUnit getestet werden kann.

Zeit sparen

Das Implementieren eines Systemtests dauert nur wenige Minuten:

public class OperationsResourceIT { private Client client; private WebTarget tut; static final String ADDITION_URI = "http://localhost:8080/calculator/resources/operations/addition"; @Before public void init() { this.client = ClientBuilder.newClient(); this.tut = this.client.target(ADDITION_URI); } @Test public void addition() { JsonObject input = Json.createObjectBuilder(). add("a", 2). add("b", 21). build(); Response response = this.tut. request(MediaType.APPLICATION_JSON). post(json(input)); assertThat(response.getStatus(), is(200)); JsonObject jsonResult = response.readEntity(JsonObject.class); int result = jsonResult.getJsonNumber("result").intValue(); assertThat(result, is(23)); } }

Im Laufe des Projekts zahlt sich diese Investition bereits in den nächsten Stunden aus. Die Tests können entweder direkt aus der IDE oder der Kommandozeile einfach mit mvn failsafe:integration-test ausgeführt werden. Man ist für die Durchführung der Tests nicht auf curl, Browser oder Browser-Plug-ins angewiesen. Die Klasse OperationsResourceIT wird in einem eigenständigen JAR-Maven-Projekt calculator-st entwickelt. Somit ist eine strikte Trennung zwischen dem Calculator-Microservice und dem dazugehörigen Systemtest gewährleistet. In einem Systemtest darf nur über das öffentliche API des Microservice kommuniziert werden, also nur über HTTP und JSON. Für die Implementierung der JAX-RS-Aufrufe kann direkt der JAX-RS-2.0-Client verwendet werden. In unserem Beispiel verwenden wir die JAX-RS- und JSON-P-Referenzimplementierungen:

<project> <modelVersion>4.0.0</modelVersion> <groupId>cars</groupId> <artifactId>calculator-st</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <dependencies> <dependency> <groupId>org.glassfish.jersey.core</groupId> <artifactId>jersey-client</artifactId> <version>2.25.1</version> </dependency> <dependency> <groupId>org.glassfish.jersey.media</groupId> <artifactId>jersey-media-json-processing</artifactId> <version>2.25.1</version> </dependency> <dependency> <groupId>org.glassfish</groupId> <artifactId>javax.json</artifactId> <version>1.0.4</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> </project>

Ab in den Container damit

Die Anwendung wurde in meinem Fall mit NetBeans 8 entwickelt und getestet. Docker ist die Grundlage vieler Microservices- und Cloud-Umgebungen. Deswegen sollte man in der Entwicklung auch so früh wie möglich mit den Docker-Tests beginnen. Starten wir mit dem Dockerfile direkt im Wurzelverzeichnis des Projekts calculator:

FROM airhacks/tomee COPY ./target/calculator.war ${DEPLOYMENT_DIR}

Ein ausführbares Docker Image mit dem gesamten Stack [1]...

Neugierig geworden? Wir haben diese Angebote für dich:

Angebote für Teams

Für Firmen haben wir individuelle Teamlizenzen. Wir erstellen Ihnen gerne ein passendes Angebot.

Das Library-Modell:
IP-Zugang

Das Company-Modell:
Domain-Zugang