juneau-rest-server-springboot
| Maven | |
|---|---|
| Jar | juneau-rest-server-springboot-10.0.0.jar |
| OSGi | org.apache.juneau.rest.server.springboot_10.0.0.jar |
| Links | Maven Central · Javadocs · Source |
Contents/Features
The juneau-rest-server-springboot library provides classes to make it easy to integrate Juneau REST resources with
Spring and Spring Boot.
See the guide: Build a REST API on Spring Boot
Auto-Configuration Classes
The module registers two Spring Boot auto-configuration classes through
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports (the Spring Boot 3
mechanism; the module ships no spring.factories and no @ConfigurationProperties classes):
| Class | Gate | Contributes |
|---|---|---|
| JuneauRestAutoConfiguration | juneau.rest.auto-register=true (off when the property is absent) | A ServletContextInitializer bean, juneauRestAutoRegistrar, that mounts every RestServlet bean at its self-declared top-level path. |
| JuneauRestLoggingAutoConfiguration | Logback's LevelChangePropagator on the classpath, and juneau.rest.logging.propagate-levels not set to false | A Runnable bean, juneauRestLogLevelPropagatorInstaller (replaceable by declaring a bean of that name), plus a SmartInitializingSingleton that runs it. |
Explicit ServletRegistrationBean registrations always win over auto-registration, and the
JuneauServletRegistrations.forServlet(servlet, beanStore) factory is the explicit alternative. See
REST Server - Self-Registration.
Configuration Properties
All properties are read from the Spring Environment (application.properties, application.yaml,
environment variables, command line). The module defines only the following:
| Property | Type | Default | Effect |
|---|---|---|---|
juneau.rest.auto-register | boolean | absent (disabled) | When true, activates JuneauRestAutoConfiguration. |
juneau.rest.logging.propagate-levels | boolean | true (matchIfMissing) | When false, JuneauRestLoggingAutoConfiguration contributes nothing. |
juneau.rest.logging.propagate-levels.reset-jul | boolean | false | Passed to Logback's propagator as setResetJUL; see the reset-jul section below. |
juneau.profiles.active | comma-delimited string | Spring's active profiles | Not an auto-configuration property. SpringEnvironmentPropertySource answers it from Environment.getActiveProfiles() unless the property is set explicitly, in which case the explicit value wins. |
juneau.spring.missCache.disable | boolean | false | Not an auto-configuration property. When true, SpringEnvironmentPropertySource keeps no miss cache and walks Spring's property sources on every lookup. Read once, on the bridge's first lookup, from the Spring Environment itself (so application.properties, @TestPropertySource, command line, the exact system property, or JUNEAU_SPRING_MISSCACHE_DISABLE); later changes are ignored. |
# application.properties
juneau.rest.auto-register=true
juneau.rest.logging.propagate-levels=true
juneau.rest.logging.propagate-levels.reset-jul=false
Bean Precedence
When a Juneau REST resource runs inside a Spring Boot application, framework-managed beans on RestContext
(RestDebugFormatter, EncoderSet, SerializerSet, ParserSet, ThrownStore, Config, VarResolver,
HttpPartSerializer, HttpPartParser, etc.) are resolved through the resource's SpringBeanStore in the
following order — the first match wins:
- Local entries — beans registered directly on the resource's own bean store, most commonly a
@Beanmethod/field on the@Rest-annotated resource class (org.apache.juneau.commons.inject.Bean), or anything added programmatically viaaddBean(...)/addSupplier(...). - Regular parent bean store, if any — the store passed as the
parentconstructor argument when theSpringBeanStorewas created (SpringBeanStore(ApplicationContext, BeanStore)). - Memoizer-backed framework default — Juneau's built-in implementation (
BasicRestDebugFormatter,BasicEncoderSet, etc.), registered viaaddDefaultSupplier(...). - Spring
@Bean— reached only if none of the above resolved the type (and name, where applicable), via the SpringApplicationContext.
This is a fallback relationship, not an override: SpringBeanStore extends BasicBeanStore, and its
overridden getBean() / getBeanSupplier() / hasBean() / getBeansOfType() methods each call
super.getBean(...) (which resolves tiers 1–3 above) first, and only query Spring's
ApplicationContext.getBeanProvider(...) / getBean(...) when that returns empty. Concretely, a @Bean
method declared directly on the resource class always wins over an identically-typed Spring bean — this
is confirmed directly by SpringBeanStore_Test.c05_getBean_localOverridesSpring, which registers a local
bean, stubs an identically-typed bean on a mocked ApplicationContext, asserts that the local bean is
returned, and asserts verifyNoInteractions(mockAppContext) — proving Spring is never even queried once the
local lookup succeeds.
Practical implications:
- To let a Spring bean take effect, don't declare a competing
@Beanmethod/field of the same type (and name) on the resource class — a local declaration always shadows the Spring bean, regardless of any@Primary/@ConditionalOn...annotations on the Spring side. - To force your resource-class
@Beanto win, no action is needed — this is the default behavior. - Spring-native qualifiers still matter, but only among Spring candidates.
@Primary,@Qualifier, and@ConditionalOn...control which Spring beanSpringBeanStoresees when it falls back to Spring (step 4) — they have no effect if a local entry, parent-store entry, or framework default already satisfied the lookup.
BasicBeanStore separately supports a real overriding-parent slot — a store consulted before local
entries — via the BasicBeanStore(BeanStore parent, BeanStore overridingParent) constructor or, for
builder-style consumers, the BeanStoreOverridable<B>.overridingBeanStore(BeanStore) interface (implemented
by builders such as SerializerSet.Builder, ParserSet.Builder, EncoderSet.Builder, and
MockRestClient.Builder — mainly for test-time bean substitution). SpringRestServlet.createBeanStore(...)
does not use this slot for the Spring bridge: it always constructs new SpringBeanStore(appContext, parent) with parent as the regular (non-overriding) parent, so Spring is layered in only as the
last-resort fallback described above, never as a true override.
Property Resolution
Installing SpringBeanStore also bridges the Spring Environment into Juneau's Settings singleton
(via SpringEnvironmentPropertySource), so @Value("${...}") placeholders on your beans resolve against
the same property space Spring uses — application.yaml / application.properties, environment variables,
command-line arguments, and any custom Spring PropertySource. Spring's active profiles are also surfaced
to Juneau's juneau.profiles.active config-profile key. See the cross-links below for details.
There is one bridge per ApplicationContext, however many Spring REST servlets share the context. It is added when
the first SpringBeanStore for the context is built, keeps that position in the Settings chain, and is removed when
the context closes (any ConfigurableApplicationContext) or when every SpringBeanStore on it has been clear()ed.
A Settings source added between two servlets' construction therefore wins over the bridge for keys both define.
Juneau's own builder keys (MarshallingContext.unsortedProperties, Serializer.*, ...) are mixed-case, so Spring
Boot cannot parse them as configuration property names and walks every raw property source for each lookup. The
bridge remembers up to 4,096 such keys that were absent. It checks the Environment's property-source list on every
lookup, so adding, removing or replacing a PropertySource is seen at once, and a cached key that is later set as a
system property is found. Valid Spring Boot names (lowercase and dot-separated, such as my.app.key) and hits are
never cached.
The one change the cache does not see is a property source whose contents change in place (a mutated
MapPropertySource map, or MockEnvironment.setProperty in a test), for a mixed-case key that Juneau already looked
up and missed. After such a change, call SpringBeanStore.invalidateEnvironmentCache(applicationContext),
or set juneau.spring.missCache.disable=true.
Logback level propagation to JUL
When Logback is the active backend, juneau-rest-server-springboot auto-installs a JUL LevelChangePropagator
listener by default (juneau.rest.logging.propagate-levels=true, matchIfMissing=true) so logging.level.*
changes are reflected into JUL-backed REST debug detail controls.
- Installation is guarded at runtime:
- if Logback classes are absent, no install is attempted;
- if
ILoggerFactoryis not a LogbackLoggerContext, it silently no-ops.
- Disable propagation with
juneau.rest.logging.propagate-levels=false. - The installer is additive and idempotent (it reuses any existing
LevelChangePropagatorsubtype, and installs at most one reset-resistant listener).
reset-jul posture
juneau.rest.logging.propagate-levels.reset-jul defaults to false (recommended).
false(default): pre-existing JUL logger levels/handlers are preserved.true: process-global reset/reapply behavior from Logback's propagator is enabled.
When reset-jul=true, be explicit about the side effects:
- non-root explicit JUL logger levels are cleared;
- explicit Logback levels are then propagated back into JUL;
- JUL-only
logging.propertiesentries not mirrored by explicit Logback levels do not survive.
For operator-controlled durability across explicit Logback resets, you can also install a Logback XML
<contextListener> directly.
See also
- Build a REST API on Spring Boot: a guided walkthrough.
- Spring Boot Overview — base classes and a worked sample application.
- REST Server — Self-Registration — opt-in auto-configuration (
juneau.rest.auto-register=true) and theJuneauServletRegistrations.forServlet(...)factory helper for mounting servlets under Spring Boot. - @Value Annotation Basics —
@Value("${...}")resolution against the SpringEnvironment. - Config Profiles and Relaxed Binding — how
juneau.profiles.activepiggybacks on Spring's active profiles. - Juneau Commons Settings — the
Settingssingleton and theSpringEnvironmentPropertySourceproperty source.