Introduction to Eclipse MicroProfile

Craftsmen visited the Oracle Code One, formerly known as JavaOne, Conference in San Francisco in October. Apart from the extracurricular activities like a bike ride (across the Golden Gate Bridge and around the Bay) and a visit to the Google Headquarters, there were lots of interesting sessions to attend.

Most of the sessions I attended were about Machine Learning, Blockchain and Microservices. I was especially interested in sessions about the Eclipse MicroProfile specification for microservices. Of which version 2.1 was released just days before the conference.

Please find the sessions about MicroProfile that I attended in the resources section.

This is the first part of a series of blogs about the Eclipse MicroProfile specification I plan to write. In the first two articles, you find the second one here, I introduce the specification itself.

Eclipse MicroProfile Platform

The Eclipse MicroProfile Platform specification is an open-source community specification for optimizing Enterprise Java for a microservices architecture.

The Platform specification is part of the Eclipse Foundation (which also harbours the new Jakarta EE specifications) and is supported by vendors such as (but not limited to) IBM, Oracle, Microsoft, Craftsmen, Red Hat, Payara, Tomitribe, Fujitsu, Hammock and Lightbend.

The MicroProfile Platform specification combines component specifications for configuration, metrics, REST, JSON, fault tolerance, security and dependency injection as depicted in the figure below.

configuration, metrics, REST, JSON, fault tolerance, security and dependency injection

There is a MicroProfile Platform specification based on Java EE 7 (the latest being version 1.4) and a Platform specification based on Java EE 8 (the latest being version 2.2, released in February).

A new version of the Platform specification is expected every four months.

Current MicroProfile implementations (ranging from application servers to Java libraries) are available from vendors shown in the figure below.

Oracle IBM en andere rakkers

If you use one of these implementations, you have some MicroProfile components available out of the box, like default metrics, OpenApi and a default health check. And after adding the MicroProfile dependency, you can leverage the full use of these components in your application by adding annotations, implementing interfaces, etc.

<dependencies>
   <dependency>
       <groupId>org.eclipse.microprofile</groupId>
       <artifactId>microprofile</artifactId>
       <version>2.1</version>
       <type>pom</type>
       <scope>provided</scope>
   </dependency>
</dependencies>

Eclipse MicroProfile components

I won’t go into the Java EE 8 JSRs, CDI, JAX-RS, JSON-P and JSON-B here. I will focus on other MicroProfile components in these articles, starting with the Config, Metrics, Fault Toleration and Health Check components.

Config

You want to be able to modify configuration data from outside an application so that the application itself does not need to be repackaged. This component offers a Java API to support these externalised configuration data.

Out of the box the configuration data can come from three different locations. These locations are called Config Sources. If the same property is defined in multiple Config Sources, the ordinal of the Config Sources determines the order in which the application will look for a certain property.

system environment application

First the application will look in the System properties. If the property is not found, the application will look in the environment variables, and if the property is still not found it will look in all microprofile-config.properties files on the classpath.

If the property is not found at all it will fall back to the default value in the annotation.

You can also write your own implementation of the ConfigSource interface, for example, if your configuration data is stored in a database or Spring Cloud Config. You can also define the load order for that source.

A simple example of using the MicroProfile ConfigProperty annotation is shown below.

@Path("hello")
@RequestScoped
public class HelloWorldResource {

   @Inject
   @ConfigProperty(name="name", defaultValue="World")
   private String name;

   @GET
   public Response greet() {
       return Response.ok("Hello " + name + "!").build();
   }
}

In this example the value of the property name is injected on application start-up. If no configuration for name can be found, the default value “World” is used.

Sometimes it is necessary for an application to reload configuration data after it changes. The Config API makes it possible to pick up configured values immediately after they change.

Metrics

To ensure reliable operation of software it is necessary to monitor essential system parameters. This component aims to provide a unified way for MicroProfile servers to export monitoring data and a unified Java API to expose application specific monitoring data.

The format of this monitoring data is Open Metrics (Prometheus) by default, but can also be configured to be exported as JSON.

Servers that implement MicroProfile Metrics have their metrics located at the /metrics endpoint. There are three kinds of metrics, which are called scopes.

The base scope has all the core information of the server and is required for all implementations. This scope provides data on, among other things, heap memory, thread count, and available processors. It is located at /metrics/base.

The vendor scope is located at /metrics/vendor and exposes vendor-specific information. This data does not need to be portable between different implementations.

The application scope exposes the application-specific information and is located at /metrics/application. For this scope a Java API is provided.

How this API can be used:

@Path("hello")
@ApplicationScoped
public class HelloWorldResource {

   @Metered(name="greets", unit=MetricUnits.SECONDS)
   @GET
   public Response greet() {
       return Response.ok("Hello World!").build();
   }
}

Here the REST service greet is monitored. The application exports the monitoring data containing the number of times the service is called and the rate per second the calls occur.

Off course the API also offers other annotations to monitor applications.

Fault Tolerance

Fault tolerance provides a simple and flexible solution to build a robust and resilient microservice. It leverages different strategies to guide the execution and result of some logic.

Think retry policies, bulkheads, and circuit breakers. They dictate whether and when executions should take place, and offer fall-backs like alternative results when execution does not complete successfully.

The aim for this component specification is to offer a standard which can be adopted and implemented by the MicroProfile implementations.

An example of using a circuit breaker with a fall-back is shown below. It protects the greet service if the call to the backend system fails or takes too long, and returns an alternative result. Which is provided via the fall-back handler, which is an implementation of the FallbackHandler interface.

@Path("hello")
@ApplicationScoped
@CircuitBreaker(delay=10, delayUnit=ChronoUnit.SECONDS,
       requestVolumeThreshold=3, failureRatio=1.0)
@Timeout(value=3, unit=ChronoUnit.SECONDS)
public class CircuitBreakerResource {

   @GET
   @Fallback(HelloWorldFallbackHandler.class)
   public Response greet() {
       String name = callToBackend();
       return Response.ok("Hello " + name + "!").build();
   }
}

Health checks

Health checks are used to probe the state of a computing node from another machine. These checks are intended as machine-to-machine mechanisms, such as liveness checks in a Kubernetes cluster. The MicroProfile implementation provides a /health endpoint that represents the status (either UP or DOWN) of the microservices.

The result of this health check will be a JSON response containing the overall outcome and an array of checks containing the status and optionally some metadata (as key-value pairs) of the implemented health checks of the microservices.

A microservice can supply zero or more health checks, and the overall health of the server is the aggregate of the status from each health check. If no health check is implemented only the status of the MicroProfile container is returned.

A health check is implemented by providing an implementation of the call method of the HealthCheck interface, which returns a HealthCheckResponse. This response contains the name, state (UP or DOWN) and optionally any other data (in key-value pairs) you want to include.

@Health
@ApplicationScoped
public class HelloWorldHealthResource implements HealthCheck {
   
   @Override
   public HealthCheckResponse call() {
       return HealthCheckResponse.named("my-check")
               .up()
               .withData("status", "I’m alive!")
               .build();
   }
}

It’s alive!

In the next part I will give an overview of the changes in version 2.2 of the Eclipse MicroProfile Platform specification, which was released in February, and cover the other components, OpenAPI, OpenTracing, JWT Authentication and REST Client.

After that I plan to write some more articles about certain aspects of the components in greater detail. So stay tuned!

Resources

Oracle Code One sessions

• Overview of Oracle Code One sessions (including pdf versions of the slides) https://oracle.rainfocus.com/widget/oracle/oow18/catalogcodeone18
• From Jakarta EE over MicroProfile to Serverless: Interactive Onstage Hacking (Adam Bien) – https://www.youtube.com/watch?v=eBcpvmLjpZM
• Jakarta EE: What Is It and What Does It Mean for Enterprise Java? (Open panel discussion)
• Microservice Patterns: Implemented by Eclipse MicroProfile (Ivar Grimstad)
• Be Reactive and Micro with a MicroProfile Stack (Ondro Mihalyi)

Unfortunately, only Adam Bien’s session was recorded on video.

Other resources
https://microprofile.io
https://github.com/ivargrimstad/microservice-patterns

Leave a Reply

Your email address will not be published. Required fields are marked *