Spring 7.0.4: Hidden Deadlock Fix and 30‑50% Startup Boost for K8s Apps
The article analyzes a nondeterministic deadlock bug in Spring 7.0.0‑7.0.3 that surfaces in Kubernetes pods, explains how Spring 7.0.4 resolves it with a revised shutdown state machine, details additional performance‑related fixes and new features, and provides practical upgrade guidance based on JDK version and deployment scenario.
Scenario
At 3 am an alert fires in a Kubernetes cluster: a core‑service pod is repeatedly killed and recreated, but the new pod hangs. The log ends with Initializing Spring DispatcherServlet, CPU is near 0 %, and jstack shows two threads waiting on each other’s locks – AbstractApplicationContext.close() and the JVM ShutdownHook. Restarting the pod temporarily fixes the issue, but it reappears after a few days. The problem exists in Spring 7.0.0 – 7.0.3 and is fixed in 7.0.4.
Root Cause
When a Spring application shuts down, two parallel paths are executed: ConfigurableApplicationContext.close() publishes ContextClosedEvent and destroys beans.
The JVM ShutdownHook is triggered by System.exit.
In a Kubernetes graceful‑shutdown scenario the following sequence can occur: SIGTERM arrives, starting graceful shutdown.
The application begins the close() process.
If the graceful shutdown times out, kubelet sends SIGKILL.
Before SIGKILL the JVM may also run its ShutdownHook.
Both paths try to acquire the same lock, causing a deadlock.
The bug is nondeterministic; its occurrence depends on GC pauses, thread scheduling, and bean‑destruction time. It may never appear in local mvn test runs but surfaces intermittently in production.
Fix in Spring 7.0.4
The framework rewrites the ConfigurableApplicationContext state machine, introduces an independent shutdown flag and a CAS operation, ensuring that close() and the ShutdownHook never run the destroy logic simultaneously. Whichever path arrives first wins; the later one detects that shutdown is already in progress and exits.
How to Detect the Problem
Pod starts but stays stuck; the process does not exit. jstack shows close() and ShutdownHook threads waiting on each other.
The issue only reproduces in container/K8s environments, not locally.
Higher deployment frequency correlates with higher occurrence rate.
Other Notable Fixes in 7.0.4
#36293 – ConcurrentReferenceHashMap lock contention could degrade throughput under high concurrency.
#36298 – Header modifications in HandlerInterceptor were not propagated to downstream services.
#36266 – WebSocket StompBrokerRelayMessageHandler failed to reconnect after the broker restarted.
#36285 and #36226 – Message converters now support MIME wildcards; HeadersAdapter.remove() returns null instead of an empty list.
Performance Optimizations
Spring 7.0.4 accelerates start‑up and request handling through three dimensions.
1. Faster request‑mapping lookup
Hash algorithm for URL patterns replaced with a more efficient implementation (+≈5 % at million QPS).
Bean‑lookup path shortened by removing redundant intermediate objects during HandlerMethod resolution.
Single‑URL @RequestMapping patterns bypass generic pattern‑matching logic.
API‑version mapping decoupled, eliminating extra checks.
Community benchmarks report 15‑20 % latency reduction for gateway‑type services.
2. Annotation parsing cache
All annotation‑driven features ( @Transactional, @Cacheable, @Valid, etc.) previously re‑parsed on every invocation. The new implementation caches the first parse result, turning subsequent calls into pure memory look‑ups.
3. Validation reflection slimming
Bean‑validation group resolution no longer repeatedly calls Class.getAnnotations(), cutting reflection overhead in bulk‑import or multi‑step‑form scenarios.
Combined, these changes yield a 30‑50 % start‑up speedup and a 10‑20 % runtime request‑handling improvement, verified with the spring-petclinic benchmark.
Upgrade Guidance
Three hard prerequisites for moving from Spring 6.x to 7.x:
JDK ≥ 17 (21+ recommended).
All dependencies migrated from javax.* to jakarta.*.
Read the official migration guide before changing pom.xml files.
JDK version also influences the magnitude of the startup boost:
JDK 17 → ~10‑15 % improvement (only routing and annotation cache gains).
JDK 21 → ~25‑35 % improvement (virtual threads available but scheduler not fully optimized).
JDK 25 → ~40‑50 % improvement (Reactor 2025.0.3 fully exploits virtual threads).
Other dependency upgrades include Micrometer 1.6.3, ASM 9.9.1, and Apache POI 5.5, which improve monitoring and large‑file export performance.
Bottom Line
Spring 7.0.4 eliminates a hard‑to‑detect deadlock, speeds up start‑up, and trims runtime latency—benefits that translate directly into higher stability and productivity for production workloads.
Release notes: https://github.com/spring-projects/spring-framework/releases/tag/v7.0.4
Java Architect Essentials
Committed to sharing quality articles and tutorials to help Java programmers progress from junior to mid-level to senior architect. We curate high-quality learning resources, interview questions, videos, and projects from across the internet to help you systematically improve your Java architecture skills. Follow and reply '1024' to get Java programming resources. Learn together, grow together.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
