Spring Boot 3.4 was released on the 21st of November 2024, and once again it contains a lot of useful enhancements.
Once again, there’s a large focus on observability, which helps us ensure our quality and get to Josh Long’s favourite place (production). Furthermore, the Testcontainer integration has been improved, enhancing our testing capacity and fully running our applications. We also get more granular control, thus increasing the security of our applications.
We also see some upgrades, I recommend especially paying attention to the bean validation and buildpack changes.
Table of Contents
Enhancements: Spring Boot 3.4
As always, we get some useful new features to enhance our applications with.
Virtual threads
Spring and its ecosystem are further embracing Virtual Threads.
Both OtlpMeterRegistry,
and the Undertow
web server now make use of Virtual threads if they’re enabled.
Observability Improvements
Beyond the structured logging enhancements we discussed in our previous blog which added out-of-the-box support for ECS and Logstash, there are further improvements.
Graylog Extended Log Format (GELF) is now also supported by structured logging.
And the ProcessInfoContributor
now also provides us with information about heap and non-heap usage.
{ "version": "1.1", "host": "digma.org", "short_message": "A short observability message", "full_message": "A longer\n\nmultiline message", "timestamp": 1385053862.3072, "level": 1, "_user_id": 9001, "_some_info": "digmaInfo", "_some_env_var": "digmaProd" }
OTLP spans can now be sent over gRPC by updating the management.otlp.tracing.transport
(with http as default) to grpc,
and service connection support for this has been added as well.
OTLP logging now also has support for Docker Compose and Testcontainers.
Application grouping
The new property spring.application.group
allows us to group related (business unit, part of) together. This property, if configured will be included in our logging (which can be adapted by changing logging.include-application.group)
. Furthermore, it’ll also be automatically added to our OpenTelemetry Resource.
AssertJ Support for MockMvc
When AssertJ
is on the classpath we now get autoconfiguration for MockMvcTester
. This MockMvc
alternative allows us to define our requests and assertions using a Fluent API. More details can be found in the Spring Boot – MockMvc – AssertJ documentation.
New properties
Three properties have been added to manage trace exporting in a more fine-grained manner for the respective systems:
- management.otlp.tracing.export.enabled
- management.wavefront.tracing.export.enabled
- management.zipkin.tracing.export.enabled
And we can now also autoconfigure OpenTelemetry’s OtlpHttpLogRecordExporter
and SdkLoggerProvider.
Embedded broker support for ActiveMQ classic
Since ActiveMQ classic once again supports an embedded broker, the autoconfiguration has been updated to support it. Do keep in mind that the starter is client only, so you’ll need to add org.apache.activemq:activemq-broker
to use the embedded broker.
Apache pulsar
We can now further manage Apache Pulsar.
The autoconfigured PulsarContainerFactory can be customized by implementing the new PulsarContainerFactoryCustomizer interface.
The autoconfigured Pulsar listener container name is now managed by spring.pulsar.consumer.subscription.name.
Three new configuration properties have also been added:
spring.pulsar.client.threads.io
controls the number of threads used for handling connections to brokersspring.pulsar.client.threads.listener
controls the number of threads used for message listenersspring.pulsar.listener.concurrency
controls the concurrency of the autoconfigured Pulsar message listener container
Image building improvements
When building Open Container Initiative (OCI) images we can now make use of the trustBuilder
option with the respective Maven and Gradle plugins. This option allows us to control how the Cloud Native Buildpacks (CNB) lifecycle is invoked which provides us with enhanced security when using builders from untrusted sources. By default, only builders from the Paketo project, Heroku, and Google are trusted.
Docker compose enhancements
We can now pass in additional command line arguments to Docker Compose when starting and stopping services by making use of the new properties spring.docker.compose.start.arguments and spring.docker.compose.stop.arguments.
Furthermore, the POSTGRES_HOST_AUTH_METHOD=trust environment variable is now supported.
Testcontainer improvements
Testcontainer support keeps improving in Spring, this release adds:
- Redis Stack (Server) support through the
redis/redis-stack(-server)
image org.testcontainers.kafka.KafkaContainer
support
Connection details
A HazelCast implementation has been added. ConnectionDetails were added in Spring Boot 3.1 and models the connection to a remote service.
Autoconfiguration management
Support for deprecating and replacing autoconfiguration classes has been added by declaring them in the new META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.replacements
file. It will define the link between the old and new class. You can find more details in the reference documentation.
Fallback beans
We can now define a @Fallback
bean for @ConditionalOnSingleCandidate
. It will be matched if there’s a single primary beans, or in case of no primary beans if there’s a single non-fallback bean.
Upgrading
There are certain things we will need to keep in mind when we’re upgrading our application, some noteworthy ones are:
Bean validation
An important change to keep in mind if you’re using @Validated @ConfigurationProperties
is that as of this releas, the Bean Validation specification is properly followed. Whereas before this release, validation of nested properties happened as they were bound, now the validation only cascades down as expected when the field is annotated with @Valid.
Bean-based conditions
When a @Bean
method is annotated with @ConditionalOnBean
or @ConditionalOnMissingBean
where the annotation attribute has been set, it will now behave consistently as when the name, type,
or value
has been set. Before 3.4 it used the return type of the method as the default type to match. To restore the old behaviour you will need to set a value
that is the return type of the`@Bean` method and annotation.
RestClient and RestTemplate
Autoconfiguration support Reactor Netty’s HttpClient
and JDK`s HttpClient
have been added for RestClient
and RestTemplate
.
The following order of precedence is applied for the supported clients:
- Apache HTTP Components (HttpComponentsClientHttpRequestFactory)
- Jetty Client (JettyClientHttpRequestFactory)
- Reactor Netty HttpClient (ReactorClientHttpRequestFactory)
- JDK HttpClient (JdkClientHttpRequestFactory)
- Simple JDK HttpURLConnection (SimpleClientHttpRequestFactory)
In case you want to select a particular one, then you can set spring.http.client.factory
to one of the following: http-components, jetty, reactor, jdk or simple.
And these all follow redirects by default, which can be changed by setting spring.http.client.redirects
to dont-follow.
DynamicPropertyRegistry deprecation
Dynamic property injection by using DynamicPropertyRegistry
has been deprecated, and will now fail by default. Instead, we should implement a @Bean method that returns a DynamicPropertyRegistrar to inject the container from which the properties should be sourced. This resolve some container lifecycle issues, and ascertains that the source containers have started before the property is used.
@Bean DynamicPropertyRegistrar apiPropertiesRegistrar(SomeSource someSource) { return registry -> registry.add("someSource.someProperty", someSource::getSomeProperty); }
If we wish to keep the legacy behaviour we can set spring.testcontainers.dynamic-property-registry-injection
to either warn
or allow
where the former will log a warning, and the latter restores the Spring Boot 3.3 behaviour.
More granular Actuator access control
The original on-off support has been augmented with a read-only mode to enhance security.
To facilitate this some properties have been deprecated
management.endpoints.enabled-by-default
in favour of management.endpoints.access.defaultmanagement.endpoint.<id>.enabled
in favour ofmanagement.endpoint.<id>.access
On the @Endpoint
annotation, the enableByDefault
attribute has also been deprecated in favour of the new defaultAccess attribute
.
Important to keep in mind is that enabled-by-default
is now applied consistently regardless of the use of @ConditionalOnEnabledEndpoint.
Thus I an endpoint becomes unavailable after your upgrade you will need to do one of the following:
- set
management.endpoint.<id>.access
toread-only
orunrestricted
- set management.endpoint.<id>.enabled to true
And a new property has been added: management.endpoints.access.max-permitted.
It allows an operator to manage the permitted access level to Actuator endpoints by defining the maximum level of access.
For example:management.endpoint.loggers.access=unrestricted
management.endpoints.access.max-permitted=readonly
This will result in only read-only access to the logger endpoint being allowed.
OkHttp Dependency is no longer managed
If our application directly depends on OkHttp
we will need to specify a version as Spring Boot no longer depends on it.
@AutoConfigureTestDatabase
If we’re using containerized databases we no longer need to add replace=Replace.NONE
as there’s now autodetection for container usage. We can apply replace=Replace.AUTO_CONFIGURED
to revert to the old behaviour.
Graceful shutdown by default
Embedded webservers will now shut down gracefully by default, if you preferred the old behaviour you can set server.shutdown
to immediate.
Gradle 8
The minimum supported version has shifted to 8.4, and Gradle 7 remains at 7.6.4 and later.
Cloud-native buildpacks
The default cloud native buildpack builder used when we are using the build image goal in Gradle or Maven has changed from paketobuildpacks/builder-jammy-base
to paketobuildpacks/builder-jammy-java-tiny. This will result in smaller images, one important thing to keep in mind is that out of the box tiny does not include a shell, so if you require a start script then you’ll need to customize the builder as documented here for Maven or Gradle
Deprecations
- The Spring Boot managed
org.webjars:webjars-locator-core
dependency support has been deprecated in favour of org.webjars:webjars-locator-lite
. This dependency is used for faster startup times and assert resolution when using WebJars ( documentation for this feature). OtlpAutoConfiguration
has been deprecated in favour ofOtlpTracingAutoConfiguration
Varia
There have been a lot of minor changes, for which I recommend checking out the release notes. Some interesting ones are:
- A new s
pring.data.web.pageable.serialization-mode
property to configure the spring data web serialization mode - Registered
@ConfigurationProperties
beans now respect@DependsOn, @Description, @Fallback, @Lazy, @Primary, @Scope
and@Role
annotations. - Support for Testcontainer’s
RedisContainer
has been added - Autoconfiguration for MockMvcTester is now provided when AssertJ is on the classpath.
Personal thoughts
It’s nice to see the direction the framework’s evolving with the strong focus on observability and developer productivity engineering.
Juergen Hoeller also released some information on what we can look forward to In Spring framework 7.0 on his recent blog post From Spring Framework 6.2 to 7.0.
As always, I recommend perusing the Spring Boot 3.4 release notes. There are certainly more interesting things to peruse in there, and as always the Spring team has done a magnificent job of documenting the (dependency) changes.
Getting in Touch
I’m always happy to receive feedback, and questions, or engage in an interesting conversation. Feel free to check out my recent blog, where I shared tips for structured logging in Spring Boot 3.4.
In case you want to reach out I can be found at:
- https://www.linkedin.com/in/simonverhoeven/
- https://github.com/simonVerhoeven/
- https://twitter.com/Simon_Verhoeven