☕ Modern Spring & Testing Updates — Spring Boot 4, Spring 7 & JUnit 6
Keeping up with the latest in Spring and testing frameworks is essential for building scalable, reactive, and maintainable applications. Here’s a complete and updated overview of what’s new in Spring Boot 4, Spring Framework 7, and JUnit 6 — including real examples, architectural insights, and practical features for enterprise microservices. ๐
1️⃣ Spring Boot 4 — Key Enhancements
- ๐จ Faster startup and lower memory footprint using improved AOT
- ☁️ Better cloud-native support and Spring Cloud integration
- ๐ Observability by default (Micrometer 2 + OpenTelemetry)
- ๐งฉ Complete modularization — giant auto-config JAR split into dozens of small modules
- ๐ Built-in null-safety using JSpecify annotations
- ๐ ️ New
@ConfigurationPropertiesSourcefor modular configuration metadata - ๐ Improved SSL health reporting (e.g.,
expiringChains) - ๐ Fully optimized for GraalVM native images
- ⚡ Virtual threads support (Java 21/25) for 10,000+ concurrent requests
- ๐️ First-Class API Versioning: Native support for URL, header, or media-type versioning
๐ Example: API Versioning
@RestController
@RequestMapping(value = "/customer", version = "2")
public class CustomerV2Controller {
@GetMapping
public Customer getCustomer() {
// Version 2 logic
return new Customer("Alice", "Premium");
}
}
Clients can access this version using the URL: /v2/customer
Other supported strategies:
- ๐จ Header versioning:
X-API-VERSION: 2 - ๐ Media-type versioning:
Accept: application/vnd.example.v2+json
✅ Benefits:
- ๐ซ Avoid breaking clients when evolving APIs
- ๐ Supports multiple concurrent API versions
- ✨ Cleaner, declarative approach without custom logic
๐งฉ Why Modularization Matters
- ๐จ Faster startup and smaller Docker images
- ๐ Better native-image builds (GraalVM)
- ๐️ Cleaner dependency management
- ☁️ Better for monorepos & cloud deployments
- ๐ Huge benefit for microservices running on Kubernetes
๐ฅ️ Native Image Example
./mvnw spring-boot:build-image -Dspring-boot.build-image.imageName=demo-native
./demo-native
๐ Observability Enabled by Default
management:
endpoints:
web:
exposure:
include: "*"
tracing:
enabled: true
metrics:
enable:
all: true
๐ก️ Custom Health Indicator
@Component
public class ExternalServiceHealth implements HealthIndicator {
@Override
public Health health() {
boolean status = pingExternalSystem();
return status
? Health.up().build()
: Health.down().withDetail("reason", "External service unreachable").build();
}
}
2️⃣ Spring Framework 7 — New Features
- ☕ Jakarta EE 11 support (Servlet 6.1, JPA 3.2, Validation 3.1)
- ๐ New fluent
JmsClientAPI - ๐ก️ Built-in resilience:
@Retryable,@CircuitBreaker,@ConcurrencyLimit - ๐งพ Overhauled
HttpHeadersAPI - ๐ก New declarative HTTP clients (
@HttpServiceClient) — official alternative to Feign - ๐ฆ Programmatic registration via
BeanRegistrar - ๐ JSpecify null-safety across core APIs
- ๐งช Test context pausing to speed up large test suites
⚡ Functional Endpoint Example
@Bean
RouterFunction httpRoutes(MyHandler handler) {
return RouterFunctions.route(GET("/hello"), handler::hello);
}
@Component
public class MyHandler {
public Mono hello(ServerRequest request) {
return ServerResponse.ok().bodyValue("Hello from Spring 7!");
}
}
๐ก HTTP Service Client Example
@HttpServiceClient("paymentService")
public interface PaymentClient {
@PostExchange("/pay")
@Retryable(maxAttempts = 3)
PaymentResponse pay(@RequestBody PaymentRequest req);
}
spring:
http:
service:
clients:
paymentService:
base-url: http://payment-service
๐ก️ Built-In Resilience Example
@EnableResilience // Enables retry, circuit breaker, concurrency limits
@Configuration
public class ResilienceConfig { }
@Service
public class PaymentService {
@Retryable(
attempts = 3,
backoff = @Backoff(delay = 500),
retryOn = { IOException.class }
)
@ConcurrencyLimit(10)
public String processPayment() throws IOException {
System.out.println("Attempting payment...");
if (new Random().nextInt(3) != 0) {
throw new IOException("Payment gateway unreachable");
}
return "Payment successful!";
}
@Recover
public String recover(IOException ex) {
return "Fallback: Payment queued for retry later.";
}
}
3️⃣ JUnit 6 — What’s New
- ๐ Cleaner annotations and extension model
- ๐ Improved parameterized tests
- ๐งช Better nested and dynamic tests
- ๐ Faster test execution and better parallelization
@ParameterizedTest
@ValueSource(strings = {"Hello", "Spring", "JUnit"})
void testNotEmpty(String input) {
assertFalse(input.isEmpty());
}
@DynamicTest
Stream dynamic() {
return Stream.of(1,2,3)
.map(i -> DynamicTest.dynamicTest("test " + i, () -> assertTrue(i > 0)));
}
4️⃣ Spring Boot 4 vs Spring Boot 3
| Feature | Spring Boot 3 | Spring Boot 4 |
|---|---|---|
| Native Images | Basic AOT | Advanced AOT, faster & smaller native images |
| Observability | Optional, manual config | Enabled by default (Micrometer 2 + OTEL) |
| Starter Modules | Larger, monolithic | Complete modularization, smaller & faster |
| Java Baseline | 17+ | 17+ (recommended 21 / 23 / 25) |
| API Versioning | Manual (path, header, param) | First-class support: URL, header, media-type |
| Resilience | Requires Spring Retry / Resilience4j | Built-in: Retry, CB, ConcurrencyLimit |
| Testing | MockMvc / WebTestClient | + New RestTestClient + test context pausing |
| Performance | Standard startup | Virtual threads, <50ms startup, 30–60% lower memory |
5️⃣ Practical Recommendations
- ๐ Migrate Boot 3 → 4 gradually and test AOT builds early
- ⚡ Use new resilience annotations instead of external libraries
- ๐ Adopt JSpecify null-safety to avoid NPE bugs
- ๐ญ Enable OpenTelemetry from day one for distributed tracing and metrics
- ๐งฉ Take advantage of new modular starters to reduce jar size
- ๐ Use
@HttpServiceClientfor modern declarative HTTP calls - ๐ฆ Use first-class API versioning to avoid breaking clients
- ☁️ Microservice/cloud benefits: faster pod scaling, smaller Docker images, native images, zero-touch tracing
- ๐ก️ Security upgrades (Spring Security 7): stronger OIDC, OAuth2 improvements, modern crypto defaults, MFA, zero-trust microservice security patterns
Labels: Java, Spring Boot, Spring Framework, Resilience, Microservices, Reactive, Testing, Observability, Security, Cloud
Comments
Post a Comment