Spring Boot 4 is coming in November 2025 (Milestones versions already available), built on top of the brand new Spring Framework 7.0.0.
If you develop modern Java applications, this release brings a host of updates and new features worth exploring.
After the big migration in Spring Boot 3.x to Jakarta EE 10, Spring Boot 4 continues the modernization journey with stronger alignment to Jakarta EE 11, modern JDKs, and cloud-native development practices. This is amajor milestone that sets the tone for the next decade of Java development.
In this article, we’ll highlight the most important changes and what they mean for your projects.
Spring Framework 7 now supports API versioning directly in the@RequestMapping
annotation, making it easier to maintain multiple versions of your REST endpoints and ensure backward compatibility.
@RestController@RequestMapping("/api/products")publicclassProductController{@RequestMapping(value="/search",version="1")publicList<ProductV1>searchProductsV1(@RequestParamStringquery){...}@RequestMapping(value="/search",version="2")publicProductSearchResponseV2searchProductsV2(@RequestParamStringquery,@RequestParam(defaultValue="10")intlimit){...}}
You can specify the desired version using theVersion
header in your HTTP request. The controller will route the request to the appropriate method based on the version provided.
To call version 1 of the API (returns simple product list):
GET /api/products/search?query=laptopVersion: 1
To call version 2 of the API (returns enhanced search with metadata):
GET /api/products/search?query=laptop&limit=20Version: 2
Spring Framework 7 has migrated to JSpecify annotations, improving null safety and integration with Kotlin. JSpecify provides more precise nullness contracts for method parameters, return types, and fields, helping developers catch potential null-related bugs at compile time.
Here’s how you might use JSpecify annotations in a Spring component:
importorg.jspecify.annotations.Nullable;importorg.jspecify.annotations.NonNull;@ComponentpublicclassUserService{public@NonNullStringgetUserName(@NullableStringuserId){if(userId==null){return"Unknown";}// fetch user name logicreturn"Alice";}}
In this example, theuserId
parameter can be null, but the method guarantees a non-null return value. This helps prevent null pointer exceptions and improves code reliability, especially when integrating with Kotlin or other null-safe languages.
Spring Framework 7 introduces theBeanRegistrar
contract, allowing developers to register beans programmatically with more flexibility. This is useful for advanced scenarios where multiple beans need to be registered dynamically, beyond what is possible with@Bean
methods.
@Configuration(proxyBeanMethods=false)publicclassMyBeanConfigimplementsBeanRegistrar{@OverridepublicvoidregisterBeans(BeanDefinitionRegistryregistry){registry.registerBeanDefinition("myBean",newRootBeanDefinition(MyBean.class));}}
You can register beans based on runtime conditions or external configuration, making your application more dynamic and modular.
SpEL (Spring Expression Language) now has better support forOptional
types, including null-safe operations and the Elvis operator. This makes it easier to work with optional values in configuration and bean definitions.
@Value("#{userService.findUser(#userId)?.orElse('Guest')}")privateStringuserName;
You can safely handle missing values and avoid null pointer exceptions in your configuration and bean wiring.
New annotations like@Retryable
and@ConcurrencyLimit
help build more resilient applications by enabling retry logic and concurrency limits directly in your service methods. The@EnableResilientMethods
annotation activates these features for your beans.
@Service@EnableResilientMethodspublicclassPaymentService{@Retryable(maxAttempts=3)publicvoidprocessPayment(){// logic that may fail and should be retried}@ConcurrencyLimit(maxConcurrentCalls=5)publicvoidupdateBalance(){// logic with concurrency limit}}
You can add retry and concurrency control to your business logic with simple annotations, improving reliability and scalability.
Spring Framework 7 adds the@ImportHttpServices
annotation, making it easier to configure and group HTTP clients. This streamlines the setup for applications that interact with multiple external services.
@Configuration(proxyBeanMethods=false)@ImportHttpServices(group="weather",types={WeatherClient.class})publicclassHttpClientConfig{}
You can organize and configure multiple HTTP clients efficiently, reducing boilerplate and improving maintainability.
HTTP clients now support streaming request and response bodies usingInputStream
andOutputStream
. This is especially useful for handling large files or data streams efficiently.
@PostMapping("/upload")publicvoiduploadFile(InputStreaminputStream){// process large file stream}
You can handle large file uploads and downloads without loading everything into memory, improving performance and scalability.
The newJmsClient
provides a modern API for working with JMS (Java Message Service), whileJdbcClient
has been enhanced for easier and more flexible database operations.
JmsClientjmsClient=JmsClient.create(connectionFactory);jmsClient.send("queue","Hello World");JdbcClientjdbcClient=JdbcClient.create(dataSource);List<User>users=jdbcClient.sql("SELECT * FROM users").query(User.class).list();
You get a more fluent and modern API for messaging and database access, reducing boilerplate and improving developer productivity.
Spring Framework 7 introduces centralized configuration for HTTP message converters, making it easier to customize how data is serialized and deserialized in web applications.
@ConfigurationpublicclassWebConfigimplementsWebMvcConfigurer{@OverridepublicvoidconfigureMessageConverters(HttpMessageConverters.ServerBuilderbuilder){builder.jsonMessageConverter(newJacksonJsonHttpMessageConverter(JsonMapper.builder().build()));}}
You can easily customize serialization and deserialization logic for your APIs in a single place, improving consistency and maintainability.
RestTestClient
is a new tool for testing REST APIs, offering a fluent API and support for both live servers and mock setups. It simplifies writing and maintaining integration tests for your endpoints.
RestTestClientclient=RestTestClient.bindToServer("http://localhost:8080");client.get().uri("/api/user").exchange().expectStatus().isOk();
You can write concise and readable integration tests for your REST endpoints, improving test coverage and reliability.
Path matching in Spring MVC has been improved with the enhancedPathPattern
support, replacing legacy options and providing more powerful and flexible URI template matching for your controllers.
@RequestMapping("/**/pages/{pageName}")publicStringhandlePage(@PathVariableStringpageName){returnpageName;}
You can define more flexible and powerful URI patterns for your controllers, making routing and endpoint design easier and more expressive.
Spring Boot 4 and Spring Framework 7 have removed several legacy features and deprecated APIs to streamline the framework and encourage modern development practices.
Removed / Deprecated | Alternative |
---|---|
spring-jcl | Apache Commons Logging |
javax.annotation ,javax.inject | jakarta.annotation ,jakarta.inject |
suffixPatternMatch ,trailingSlashMatch ,favorPathExtension | Explicit media types / URI templates |
XML-based Spring MVC config | Java-basedWebMvcConfigurer |
JUnit 4 | JUnit 5 |
Jackson 2.x | Jackson 3.x |
Below you can find more details about each removal and deprecation.
Thespring-jcl
module has been retired in favor of Apache Commons Logging, simplifying the logging infrastructure. Additionally, annotations fromjavax.annotation
andjavax.inject
are no longer supported—you’ll need to migrate to their Jakarta equivalents:jakarta.annotation
andjakarta.inject
.
Several path mapping options have been removed from Spring MVC. Features likesuffixPatternMatch
,trailingSlashMatch
, andfavorPathExtension
are no longer supported in annotated controller methods and content negotiation.
Previously, you could use suffix-based routing:
@RequestMapping(value="/users.json",produces="application/json")publicList<User>getUsersJson(){...}
Or configure suffix pattern matching in Java config:
@ConfigurationpublicclassWebConfigimplementsWebMvcConfigurer{@OverridepublicvoidconfigurePathMatch(PathMatchConfigurerconfigurer){configurer.setUseSuffixPatternMatch(true);}}
These options are now removed. Instead, use explicit media types and URI templates for cleaner, more predictable routing.
XML configuration for Spring MVC is now deprecated. If you’re still using XML-based configuration like this:
<mvc:annotation-driven/><mvc:resourcesmapping="/resources/**"location="/public/"/><mvc:view-controllerpath="/home"view-name="home"/>
It’s recommended to migrate to Java-based configuration:
@ConfigurationpublicclassWebConfigimplementsWebMvcConfigurer{@OverridepublicvoidaddViewControllers(ViewControllerRegistryregistry){registry.addViewController("/home").setViewName("home");}}
Support for JUnit 4 and Jackson 2.x is also deprecated, encouraging migration to JUnit 5 and newer Jackson versions for better performance and modern testing capabilities.
Java 17+, package updates, XML configs, Junit 5 are some changes you can start now, to make sure your project is ready and simplify the migration process.
Spring Boot 4 and Spring Framework 7 mark a major step forward for Java development, bringing more security, flexibility, and features for modern applications. If you’re considering upgrading your project, I recommend reviewing the changes carefully and testing thoroughly before moving to production. Current Spring Boot 3.5.x will have OSS support until June 2026, so plan accordingly!
Happy Coding!
This work is licensed under aCreative Commons Attribution 4.0 International License. In other words, share generously but provide attribution.
Opinions expressed here are my own.