[BUG] ShenyuClientProxyFactory caches proxies in static ConcurrentMap keyed by apiClass — stale proxy + ApplicationContext leak across restarts
- Dominant language
- Java
- Stars
- 8.8k
- Forks
- 3.1k
- Avg merge
- 7d 1h
- Merged PRs (30d)
- 85
Description
## Description
`PROXY_CACHE` is a `static` `ConcurrentMap, Object>` that is never cleared. `createProxy` does a `containsKey`-then-`get` fast path, else `synchronized(apiClass)` builds a `ShenyuClientInvocationHandler` (which captures the `ApplicationContext` and the per-bean `ShenyuClientFactoryBean` and resolves `applicationContext.getBean(ShenyuSdkClient.class)` at construction) and stores it in the static map. The first `ApplicationContext` to build a proxy for a given interface wins; every subsequent context (Spring Boot devtools restart, repeated `@SpringBootTest` contexts) receives the cached proxy bound to the now-closed previous context.
## Location
- `shenyu-sdk/shenyu-sdk-spring/src/main/java/org/apache/shenyu/sdk/spring/proxy/ShenyuClientProxyFactory.java:36,51-61`
- `shenyu-sdk/shenyu-sdk-spring/src/main/java/org/apache/shenyu/sdk/spring/proxy/ShenyuClientInvocationHandler.java:65-74,99-114`
## Impact
After a context restart the proxy's captured `ShenyuSdkClient` and `ApplicationContext` belong to the dead context (broken/leaked HTTP client, stale url/path from the old `ShenyuClientFactoryBean`). The static cache also holds a strong reference to the closed `ApplicationContext` and all beans it transitively captured, preventing GC of closed contexts → memory growth across restarts.
## Suggested fix
Key the cache per-context (or drop the static cache and rely on `FactoryBean.isSingleton()` + Spring's own singleton cache); alternatively clear `PROXY_CACHE` on context close / make it an instance field wired to the registrar.
## Related existing
None — distinct from #6787 (static URIS list in register-client `ShenyuClientURIExecutorSubscriber`, different class/module) and #6729 (GW-SPI-7, ExtensionLoader pinned ClassLoader).
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with ShenyuClientProxyFactory.java, especially PROXY_CACHE and createProxy, then read ShenyuClientInvocationHandler.java to trace the captured ApplicationContext and ShenyuSdkClient. Exercise proxy creation across repeated Spring application contexts and verify that a new context does not receive a proxy from a closed one. Done means stale proxies and strong references to closed contexts are no longer retained.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, spring
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100