MicroProfile 3.0 with improved developer experience on Open Liberty 19.0.0.7
Welcome to MicroProfile 3.0 on Open Liberty! MicroProfile 3.0 provides improvements to the developer experience. MicroProfile Rest Client provides simplified configuration of SSL authentication and multiple client interfaces, MicroProfile Health Check separates liveness and readiness endpoints so that Kubernetes can check for both, and MicroProfile Metrics provides multi-dimensional metrics and simpler counters. In addition, Open Liberty now supports the PostgreSQL relational database. Give it a try in Open Liberty 19.0.0.7.
In Open Liberty 19.0.0.7:
If you’re curious about what’s coming in future Open Liberty releases, take a look at our previews in the latest development builds. In particular, get an early insight into MicroProfile Reactive Messaging.
View the list of fixed bugs from 19.0.0.7
Run your apps using 19.0.0.7
If you’re using Maven, here are the coordinates:
<dependency>
<groupId>io.openliberty</groupId>
<artifactId>openliberty-runtime</artifactId>
<version>19.0.0.7</version>
<type>zip</type>
</dependency>
Or for Gradle:
dependencies {
libertyRuntime group: 'io.openliberty', name: 'openliberty-runtime', version: '[19.0.0.7,)'
}
Or if you’re using Docker:
docker pull open-liberty
Or take a look at our Downloads page.
MicroProfile 3.0 support
Add the whole of MicroProfile 3.0 to your application with this convenience feature in your server.xml
:
<featureManager>
<feature>microProfile-3.0</feature>
</featureManager>
The microProfile-3.0
feature automatically includes the following features in your app: jaxrs-2.1
, cdi-2.0
, jsonp-1.1
, jsonb-1.0
, mpConfig-1.3
, mpFaultTolerance-2.0
, mpHealth-2.0
, mpJwt-1.1
, mpMetrics-2.0
, mpOpenAPI-1.1
, mpOpenTracing-1.3
, and mpRestClient-1.3
.
Improved portability and developer experience (MicroProfile Rest Client 1.3)
MicroProfile Rest Client 1.3 improves portability and developer experience:
-
HTTPS configuration is now part of the spec, so SSL stores and certificate-based authentication are now portable across multiple MicroProfile Rest Client vendors.
-
Rest Client interface instances now implement
AutoCloseable
allowing developers to better control resource utilization. -
Config Keys simplify configuration of multiple client interfaces. For example, suppose you have three client interfaces that all use the same base URI:
@RegisterRestClient(configKey="myKey") @Path("/path1") public interface ClientInterface1 { ... } @RegisterRestClient(configKey="myKey") @Path("/path2") public interface ClientInterface2 { ... } @RegisterRestClient(configKey="myKey") @Path("/path3") public interface ClientInterface3 { ... }
All it takes to set the base URI for all three clients is this MicroProfile Config property:
myKey/mp-rest/uri=http://somehost:9080/contextRoot
-
MicroProfile Rest Client 1.3 defaults the MIME type to
application/json
if it is left unspecified; in previous releases, it was undefined which MIME type would be used. If you are not using JSON, it might be a good idea to ensure your client interfaces specify the MIME types for request/response using the@Consumes
/@Produces
annotations respectively.
Learn more about MP Rest Client 1.3.
Separate liveness and readiness checks of microservice health (MicroProfile Health Check 2.0)
MicroProfile Health Check 2.0 enables you to provide your own health check procedures to be invoked by Liberty, to verify the health of your microservice.
MicroProfile Health Check 2.0 introduces two new endpoints, /health/live
and /health/ready
, which represent the liveness and readiness of your microservice respectively. You can now configure the Kubernetes Liveness and Readiness probes with these two endpoints. Previously, you could only configure one of the Kubernetes Liveness or Readiness probes to represent the liveness or readiness of your microservice with a single /health
endpoint.
A readiness check is a health check that enables third-party services, such as Kubernetes, to know whether the microservice is ready to process requests or not. For example, dependency checks, such as database connections, application initialization, and so on.
A liveness check is a health check that enables third-party services to determine whether the microservice is running. This means that if this procedure fails, the application can be discarded (terminated, shutdown) for, for example, running out of memory.
To use MicroProfile Health Check 2.0 in your app, add the feature to your server.xml
:
<featureManager>
<feature>mpHealth-2.0</feature>
</featureManager>
Applications are expected to provide health check procedures, by implementing the HealthCheck interface with the @Liveness
or @Readiness
annotations, which are used by Liberty to verify the liveness or readiness of the application, respectively. Add the logic of your health check in the call()
method. To view the status of each health check, access the either the http://<hostname>:<port>/health/live
or the http://<hostname>:<port>/health/ready
endpoints.
**Liveness Check**
@Liveness
@ApplicationScoped
public class AppLiveCheck implements HealthCheck {
...
@Override
public HealthCheckResponse call() {
...
}
}
**Readiness Check**
@Readiness
@ApplicationScoped
public class AppReadyCheck implements HealthCheck {
...
@Override
public HealthCheckResponse call() {
...
}
}
...
See also:
Instrument metrics in microservices for easy monitoring (MicroProfile Metrics 2.0)
MicroProfile Metrics 2.0 introduces multi-dimensional metrics through the use of metric tags. This is an evolution from Metrics 1.x which only allowed a metric name to be used with only one set of tags. Now multiple related metrics can be easily queried and monitored by name through a monitoring tool.
Additionally in MicroProfile Metrics 2.0 the Counter metric type has been simplified. Counters now only count up. A new metric type ConcurrentGauge has been introduced which inherits the non-monotonic behavior of the Counter from MicroProfile Metric 1.x. The new concurrent gauge metric also keeps a high and low water mark. This change simplifies the usage of the MicroProfile Metrics API.
Lastly, Microprofile Metrics 2.0 uses the new multi-dimensional metric capability by auto-tagging metrics with an _app
tag with the value retrieved from the mp.metrics.appName
value, if defined. This is especially useful if multiple apps are running because it tags each individual application’s metrics with the name of the application.
To use the MicroProfile Metrics 2.0 feature in your app, add the feature to the server.xml
:
<featureManager>
<feature>mpMetrics-2.0</feature>
</featureManager>
The annotated Counter (@Counted
) no longer has the monotonic parameter. It is inherently monotonic and only counts up sequentially. To use the concurrent gauge, annotate with @ConcurrentGauge
:
@Counted(name = "colorCount", absolute = true, tags= {"color=blue"})
public String countBlueShapes() {
...
}
@Counted(name = "colorCount", absolute = true, tags= {"color=red"})
public String countRedShapes() {
...
}
@ConcurrentGauge(name = "myConcurrentGauge", absolute = true)
public String countConcurrently() throws InterruptedException {
...
}
See also:
Support for PostgreSQL relational database
PostgreSQL is a very popular open source relational database that has a wide amount of adoption in the community. Now there is a first-class configuration support for using it with Open Liberty.
To use PostgreSQL with Open Liberty, first make sure one of the JDBC features is enabled:
<featureManager>
<feature>jdbc-4.2</feature>
<feature>jndi-1.0</feature> <!-- Required only if JNDI is desired to look up resources -->
</featureManager>
Then, configure a data source as follows:
<dataSource jndiName="jdbc/postgresql">
<jdbcDriver libraryRef="PostgresLib" />
<properties.postgresql serverName="localhost" portNumber="5432" databaseName="SAMPLEDB"
user="bob" password="secret"/>
</dataSource>
<library id="PostgresLib">
<fileset dir="${server.config.dir}/jdbc"/>
</library>
Get the JDBC driver for PostgreSQL from Maven Central.
Get the Postgres Docker images from DockerHub.
For more about PostgreSQL, see PostgreSQL website.
Previews of early implementations available in development builds
You can now also try out early implementations of some new capabilities in the latest Open Liberty development builds:
These early implementations are not available in 19.0.0.7 but you can try them out in our daily Docker image by running docker pull openliberty/daily
. Let us know what you think!
Reactive messaging in microservices (MicroProfile Reactive Messaging)
An application using reactive messaging is composed of CDI beans consuming, producing, and processing messages passing along reactive streams. These messages can be internal to the application or can be sent and received via different message brokers.
Reactive Messaging provides a very easy to use way to send, receive, and process messages. With MicroProfile Reactive Messaging, you can annotate application beans' methods to have messages on a particular channel (@Incoming, @Outgoing, or both) and Liberty drives those methods appropriately as reactive streams publishers, subscribers, or processors.
To enable the feature include it in your server.xml
feature list:
<featureManager>
<feature>mpReactiveMessaging-1.0</feature>
...
</featureManager>
With this feature in the OpenLiberty runtime, an application CDI bean can have one of its methods annotated as being message driven. In the example below, the method processes messages from the "greetings" channel:
@Incoming("greetings")
publicCompletionStage <Void> consume(Message<String> greeting ){
return greeting.ack();
}
A channel represents a stream of messages of a given type and, usually, the same topic. Channels can operate locally within the process or use message brokers to send messages between services.
For example, with no code changes we could change the consume method above to subscribe to messages from the Kafka greetings topic using a Kafka connector like so:
mp.messaging.incoming.greetings.connector=io.openliberty.kafka
The io.openliberty.kafka
connector operates according to the reactive messaging specification. For example the consume
method above is, by default, set to consume messages from a Kafka topic queue. Further Kafka client properties can be set for the channel by setting properties that are picked up by the MicroProfile Config specification. For example, System properties via OpenLiberty’s bootstrap.properties
file or environment variables from OpenLiberty’s server.env
file. As per the reactive messaging specification the following configuration properties are passed
to the Kafka client:
mp.messaging.incoming.greetings.[PROPERTY-NAME]=value1
mp.messaging.connector.io.openliberty.kafka.[PROPERTY-NAME]=value2
These are passed to the Kafka Consumer factory method as:
PROPERTY-NAME=value
So, for example, a full set of properties to access IBM Public Cloud Event Streams could look like:
mp.messaging.connector.io.openliberty.kafka.bootstrap.servers=broker-1-eventstreams.cloud.ibm.com:9093,broker-2-eventstreams.cloud.ibm.com:9093
mp.messaging.connector.io.openliberty.kafka.sasl.jaas.config=org.apache.kafka.common.security.plain.PlainLoginModule required username="token" password="my-apikey";
mp.messaging.connector.io.openliberty.kafka.sasl.mechanism=PLAIN
mp.messaging.connector.io.openliberty.kafka.security.protocol=SASL_SSL
mp.messaging.connector.io.openliberty.kafka.ssl.protocol=TLSv1.2
When using Kafka-based channels, Open Liberty Reactive Messaging 1.0 loads the Kafka client classes using the application classloader. If you are using the io.openliberty.kafka
connector to
read or write Kafka messages, include in your application a Kafka client API jar that is compatible with your Kafka server. For example, the /WEB-INF/lib/
folder would be a suitable place to place a Kafka client JAR when building the application’s .war
file.
This is an early release of the Open Liberty Reactive Messaging Kafka connector. We will look to provide more support for sensible defaults and cloud binding information such as Cloud Foundry’s VCAP_SERVICES
environment variable in the 1.0 release.
Find out more in the MicroProfile Reactive Messaging spec.
Testing database connections in Liberty apps with REST APIs
How many times have you had to write a server-side test that gets a connection just to check if your configuration is valid and your app can connect to your database? Now by utilizing the REST API provided by the configValidator-1.0 beta feature, you can validate supported elements of your configuration via REST endpoints.
To enable these REST endpoints, add the configValidator-1.0 beta feature to any server using JDBC, JCA, or JMS technologies. For more information checkout this blog post.
<featureManager>
<feature>configValidator-1.0</feature>
</featureManager>
MicroProfile Context Propagation (formerly MicroProfile Concurrency)
MicroProfile Context Propagation (formerly MicroProfile Concurrency) allows you to create completion stages that run with predictable thread context regardless of which thread the completion stage action ends up running on.
MicroProfile Context Propagation provides completion stages that run with predictable thread context that also benefit from being backed by the automatically-tuned Liberty global thread pool. Configuration of concurrency constraints and context propagation is possible programmatically with fluent builder API where defaults can be established using MicroProfile Config.
To enable the MicroProfile Context Propagation 1.0 feature in your server.xml
:
<featureManager>
<feature>mpContextPropagation-1.0</feature>
<feature>cdi-2.0</feature> <!-- used in example -->
<feature>jndi-1.0</feature> <!-- used in example -->
... other features
</featureManager>
Example usage of programmatic builders:
ManagedExecutor executor = ManagedExecutor.builder()
.maxAsync(5)
.propagated(ThreadContext.APPLICATION, ThreadContext.SECURITY)
.build();
CompletableFuture<Integer> stage1 = executor.newIncompleteFuture();
stage1.thenApply(function1).thenAccept(value -> {
try {
// access resource reference in application's java:comp namespace,
DataSource ds = InitialContext.doLookup("java:comp/env/jdbc/ds1");
...
} catch (Exception x) {
throw new CompletionException(x);
}
};
...
stage1.complete(result);
Example usage in a CDI bean:
// CDI qualifier which is used to identify the executor instance
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER })
public @interface AppContext {}
// Example producer field, defined in a CDI bean,
@Produces @ApplicationScoped @AppContext
ManagedExecutor appContextExecutor = ManagedExecutor.builder()
.propagated(ThreadContext.APPLICATION)
.build();
// Example disposer method, also defined in the CDI bean,
void disposeExecutor(@Disposes @AppContext exec) {
exec.shutdownNow();
}
// Example injection point, defined in a CDI bean,
@Inject @AppContext
ManagedExecutor executor;
...
CompletableFuture<Integer> stage = executor
.supplyAsync(supplier1)
.thenApply(function1)
.thenApplyAsync(value -> {
try {
// access resource reference in application's java:comp namespace,
DataSource ds = InitialContext.doLookup("java:comp/env/jdbc/ds1");
...
return result;
} catch (Exception x) {
throw new CompletionException(x);
}
});
For more information:
-
Information about the 1.0 release (including the specification, the Javadoc API, and Maven coordinates for the spec jar)