Configuring Spring Boot Starter
How to wire the Axelix Spring Boot Starter into a Spring Boot application so Axelix Master can discover it, read its state, and act on it.
This page shows how to wire the Axelix Spring Boot Starter into a Spring Boot application so Axelix Master can discover it, read its state, and act on it — both from the UI and through Master's bundled MCP (Model Context Protocol) server, which exposes the same data to AI agents. Pick the starter module matching your Boot major version, expose the Axelix actuator endpoints (automatic as of Axelix 1.2.0), share the JWT signing key with Master, and tell Master where to find the instance.
Before you start
A few facts worth pinning down before you copy any of the snippets below.
- Three starter modules, one per Spring Boot major version. Pick the one that matches the Boot version your
application already uses:
com.axelixlabs:axelix-spring-boot-2-starter— Spring Boot 2.7+ (a hard floor, not just what we tested; built and tested against2.7.18, Spring Cloud2021.0.9, minimum JDK 11).com.axelixlabs:axelix-spring-boot-3-starter— Spring Boot 3.x (built and tested against3.0.13, Spring Cloud2022.0.4, minimum JDK 17).com.axelixlabs:axelix-spring-boot-4-starter— Spring Boot 4.x (built and tested against4.0.6, Spring Cloud2025.1.0, minimum JDK 17).
- What the starter contributes: a set of Axelix-specific actuator endpoints (
axelix-metadata,axelix-beans,axelix-loggers, …), a JWT-based authorization filter that gates them, and an optional self-registration component that announces this instance to Master. - The Axelix build plugin is required too: alongside the starter dependency, apply the Axelix Gradle or Maven build
plugin. It stamps your build coordinates (
groupId/artifactId/version) into the artifact, and Master identifies every application by those coordinates — an instance built without the plugin cannot register. See What is the Axelix build plugin? and Configuring the build plugin. - Two consumers of the same data: Master serves the Axelix UI at
/and an MCP server at/api/mcp(controlled byaxelix.master.mcp-server.enabled, on by default). Both read from the actuator endpoints the starter exposes, so wiring the starter up makes the instance visible to UI users and to MCP clients with no extra configuration on the starter side. - What Master needs to talk to the instance: HTTP reachability to the application's actuator base path (default
/actuator), the Axelix endpoints exposed throughmanagement.endpoints.web.exposure.include, and a JWT signing key identical to the one configured on Master — see Authentication — JWT for the master side. - Two ways Master finds the instance:
- Master-side autodiscovery — Master scans its environment (currently Kubernetes Services) and probes the actuator endpoint itself. The starter only needs to expose the endpoints; nothing additional to configure.
- Self-registration — the starter posts a heartbeat to Master on a fixed interval. Use this when Master cannot scan the instance's environment (different network, no platform integration, plain VMs).
Reactive (WebFlux) applications
Starting with Axelix 1.3.0, all three starters work in reactive applications built on Spring WebFlux, not only in
servlet (Spring MVC) applications. The starter detects which web stack your application runs on, so there is nothing
extra to add or configure: the dependency, the build plugin, and the properties on this page are the same for both.
The Axelix endpoints and the JWT authorization in front of them work the same way, including when Actuator runs on a
separate management.server.port.
One feature stays servlet-only. Transaction monitoring, and with it the Transaction Control and Entities Map pages, is not available in WebFlux applications.
Add the dependency
Declare the starter coordinate matching your Boot major version.
The snippets below use the latest release, 1.2.2.
dependencies {
implementation("com.axelixlabs:axelix-spring-boot-4-starter:1.2.2")
}The starter also depends on Spring Boot
Actuator if your application doesn't
already include spring-boot-starter-actuator, add it alongside.
The build plugin is a separate step
Applying the Axelix build plugin is required for every managed service, but it lives in its own section — see What is the Axelix build plugin? and Configuring the build plugin.
Transitive dependencies
The starter is built to add as little as possible to your classpath. Everything it integrates with — Spring Boot, Actuator, Spring Kafka, Micrometer, Caffeine, Jackson — is compiled against but not brought in: the starter uses whatever your application already has. The only libraries it brings in transitively are:
| Dependency | Why it is there |
|---|---|
org.slf4j:slf4j-api | Logging. Already present in every Spring Boot application. |
io.jsonwebtoken:jjwt-api, jjwt-impl, jjwt-jackson | Verifying the JWT that Master sends with every request. |
This list is meant to shrink. The starter is the one Axelix component that runs inside your services, and every library it brings in is one more thing on your classpath to scan, patch, and keep compatible with the rest of your application. The Axelix core team's position is that the starter should have no external dependencies at all, and we are removing the remaining ones step by step — follow axelixlabs/axelix#1748 for the progress.
JsonPath is no longer included
Up to and including Axelix 1.1.x, the starter also brought in com.jayway.jsonpath:json-path, although it never used
it. Starting with Axelix 1.2.0, that dependency is removed — the first step towards the dependency-free starter
described in axelixlabs/axelix#1748.
If your application uses JsonPath in its own code and has been getting it only through the Axelix starter, declare it explicitly when you upgrade. The version is managed by Spring Boot, so you do not need to specify one:
dependencies {
implementation("com.jayway.jsonpath:json-path")
}Tests are not affected: spring-boot-starter-test brings in JsonPath on its own.
JSpecify is no longer included
Up to and including Axelix 1.2.x, the starter also brought in org.jspecify:jspecify. The starter uses JSpecify only
for its nullness annotations, and it needs them only at compile time. Starting with Axelix 1.3.0, the dependency is
removed, as the next step towards the dependency-free starter described in
axelixlabs/axelix#1748.
The starter keeps working without JSpecify on the classpath, because the JVM ignores annotations whose classes are missing at runtime. On Spring Boot 4 nothing changes at all, since Spring Framework 7 depends on JSpecify itself.
If your own code uses the JSpecify annotations and has been getting them only through the Axelix starter, declare the dependency explicitly when you upgrade. Spring Boot 2 and 3 do not manage its version, so specify it:
dependencies {
implementation("org.jspecify:jspecify:1.0.0")
}Actuator endpoints
Starting with Axelix 1.2.0 there is nothing to configure by hand: on application startup the starter adds its own
actuator endpoints to management.endpoints.web.exposure.include, so Master can reach them out of the box. On older
versions the starter does not do this, and the endpoints must be listed manually — see Exposing the endpoints on
Axelix below 1.2.0.
What the starter exposes
The starter exposes the following endpoints:
| Endpoint | Purpose | Since |
|---|---|---|
axelix-metadata required | Service metadata; the one Master probes first | 1.0.0 |
axelix-ping | Health, memory, and transaction data Master polls for instances it already knows | 1.3.0 upcoming |
axelix-details | Summary information about the instance | 1.0.0 |
axelix-beans | Context beans | 1.0.0 |
axelix-caches | Caches (when a CacheManager is present) | 1.0.0 |
axelix-conditions | Auto-configuration conditions report | 1.0.0 |
axelix-configprops | @ConfigurationProperties | 1.0.0 |
axelix-env | Environment and property sources | 1.0.0 |
axelix-feign legacy | Feign clients (when Feign is on the classpath). Removed in 1.3.0, see below | 1.0.0 |
axelix-gc | Garbage collection | 1.0.0 |
axelix-heap-dump | Heap dump | 1.0.0 |
axelix-loggers | Logging levels | 1.0.0 |
axelix-logs | Recent log entries | 1.3.0 upcoming |
axelix-metrics | Metrics | 1.0.0 |
axelix-scheduled-tasks | Scheduled tasks | 1.0.0 |
axelix-thread-dump | Thread dump | 1.0.0 |
axelix-dependencies | Dependency SBOM | 1.2.0 |
The Since column names the Axelix starter release an endpoint first shipped in. 1.0.0 is the first Axelix release,
so an endpoint marked 1.0.0 has been there from the very beginning. A version marked upcoming is not released yet:
the endpoint will become available in the next Axelix release, whether that is a minor or a major one.
Endpoints that don't apply to your application stay inert — the starter activates each one only when its prerequisites
are met (for example, axelix-caches without a CacheManager never comes up).
As of Axelix 1.2.0 the native health and info endpoints are no longer required, so the starter never exposes
them on its own (before 1.2.0 Axelix depended on them, and the starter force-exposed both). Only the endpoints you
list in management.endpoints.web.exposure.include plus the Axelix ones are exposed — add health and info to the
list yourself when you need them, including the health endpoint that Spring Boot would otherwise expose by default.
The axelix-feign endpoint is removed
Up to and including Axelix 1.2.x, the Spring Boot 3 and Spring Boot 4 starters also contributed an axelix-feign
endpoint that listed the Spring Cloud OpenFeign clients of the application. Axelix Master has never used it to
render anything, and it stayed around only as a leftover from the early days of the project. Starting with Axelix 1.3.0 the endpoint is removed from the starters, together with everything in Master
that was able to call it.
There is nothing to do when you upgrade. The only visible difference is that /actuator/axelix-feign no longer
exists on a service running starter 1.3.0 or newer, so if your own tooling calls that URL directly, it will get a
404. If you list the Axelix endpoints in management.endpoints.web.exposure.include by hand and axelix-feign is
among them, you can drop it from the list — leaving it there is harmless.
Adding your own endpoints
If you need your own actuator endpoints, just list only them — the starter merges your list with its own instead of replacing it.
management:
endpoints:
web:
exposure:
include:
- prometheusThe result is that prometheus and all the Axelix endpoints are exposed.
The * value is supported too — everything gets exposed and the starter leaves the list alone.
Exposing the endpoints on Axelix below 1.2.0
Starters older than 1.2.0 do not add their endpoints to the exposure list themselves, so every Axelix endpoint you
want Master to read has to be listed in management.endpoints.web.exposure.include by hand. At minimum expose
axelix-metadata — without it the instance never appears in Master — and in practice the whole set, so every UI
section has data to show. The health and info endpoints are force-exposed by those starter versions on their own,
so you do not need to list them:
management:
endpoints:
web:
exposure:
include:
- axelix-metadata
- axelix-beans
- axelix-caches
- axelix-conditions
- axelix-configprops
- axelix-details
- axelix-env
- axelix-gc
- axelix-heap-dump
- axelix-loggers
- axelix-metrics
- axelix-scheduled-tasks
- axelix-thread-dumpThese starter versions also contribute the legacy axelix-feign endpoint. It is left out of the list on purpose:
Master never reads it, and the endpoint is removed in Axelix 1.3.0 — see above.
Export Axelix metrics through Micrometer
The axelix-metrics actuator endpoint powers the Axelix UI. In addition, the Spring Boot starters can publish a small
set of Axelix-specific meters into your application's own Micrometer MeterRegistry.
This export path switches on automatically when a MeterRegistry bean is present. There is no extra Axelix property for
it. The starter registers these meters:
| Meter | Type | Tags | Meaning |
|---|---|---|---|
axelix_transaction_duration | Timer | class, method | Duration of each monitored @Transactional execution. The timer also publishes 0.5, 0.95, and 0.99 percentiles. |
axelix_transaction_queries | Counter | class, method | Total number of SQL queries executed inside monitored transactions. |
axelix_transaction_external_calls | Counter | class, method | Total number of external calls (e.g. RestTemplate) made inside monitored transactions. |
axelix_cache_requests | Counter | cache, result | Total number of cache lookups recorded by Axelix-enhanced caches. |
axelix_cache_enabled | Gauge | cache | Current runtime state of each enhanced cache: 1 when enabled, 0 when disabled. |
These meters complement the UI-facing actuator endpoints rather than replace them. The UI still reads
axelix-metrics and axelix-caches. Transaction monitoring data is not served by a dedicated actuator endpoint —
it travels to Master as part of the instance's registration metadata exposed through axelix-metadata (see
Transaction monitoring).
Share the JWT signing key with Master
Every Axelix actuator endpoint is gated by JwtAuthorizationFilter. The filter expects an HS256, HS384, or HS512 token
signed with the same key Master uses, so the two sides must agree on the algorithm and the secret. Use the same value
you set for axelix.master.auth.jwt.signing-key on Master.
axelix:
sbs:
auth:
jwt:
algorithm: HMAC512
signing-key: ${AXELIX_JWT_SIGNING_KEY}
duration: 5mduration controls how long the starter-issued token used for self-registration heartbeats is valid, the default is five minutes,
after which the starter rotates it automatically.
A signing key shared between Master and every monitored service is a sensitive secret. Inject it through an environment variable, mounted file, or secret manager — not a checked-in YAML.
Running without a signing key
Starting with Axelix 1.2.0, algorithm and signing-key are optional. When they are not set, the starter uses
HMAC512 and the same built-in key that Master uses by default, so the service connects to a Master with default
settings without any key setup. While the built-in key is in use, the starter logs a warning at startup.
The built-in key is publicly known. Anyone who can reach the service's actuator endpoints can sign a token with it and
call the Axelix endpoints, for example to read the environment or take a heap dump. Set your own
axelix.sbs.auth.jwt.signing-key, the same as on Master, before using Axelix beyond a local trial.
Let Master find the instance
Pick one of the two paths below. They are mutually exclusive in practice — self-registration only adds latency if Master can already scan the environment.
Option A — Master-side autodiscovery
When Master runs inside a Kubernetes cluster alongside your services, the simplest setup is to let Master scan the
namespace for Services and probe each one's /actuator/axelix-metadata. No further configuration is needed on the
starter side beyond exposing the actuator endpoints and sharing the JWT signing key. Configure the master-side scan with
axelix.master.discovery.auto.* — see Discovery —
auto-discovery on the Master page.
For what Master does on each scan, see How discovery works.
Option B — Self-registration
When Master cannot scan the instance's environment — a different cluster, a plain VM, an isolated network — switch on
self-registration in the starter. The instance then posts a heartbeat carrying its actuator URL to Master on a fixed
interval. Master accepts the post at POST /api/internal/service/register, which is also where you point
axelix.sbs.discovery.master-url. Starting with Axelix 1.3.0, the starter sends this full registration only once and
then switches to lightweight heartbeats, which go to an endpoint next to master-url. For the whole cycle, see How
discovery works.
axelix:
sbs:
discovery:
self-registration: true
master-url: http://master.internal:2935/api/internal/service/register
instance-actuator-url: http://my-app.internal:8080/actuator
instance-name: orders-service
heartbeat-interval: 15sA few details that catch people out:
instance-actuator-urlis the base URL of the service as Master will reach it from its own network — host and port only.master-urlis the full URL including/api/internal/service/register. The starter posts to it verbatim. Master listens on2935by default since Axelix1.2.0; before that release the default port was8080— see General.instance-nameis the label Master shows for this instance in the UI and in MCP responses. Pick a name that survives restarts and replicas — typically the service name, not the pod name.- Self-registration is accepted by Master out of the box (
axelix.master.discovery.self-registration.enabledistrueby default), set it tofalseif you want to refuse heartbeats. Master evicts an instance afteraxelix.master.discovery.self-registration.eviction.heartbeat-timeoutof silence (45sby default), so keepheartbeat-intervalcomfortably under that.
Sanitize sensitive property values
The Axelix axelix-env and axelix-configprops endpoints return property values to Master. To keep secrets out of
casual reads, the starter masks values it returns to callers that lack the right authority. The mechanism is the same
for both endpoints, controlled by a single starter property:
axelix.sbs.endpoints.config.sanitized-properties
- Empty list (default) — every value returned by
axelix-envandaxelix-configpropsis replaced with******for callers without the relevant authority. The default is intentionally conservative: no opt-in needed to be safe. - Non-empty list — only the listed keys are masked; everything else is returned raw to any caller. Use this when the conservative default is too aggressive and you want to mask only specific keys (passwords, tokens, signing keys).
Authority is checked per-endpoint:
axelix-env— theENV_VALUES_READauthority lets the caller see raw values.axelix-configprops— theCONFIG_PROPS_VALUES_READauthority lets the caller see raw values.
Both authorities are granted by Master's built-in ADMIN and SUPER_ADMIN roles. VIEWER and EDITOR always go through the sanitization function. See Roles and authorities for the full matrix.
axelix:
sbs:
endpoints:
config:
sanitized-properties:
- database.password
- spring.datasource.password
- jwt.signing-keyThe standard Spring Boot Actuator masking switches — management.endpoint.env.show-values,
management.endpoint.env.keys-to-sanitize, and their configprops equivalents — are not consulted.
Configuration reference
Every starter property lives under the axelix.sbs.* namespace.
Disabling the starter
axelix.sbs.enabled is the global switch for the whole starter. It is true by default, so adding the dependency is
enough to activate everything described on this page. Set it to false and every Axelix auto-configuration backs off:
no Axelix actuator endpoints, no JWT authorization filter, no self-registration heartbeats, no Micrometer meters, and
no transaction monitoring. The application then starts as if the starter were not on the classpath, while the
dependency itself stays in the build.
Reach for this switch when you want Axelix off in a specific environment — for example locally or in a test profile — without maintaining a separate dependency set. It is also a quick way to rule the starter out while troubleshooting startup issues.
axelix:
sbs:
enabled: falseThe property is read once, during startup. As a result, changing it requires a restart of the application.
With the starter disabled, Master loses sight of the instance: autodiscovery probes to /actuator/axelix-metadata
fail, and self-registration heartbeats stop, so the instance disappears from the UI and from MCP responses.
| Property | Default | Description |
|---|---|---|
axelix.sbs.enabled | true | Global switch for the whole starter. Set to false to make every Axelix auto-configuration back off. Behaves identically on the Spring Boot 2, 3, and 4 starters. |
Authentication — JWT
| Property | Default | Description |
|---|---|---|
axelix.sbs.auth.jwt.algorithm | HMAC512 (1.2.0+; required before) | Signing algorithm. One of HMAC256, HMAC384, or HMAC512. Must match Master's axelix.master.auth.jwt.algorithm. |
axelix.sbs.auth.jwt.signing-key | built-in key (1.2.0+; required before) | Shared secret used to verify Master-issued tokens and to sign self-registration heartbeats. Must match Master's signing key. |
axelix.sbs.auth.jwt.duration | 5m | Validity of the self-registration token the starter issues itself. Tokens are rotated automatically before expiry. |
Self-registration
Self-registration is off by default (axelix.sbs.discovery.self-registration=false) — leave it that way when Master can find the
instance through Master-side autodiscovery instead.
When axelix.sbs.discovery.self-registration=true, the following properties become required:
axelix.sbs.discovery.master-urlaxelix.sbs.discovery.instance-actuator-urlaxelix.sbs.discovery.instance-name
The Master-side receiver of these heartbeats — endpoint, eviction timeout, eviction sweep schedule — is documented on
the Master page in Discovery —
self-registration. The JWT signing key
configured under axelix.sbs.auth.jwt.signing-key must match axelix.master.auth.jwt.signing-key on Master, otherwise
heartbeats are rejected with 401.
| Property | Default | Description |
|---|---|---|
axelix.sbs.discovery.self-registration | false | Master switch. Set to true to enable self-registration; leave false to rely on Master-side autodiscovery. |
axelix.sbs.discovery.master-url | (unset) required | Full URL of Master's self-registration endpoint, e.g. http://master:2935/api/internal/service/register. Required when self-registration=true. |
axelix.sbs.discovery.instance-actuator-url | (unset) required | Base URL of this service as reachable from Master (It is necessary to specify the postfix /actuator). Required when self-registration=true. |
axelix.sbs.discovery.instance-name | (unset) required | Display name shown in Axelix UI and MCP responses. Required when self-registration=true. |
axelix.sbs.discovery.heartbeat-interval | 15s | Interval between heartbeats. Should be smaller than Master's eviction heartbeat-timeout. |
Endpoint value sanitization
| Property | Default | Description |
|---|---|---|
axelix.sbs.endpoints.config.sanitized-properties | (empty list) | Property keys whose values are masked as ****** for callers without ENV_VALUES_READ (for axelix-env) or CONFIG_PROPS_VALUES_READ (for axelix-configprops). Empty list means all values are masked. See Sanitize sensitive property values for the matching rules. |
Cache management
Cache management is what powers the Caches page and the axelix_cache_* meters: the starter wraps every CacheManager
bean of your application in a proxy that records cache lookups and lets you enable, disable, and clear caches at
runtime, and it exposes that data through the axelix-caches actuator endpoint. It is on by default once the
starter is on the classpath.
Set axelix.sbs.cache.management.enabled to false to turn it off entirely — no CacheManager proxying, no
axelix-caches endpoint, and no cache meters. Your CacheManager beans are then left exactly as your application
defined them.
axelix:
sbs:
cache:
management:
enabled: false| Property | Default | Description |
|---|---|---|
axelix.sbs.cache.management.enabled | true | Master switch for cache management. Set to false to make the whole cache management auto-configuration back off. Behaves identically on the Spring Boot 2, 3, and 4 starters. |
With cache management disabled, the Caches page in Master has no data to show for this instance, and the cache MCP tools fail for it.
Log entries
The axelix-logs endpoint serves the most recent log entries of your application, so you can read them without
access to the host. The starter keeps these entries in memory, starting from application startup. When the buffer is
full, each new entry pushes out the oldest one. Because the buffer lives in memory, it is empty again after a restart.
By default, the starter keeps the last 1000 entries. Raise axelix.sbs.logs.max-entries when a busy service logs
so much that 1000 entries cover only a few seconds. Lower it when memory is tight, because every kept entry stays on
the heap.
axelix:
sbs:
logs:
max-entries: 5000| Property | Default | Description |
|---|---|---|
axelix.sbs.logs.max-entries | 1000 | Maximum number of the most recent log entries the starter keeps in memory. Must be greater than 0. |
The starter checks the value once the application has started. If it is 0 or negative, startup fails with an
IllegalArgumentException saying axelix.sbs.logs.max-entries must be positive.
Transaction monitoring
Transaction monitoring is what powers the Transaction Control page and the related meters: it wraps your
@Transactional methods, proxies the data source to count queries, cleans up the per-request transaction stack, and
registers the Hibernate N+1 integrator. The collected insights travel to Master inside the instance's registration
metadata (exposed through axelix-metadata), so there is no separate actuator endpoint to expose. It is on by
default once the starter is on the classpath.
Transaction monitoring works only in servlet (Spring MVC) applications. In a reactive (WebFlux) application the starter doesn't turn it on, whatever the property says. See Reactive (WebFlux) applications.
Set axelix.sbs.transaction.monitoring.enabled to false to turn it off entirely — no bean post-processors, no data
source proxying, no cleanup filter, and no Hibernate integrator. Use this to shave the associated overhead, to rule out
interference while troubleshooting your data source / Hibernate setup, or simply when you don't use the feature.
axelix:
sbs:
transaction:
monitoring:
enabled: false| Property | Default | Description |
|---|---|---|
axelix.sbs.transaction.monitoring.enabled | true | Master switch for transaction monitoring. Set to false to make the whole transaction monitoring auto-configuration back off. Behaves identically on the Spring Boot 2, 3, and 4 starters. |
Disabling transaction monitoring also disables in-memory pagination detection described below, since that detection is part of the same auto-configuration.
In-memory pagination detection
Detects Hibernate`s in-memory pagination caused by using setFirstResult/setMaxResults together with a collection fetch.
By default, transaction monitoring registers an appender that intercepts Hibernate warnings (HHH000104 in Hibernate 5.x and HHH90003004 in Hibernate 6.x–7.3.x). The starter picks the appender that matches your application's active logging system, so detection works whether you run on Logback or Log4j2:
- Logback — the starter registers
com.axelixlabs.axelix.sbs.spring.core.persistence.hibernate.pagination.LogbackInMemoryPaginationAppender. This is the case for a default Spring Boot setup, where Logback is the logging system. - Log4j2 — when your application uses Log4j2 instead (typically after adding
spring-boot-starter-log4j2and excluding the default Logback starter), the starter registerscom.axelixlabs.axelix.sbs.spring.core.persistence.hibernate.pagination.Log4j2InMemoryPaginationAppender.
You don't choose between them — the starter detects the active logging system and registers the right appender for you.
Set axelix.sbs.transaction.monitoring.in-memory-pagination-detection.enabled to false if you want to prevent either
appender from being registered.
axelix:
sbs:
transaction:
monitoring:
in-memory-pagination-detection:
enabled: falseRelated
- Configuring the build plugin — the second half of wiring a service up; required for the instance to register.
- Configuring Master — where the signing key, eviction timeout, and Kubernetes scan are set.
- What is Master? — background on how Master uses the data the starter exposes.
- Authentication — deeper look at JWT and authority resolution on both sides.