- Severity: Medium
- Location:
shenyu-client/shenyu-client-websocket/shenyu-client-spring-websocket/src/main/java/org/apache/shenyu/client/spring/websocket/init/SpringWebSocketClientEventListener.java:113-115 (registerEndpointsBeans call in getBeans); guard at shenyu-client-core/.../AbstractContextRefreshedEventListener.java:149 (markRegistered)
Description:
The parent onApplicationEvent calls getBeans(context) (line 145) before markRegistered() (line 149). The WebSocket override of getBeans performs the side-effecting registerEndpointsBeans(context, endpointBeans) (line 114), which calls ShenyuServerEndpointerExporter.registerEndpoint → serverContainer.addEndpoint(endpointConfig) for every @ShenyuServerEndpoint bean. The once-only markRegistered guard protects handle and URI publishing, but does not protect this getBeans side effect. On a second ContextRefreshedEvent (Spring MVC parent+child contexts, or integration tests refreshing multiple contexts), addEndpoint is invoked again for the same path; per the Jakarta WebSocket spec and Tomcat's WsServerContainer, re-adding a duplicate path throws DeploymentException (wrapped as IllegalStateException at ShenyuServerEndpointerExporter.java:112), failing the context refresh.
Impact:
Duplicate websocket endpoint registration crashes context refresh in hierarchical/multi-refresh contexts.
Suggested fix:
Move registerEndpointsBeans out of getBeans into handle (which is post-guard), or track endpoint registration with its own AtomicBoolean.
Confidence: Medium
Identified during the 2026-08-02 deep re-scan; full list in docs/scan2-2026-08-02/06-medium-tiers.md.
shenyu-client/shenyu-client-websocket/shenyu-client-spring-websocket/src/main/java/org/apache/shenyu/client/spring/websocket/init/SpringWebSocketClientEventListener.java:113-115(registerEndpointsBeanscall ingetBeans); guard atshenyu-client-core/.../AbstractContextRefreshedEventListener.java:149(markRegistered)Description:
The parent
onApplicationEventcallsgetBeans(context)(line 145) beforemarkRegistered()(line 149). The WebSocket override ofgetBeansperforms the side-effectingregisterEndpointsBeans(context, endpointBeans)(line 114), which callsShenyuServerEndpointerExporter.registerEndpoint→serverContainer.addEndpoint(endpointConfig)for every@ShenyuServerEndpointbean. The once-onlymarkRegisteredguard protectshandleand URI publishing, but does not protect thisgetBeansside effect. On a secondContextRefreshedEvent(Spring MVC parent+child contexts, or integration tests refreshing multiple contexts),addEndpointis invoked again for the same path; per the Jakarta WebSocket spec and Tomcat'sWsServerContainer, re-adding a duplicate path throwsDeploymentException(wrapped asIllegalStateExceptionatShenyuServerEndpointerExporter.java:112), failing the context refresh.Impact:
Duplicate websocket endpoint registration crashes context refresh in hierarchical/multi-refresh contexts.
Suggested fix:
Move
registerEndpointsBeansout ofgetBeansintohandle(which is post-guard), or track endpoint registration with its ownAtomicBoolean.Confidence: Medium
Identified during the 2026-08-02 deep re-scan; full list in
docs/scan2-2026-08-02/06-medium-tiers.md.