This page shows how to add Knock to a project, write a first HealthCheck, let CDI discover it, and serve the MicroProfile Health endpoints. No reflection runs at startup: discovery happens through a Vauban Build Compatible Extension and the runtime relies on generated wiring only.
Prerequisites
-
Java 25 — Temurin recommended (
java=25-temin.sdkmanrc). Module path enabled. -
Maven 3.9.16 — pinned via
.sdkmanrcat the repo root. -
Strict JPMS: one
module-info.javaper Maven module.
Maven coordinates
Pick the modules matching your integration level. For a CDI + Jakarta REST application you need the API plus the two integration modules:
<properties>
<knock.version>0.2.0-SNAPSHOT</knock.version>
</properties>
<dependencies>
<!-- MicroProfile Health API + Knock SPI -->
<dependency>
<groupId>io.vidocq.knock</groupId>
<artifactId>knock-api</artifactId>
<version>${knock.version}</version>
</dependency>
<!-- Standalone core: registry, aggregation, JSON-P serialisation -->
<dependency>
<groupId>io.vidocq.knock</groupId>
<artifactId>knock-core</artifactId>
<version>${knock.version}</version>
<scope>runtime</scope>
</dependency>
<!-- CDI discovery of @Liveness/@Readiness/@Startup beans (Vauban) -->
<dependency>
<groupId>io.vidocq.knock</groupId>
<artifactId>knock-cdi-vauban</artifactId>
<version>${knock.version}</version>
<scope>runtime</scope>
</dependency>
<!-- Jakarta REST /health* endpoints (deployed on Cassini) -->
<dependency>
<groupId>io.vidocq.knock</groupId>
<artifactId>knock-jaxrs</artifactId>
<version>${knock.version}</version>
<scope>runtime</scope>
</dependency>
</dependencies>
|
|
First check
A health check is a CDI bean implementing HealthCheck, carrying exactly one probe qualifier:
package io.example;
import jakarta.enterprise.context.ApplicationScoped;
import org.eclipse.microprofile.health.HealthCheck;
import org.eclipse.microprofile.health.HealthCheckResponse;
import org.eclipse.microprofile.health.Liveness;
@Liveness
@ApplicationScoped
public class DatabaseCheck implements HealthCheck {
@Override
public HealthCheckResponse call() {
return HealthCheckResponse.named("database")
.up()
.withData("responseTime", "8ms")
.build();
}
}
|
A check must carry exactly one of |
Minimal module-info.java
module io.example {
requires microprofile.health.api;
requires jakarta.cdi;
requires jakarta.inject;
exports io.example;
}
The knock-cdi-vauban extension discovers io.example beans through the module graph — no opens and no classpath scanning are required.
Querying the endpoints
Once deployed on Cassini, the four endpoints answer immediately:
curl -i http://localhost:8080/health
{
"status": "UP",
"checks": [
{
"name": "database",
"status": "UP",
"data": { "responseTime": "8ms" }
}
]
}
A DOWN aggregate switches the HTTP status to 503 while keeping the same JSON shape.
Standalone (no CDI)
knock-core is pure Java SE. You can drive it without any container through the KnockHealthService facade:
import io.vidocq.knock.spi.HealthCheckRegistry;
import io.vidocq.knock.spi.ProbeType;
import io.vidocq.knock.internal.KnockHealthCheckRegistry;
import io.vidocq.knock.runtime.KnockHealthService;
import io.vidocq.knock.runtime.HealthReport;
HealthCheckRegistry registry = new KnockHealthCheckRegistry();
registry.register(new DatabaseCheck());
KnockHealthService service = new KnockHealthService(registry);
HealthReport report = service.report(ProbeType.ALL);
System.out.println(report.httpStatus()); // 200 or 503
System.out.println(report.json()); // serialised payload
Next step
-
Usage patterns — probe qualifiers, response data, aggregation, error handling.
-
Concepts — health check, probe type, registry, snapshot, JSON contract.