Skip to main content

Microservice Overview

Juneau microservices are self-contained, deployable REST servers built on top of the Juneau REST server framework. A microservice packages your REST resources, configuration, and an embedded HTTP container into a single executable jar (or WAR) that you can start with a plain java -jar command.

The microservice layer builds on top of the full Juneau stack:

Juneau Microservice Stackjuneau-microservice — core lifecycle, config, console, inject bootstrapjuneau-rest-server — @Rest / @RestOp REST engine (serialization, routing, guards, …)juneau-marshall — multi-format POJO marshalling (JSON, XML, HTML, YAML, …)Deployment target (one of Jetty / Tomcat / Spring Boot)

Deployment Targets​

Juneau provides three independently-releasable deployment adapters. All three share the same Microservice + @Configuration + @Bean Servlet programming model and the same lifecycle contracts.

ModuleWhen to use
juneau-microservice-jettyDefault choice for standalone runnable jars. Ships a zero-config JettyMicroservice.run(args, servlet) one-liner and a classpath-driven jetty.xml knob for advanced connector tuning.
juneau-microservice-tomcatDrop-in alternative when your organisation standardises on Tomcat, or when you want to share [Tomcat] config between an embedded dev launcher and a full Tomcat deployment.
juneau-rest-server-springbootIntegration point for Spring Boot applications. REST resources extend BasicSpringRestServlet / BasicSpringRestServletGroup so Spring @Autowired injection and @Bean resolution flow through the Spring application context instead of the Juneau bean store.

All three adapters depend on juneau-microservice for the core lifecycle engine and on juneau-rest-server for the REST framework itself.


Lifecycle​

Every Juneau microservice follows a builder → configure → start → join/stop lifecycle.

MicroserviceMicroservice.create() — obtain a fluent builderbuilder.args(args) — pass CLI argumentsbuilder.configurations(…) — register @Configuration classes (adds the HTTP container)builder.build() — construct the Microservice instancestart() — start all MicroserviceListeners (including the HTTP container)startConsole() — (optional) launch interactive stdin consolejoin() — block the calling thread until stop() is calledstop() — stop all listeners in reverse order; close the bean store

All methods on Microservice return this, making it easy to chain the whole bootstrap in one fluent expression.


Microservice API Classes​

The core lifecycle engine lives in a small, self-contained set of packages and classes:

Microservice APIorg.apache.juneau.microservice - Main packageMicroservice - The base microservice class.Microservice.Builder - Builder for the microservice class.MicroserviceListener - Interface for hooking into lifecycle events of the microservice.BasicMicroserviceListener - No-op adapter for the MicroserviceListener interface.org.apache.juneau.microservice.console - Console packageConsoleCommand - Abstract class for defining interactive console commands.

By itself the core API provides only the bootstrap machinery — an executable-jar lifecycle, config resolution, command-line-argument and manifest access, an interactive console, and the inject bean store. The embedded HTTP server is contributed by a deployment adapter (Jetty, Tomcat, or Spring Boot) registered as a @Configuration class.


Hello World (Jetty)​

The following is the smallest complete Juneau microservice: a single REST resource mounted on an embedded Jetty server with automatic JSON/XML/HTML content negotiation.

Add the dependency, with juneau-bom imported as on Install Juneau:

<dependency>
<groupId>org.apache.juneau</groupId>
<artifactId>juneau-microservice-jetty-bundle</artifactId>
<type>pom</type>
</dependency>

Define a REST resource:

import org.apache.juneau.http.*;
import org.apache.juneau.rest.server.*;
import org.apache.juneau.rest.server.servlet.*;

@Rest(
path = "/hello",
title = "Hello World"
)
public class HelloResource extends BasicRestServlet {

@RestGet(path = "/*", summary = "Returns a greeting.")
public String sayHello() {
return "Hello, World!";
}
}

Boot it from main:

import org.apache.juneau.microservice.jetty.*;

public class App {
public static void main(String[] args) throws Exception {
JettyMicroservice.run(args, new HelloResource(), false).join();
}
}

JettyMicroservice.run(args, servlet, false) is a convenience facade that wires JettyConfiguration into the Microservice builder, registers the servlet at the path in its @Rest annotation, and starts on port 10000 (or as configured in juneau.cfg); join() blocks until the server stops. The false turns the interactive console off, as on Your First REST App; run(args, servlet) turns it on. Point a browser at http://localhost:10000/hello — the default HTML view renders automatically.

For the Tomcat or Spring Boot equivalents, see the module-specific pages listed in the Deployment Targets section above.

Ports used in these docs​

PortWhen
10000Jetty microservice (Getting Started, MCP quickstart, starters, Petstore Jetty). Set by jetty.xml $S{availablePort,10000}. The Spring Boot starter also uses 10000 (server.port), as does the juneau-examples-mcp Jetty ExampleServer (DEFAULT_PORT = 10000).
8080Spring Boot's default (Spring guides, the MCP recipe snippets, the juneau-examples-mcp Spring example) and Tomcat.
5000Petstore Spring Boot (server.port=${PORT:5000}).

Configuration Files​

Every microservice reads its runtime settings from an INI-style juneau.cfg file that is resolved from the classpath or working directory at startup. Key sections used by the built-in modules:

[Microservice]
# Name and version shown in the console banner.
name = MyApp
version = 1.0

[Jetty]
# Comma-separated list of candidate ports; first available wins. 0 = random.
port = 8080, 0

[Logging]
# Root logging level (java.util.logging).
level = WARNING
# Log file relative to the working directory.
logFile = logs/microservice.%g.log

The configuration is exposed as a Config object through Microservice.getConfig() and is also registered in the bean store so @Bean factory methods can inject it directly.

Hot-reload​

Config supports file-watch hot-reload out of the box. When the underlying juneau.cfg file changes on disk, listeners registered via Config.addListener(…) are notified with the full set of changed entries. The microservice uses this to propagate logging level changes and port-list updates without a restart.

You can register your own listener from a @Configuration class:

import org.apache.juneau.commons.inject.*;
import org.apache.juneau.config.event.*;
import org.apache.juneau.microservice.*;

@Configuration
public class AppConfig {

@Bean
MicroserviceListener configWatcher() {
return new BasicMicroserviceListener() {
@Override
public void onConfigChange(Microservice ms, ConfigEvents events) {
System.out.println("Config changed: " + events);
}
};
}
}

The onConfigChange(Microservice, ConfigEvents) callback fires on the calling thread of the file-store watcher, not the request thread, so keep it non-blocking. The ConfigEvents argument carries the full set of changed entries — see Listeners for reacting to specific sections.


Built-in Management Resources​

The Jetty and Tomcat launchers expose several built-in REST endpoints under the root path when management mixins are enabled. These are opt-in: add the appropriate mixin to your root @Rest resource.

EndpointMixin / featureDescription
GET /healthzHealth ProbesAggregated health/liveness check. Returns 200 OK or 503 Service Unavailable.
GET /readyzHealth ProbesReadiness probe, used by Kubernetes load-balancer pre-stop hooks.
GET /livezHealth ProbesLiveness probe for pod restart decisions.
GET /actuatorManagement SurfaceActuator-style endpoint listing all available management sub-paths.
GET /apiAuto-generated via Swagger / OpenAPISwagger 2.x JSON schema; OPTIONS on any resource returns an inline schema.
GET /statsExecution StatisticsPer-operation call counts, error rates, and latency percentiles.

The management surface is implemented via the standard Juneau mixin pack mechanism — there are no special microservice APIs. The same mixins work in a plain servlet container too.


Bean Store and Inject Bootstrap​

Microservice owns an internal WritableBeanStore populated from every @Configuration class registered on the builder. This makes it easy for companion modules — such as JettyConfiguration and TomcatConfiguration — to contribute lifecycle components and for user code to wire in application services without subclassing.

@Configuration
public class AppConfig {

@Bean
Servlet rootResources() { return new RootResources(); } // auto-mounted by JettyConfiguration

@Bean
MyService myService() { return new MyService(); } // available to other @Bean methods
}

public class App {
public static void main(String[] args) throws Exception {
Microservice.create()
.args(args)
.configurations(JettyConfiguration.class, AppConfig.class)
.build()
.start()
.startConsole()
.join();
}
}

JettyConfiguration walks the bean store at startup, finds every @Bean whose declared return type is Servlet and whose runtime class carries @Rest, and mounts it at the path declared in @Rest(path = "..."). TomcatConfiguration follows an identical contract.

See Inject-Aware Microservice for a complete reference on resolution priority, @PostConstruct / @PreDestroy callbacks, and external bean store integration.


Starter Projects​

Apache Juneau provides three minimal clone-and-go starter projects — one per deployment target — that demonstrate a HelloResource, content negotiation, a Swagger/OPTIONS page, @Path/@Query binding, a YAML config file, and a MockRestClient test. Each is a true-orphan branch of apache/juneau:

git clone -b microservice-jetty-starter --single-branch https://github.com/apache/juneau.git my-app
git clone -b microservice-springboot-starter --single-branch https://github.com/apache/juneau.git my-app
git clone -b microservice-tomcat-starter --single-branch https://github.com/apache/juneau.git my-app

See Starter Projects for run commands, layout, and Docker notes.


See Also​