Microservices with Java EE

17 November, 2017

AntonHrytsenko

Nowadays Java EE platform actively evolves respectively to modern trends. One of these trends is Microservice Architecture. In this article, I focus on development and deployment of microservices. I will investigate profiles and technologies, then I will examine servers and deployment models. Finally, I will provide an example that illustrates usage of core technologies and deployment models.

Development

Profiles

The Java EE 6 specification has introduced the definition of profile as a Java EE platform configuration for a specific class of applications. Then, the Java EE 7 specification has presented a Web Profile as a Java EE platform configuration for developers of web applications. At last, the Java EE 8 specification has brought a new version of the Web Profile.

However, the Web Profile is not suitable for developers of web services, especially, for those who utilize microservices. On the one hand, the Web profile includes a set of technologies that are surplus for web services. For example, technologies for presentation and state management (JSF and JSP) or technologies for business logic and transactions management (EJB Lite and JTA). On the other hand, the Web Profile does not embrace a set of substantial areas, like monitoring and fault tolerance.

As MicroProfile is not a part of Java EE specification, it is not restricted to certain versions of technologies.

CDI is the key technology for modern Java EE applications. Foremost, it provides support for the dependency injection that is the particular form of the inversion of control. This principle implies that a container manages components’ life cycle and their dependencies. From this point of view, this technology encompasses the following concepts:

Beans – manage Java objects

Scopes – specify life cycle and visibility

Qualifiers – select a specific bean among multiple alternatives

Interceptors – implement a crosscutting concern

Producers – create or dispose a specific bean

Events – decouple beans by removing compile-time dependencies

Besides, CDI supports integration with other technologies through the Service Provider Interface. For example, Apache DeltaSpike includes a set of CDI portable extensions to make use of resources, schedulers, validators, and so on.

Deployment

Servers

Several vendors provide full support for the Java EE platform (Table 2). Nowadays, these vendors provide good support for development of microservices. They focus on lightweight integration with Java EE platform including packaging and deployment.

The basic deployment model for the Java EE platform is to deploy and configure the application server as part of the execution environment (Figure 1). The main benefit of this model is efficient resources utilization. However, the main drawback is that the server shares its resources and state between web services. In addition, this approach separates maintenance of the application server and the web service.

All compliant Java EE application servers, for example, WildFly, TomEE or Payara, support this model by design.

Figure 1. Application server

For microservices, isolation is more important than resource utilization. As consequence, each microservice utilizes a dedicated instance of the application server in the form of a standalone server or a standalone service.

The standalone server is the executable application that includes an application server and allows deploying of a compliant web service (Figure 2). This deployment model is useful for migration, because it does not require any modification of a web service.

The standalone service is an executable application that includes both an application server and a web service (Figure 3). This approach is widely used, because it simplifies maintenance and delivery of a web service.

In most cases, a particular service does not utilize all technologies provided by a server. Profiles and predefined configurations cannot manage this, because they target a particular area, but not a particular service.

Certain servers support customization of their runtime environment (Figure 4). For Java EE application servers, this allows reducing footprint by removing the surplus dependencies, which are included into Full Platform or Web Profile. For MicroProfile servers, this allows managing additional dependencies that are not included in MicroProfile.

Figure 4. Custom service

For example, WildFly Swarm and Open Liberty support modularity, but use different approaches. WildFly Swarm uses fractions. Developers can configure a particular server instance through the Maven dependency management with a predefined bill of materials. Open Liberty uses features. Developers can configure a particular server instance through the runtime deployment descriptor.

KumuluzEE and Meecrowave are modular by design. In both cases, developers can add required modules using a build tool. However, these servers cannot guarantee compatibility of different modules.

Configuration of modular server may take a while, because it requires good knowledge of naming of modules, their compatibility, and so on. To address this question, WildFly Swarm and KumuluzEE provide generators (WildFly Swarm Project Generator and KumuluzEE POM Generator). These generators create a build script (e.g., Maven POM) with required dependencies and plugins.

I explicitly specify both media type and character set for the response. This is a good practice to improve interoperability. Then, I use constructor for dependency injection. This is a good practice to improve testability. Then, I use JSON-P Object Model API to create a response body. JSON-P supports a fluent interface that improves readability. Summing up, development of microservices includes many practices that continuously improve their quality.

@Path("timestamp")

@Produces("application/json; charset=UTF-8")

public class TimestampResource {

private TimestampService timestampService

@Inject

public TimestampResource(TimestampService timestampService) {

this.timestampService = timestampService;

}

@POST

public JsonObject current() {

return Json.createObjectBuilder()

.add("timestamp", timestampService.current())

.build();

}

}

The TimestampService class generates a timestamp. To do this, I use the modern Date and Time API that is part of Java SE 8. I add this bean into the application context by specifying its scope. I intentionally avoid using interface for this service. I recommend using interfaces only for services with more than one implementation.

@ApplicationScoped

public class TimestampService {

public long current() {

return LocalDateTime.now().toEpochSecond(ZoneOffset.UTC);

}

}

At this point, nothing else is required for building and deployment of this service.

Deployment

Firstly, I create a plain web application using Maven as a build tool. The minimal Maven POM file includes only target Java EE platform as a provided dependency. In this example, I use Java EE 8 Web Profile.

Alternatively, I can use pre-build standalone server WildFly Swarm MicroProfile and deploy this service using its command-line interface.

java -jar microprofile-2017.11.0-hollowswarm.jar timestamp-1.0.0.war

Furthermore, I create a standalone service. To do this, I extend Maven POM with the following sections: WildFly Swarm BOM for configuration, fractions for CDI, JAX-RS and JSON-P and WildFly Swarm Plugin for packaging.

<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>

<failOnMissingWebXml>false</failOnMissingWebXml>

<version.wildfly.swarm>2017.11.0</version.wildfly.swarm>

</properties>

<dependencyManagement>

<dependencies>

<dependency>

<groupId>org.wildfly.swarm</groupId>

<artifactId>bom-all</artifactId>

<version>${version.wildfly.swarm}</version>

<scope>import</scope>

<type>pom</type>

</dependency>

</dependencies>

</dependencyManagement>

<dependencies>

<dependency>

<groupId>javax</groupId>

<artifactId>javaee-web-api</artifactId>

<version>8.0</version>

<scope>provided</scope>

</dependency>

<dependency>

<groupId>org.wildfly.swarm</groupId>

<artifactId>cdi</artifactId>

</dependency>

<dependency>

<groupId>org.wildfly.swarm</groupId>

<artifactId>jaxrs-jsonp</artifactId>

</dependency>

</dependencies>

<build>

<plugins>

<plugin>

<groupId>org.wildfly.swarm</groupId>

<artifactId>wildfly-swarm-plugin</artifactId>

<version>${version.wildfly.swarm}</version>

<executions>

<execution>

<phase>package</phase>

<goals>

<goal>package</goal>

</goals>

</execution>

</executions>

</plugin>

</plugins>

</build>

I can build this service using Maven.

mvn clean package

At last, I can deploy this service as an executable application.

java -jar timestamp-wildfly-1.0.0-swarm.jar

Conclusions

The core Java EE technologies for development of web services are CDI, JAX-RS, and JSON-P. These technologies are part of Web Profile and MicroProfile. The MicroProfile is more suitable for microservices, but it is not part of a Java EE specification and has limited support on the market.

Many Java EE servers provide support for microservices. They support various deployment models that simplifies migration of existing web services.

Thank you for reaching out to Sigma Software! Please fill the form below. Our team will contact you shortly.

Full Name *

E-mail *

Phone

Company

Message

Page url

I hereby confirm that I am familiar with
Sigma Privacy Policy and agree to the personal data provided by me being stored and processed in accordance with the Policy
*

Anton

Hrytsenko

Lead Java Developer

Anton is a Lead Java Developer at Sigma Software. He is engaged in Java development since 2011. In recent years, his professional activity is focused on development and integration of enterprise applications. Anton is enthusiastic about knowledge sharing and moving the IT industry forward. He used to teach a course on Java, and now often speaks at Java meetups and conferences.