Microservices with Java EE

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.

The Eclipse Foundation has introduced a MicroProfile as a Java EE platform configuration for developers of microservices. The MicroProfile inherits a set of core technologies from the Java EE platform (CDI, JSX-RS and JSON-P) and defines a set of additional APIs. These APIs ensure support for configuration (Eclipse MicroProfile Config), monitoring (Eclipse MicroProfile Health Check and Eclipse MicroProfile Metrics), fault tolerance (Eclipse MicroProfile Fault Tolerance), and security (Eclipse MicroProfile JWT Authentication).

Nevertheless, MicroProfile is not a part of a Java EE specification. As consequence, most vendors provide guaranteed support only for core Java EE technologies, but not for additional APIs.

Technologies

The core Java EE technologies for the microservices are CDI, JAX-RS and JSON-P (Table 1). These technologies encourage a component-based development with the following characteristics:

  • Loose coupling – communication without knowledge about implementation
  • High cohesion – focus on business logic rather than on configuration
  • Extensibility – support of pluggable extensions
  • Testability – support of testing in isolation using test doubles

In addition, these technologies promote the use of POJOs and annotation-based configuration.

Table 1. Core technologies

Platform CDIJSX-RSJSON-P
Java EE 7 (JSR 342)1.1 (JSR 346)2.0 (JSR 339)1.0 (JSR 353)
Java EE 8 (JSR-366)2.0 (JSR 365)2.1 (JSR 370)1.1 (JSR 374)

 

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.

The major implementations of CDI are JBoss Weld and Apache OpenWebBeans.

JAX-RS provides support for RESTful web services. This technology encompasses the following concepts:

  • Applications – define a web service
  • Resources – serve client requests
  • Providers – extend processing of requests
  • Contexts – obtain application and request contexts
  • Client API – access other web services

The major implementations of JAX-RS are Oracle Jersey, JBoss RESTEasy, and Apache CXF.

JSON-P (JSR 374) provides support for processing of JSON. This technology encompasses the following concepts:

  • Object Model API – process JSON objects and arrays
  • Streaming API – process large amounts of JSON data using the streaming model

Besides, JSON-P supports different providers through the Service Provider Interface.

The major implementation on JSON-P is Oracle JSON-P and Apache Johnzon.

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.

Table 2. Java EE servers

ServerVendorLicense
WildFly SwarmRed HatApache 2.0
TomEEApacheApache 2.0
Payara MicroPayaraCDDL 1.1, GPL 2
Open LibertyIBMEPL 1.0

 

Furthermore, several vendors provide direct support for MicroProfile (Table 3). They focus on modular and highly configurable solutions.

Table 3. MicroProfile servers

ServerVendorLicense
KumuluzEESunesisMIT
MeecrowaveApacheApache 2.0

Models

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.

Microservices with Java EE - Application Server

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.

Microservices with Java EE - Application Server

Figure 2. Standalone server

For example, WildFly and Payara provide pre-built servers (WildFly Swarm MicroProfile and Payara Micro) to deploy web services.

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.

Microservices with Java EE - Application Server

Figure 3. Standalone service

Typically, developers can create a standalone service using a build tool. For example, TomEE and Payara provide Maven plugins for embedding servers (TomEE Embedded Maven Plugin and Payara Micro Maven Plugin). In addition, TomEE plugin allows selecting a predefined server configuration.

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.

Microservices with Java EE - Application Server

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.

Example

Development

I will create a simple microservice that returns a current timestamp.

This service consists of three classes (Figure 5).

Microservices with Java EE - Application Server

Figure 5. Microservice

The TimestampApp class defines an entry point for this service.

@ApplicationPath(“”)
public class TimestampApp extends Application {
}

 

The TimestampResource class defines a client API and handles client requests.

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.

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

<dependencies>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>8.0</version>
<scope>provided</scope>
</dependency>
</dependencies>

 

I can build this service using Maven.

mvn clean package

 

Then, I can use a basic deployment model and deploy the service into WildFly Application Server using WildFly Maven Plugin.

mvn org.wildfly.plugins:wildfly-maven-plugin:1.2.1.Final:deploy

 

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.

Share article: