Spring Proxy Self-Invocation Bypasses @Cacheable, Hurts API Performance

🚨 How Spring Proxy Self-Invocation Bypassed @Cacheable and Degraded API Performance Debugged a performance issue where a critical API response time degraded to ~500ms under load. 🔍 What actually happened? A @Cacheable method in the service layer was invoked from another method within the same class. This internal call bypassed the Spring proxy, so caching was never applied — with no errors or warnings. Consequently, MongoDB was hit on every invocation (~55ms per call), and concurrency amplified the latency. Methods were public, the annotation was correct, and indexes existed in MongoDB, but none of that mattered because Spring intercepts only external calls through the proxy; self-invocation does not trigger caching. ⚠️ Key Insight Spring's official documentation states: "In proxy mode, only external method calls coming in through the proxy are intercepted. Self-invocation will not lead to actual caching at runtime even if the method is marked with @Cacheable." Java resolves internal calls as this.method() — pointing to the target object, not the proxy. ✅ Fixes Identified via JFR stack traces and I/O analysis. Removed repeated DB calls from downstream flow, introduced parallel fetch using virtual threads, and passed pre-fetched data through the call chain. This removed the need for the internal method to independently call the @Cacheable method, eliminating the proxy bypass. 👉 Result: API response time dropped from ~500ms to ~20ms 🧠 Takeaway If @Cacheable is present but ineffective, verify the call path. Self-invocation within the same class bypasses the proxy, and caching will not execute. 👉 Curious if others have encountered Spring proxy self-invocation in production. #Java #SpringBoot #SpringFramework #PerformanceEngineering #MongoDB #BackendEngineering #JVM #JFR #Caching #DistributedSystems #SoftwareEngineering #ProductionIncident #Debugging #MicroServices #JavaPerformance

To view or add a comment, sign in

Explore content categories