☕ 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 @ConfigurationPropertiesSource for 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 JmsClient API
  • ๐Ÿ›ก️ Built-in resilience: @Retryable, @CircuitBreaker, @ConcurrencyLimit
  • ๐Ÿงพ Overhauled HttpHeaders API
  • ๐Ÿ“ก 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 @HttpServiceClient for 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

Popular posts from this blog

๐Ÿ› ️ The Code Hut - Index

๐Ÿ›ก️ Thread-Safe Programming in Java: Locks, Atomic Variables & LongAdder

๐Ÿ›ก️ Resilience Patterns in Distributed Systems