This is an automated email from the ASF dual-hosted git repository.
Aias00 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shenyu.git
The following commit(s) were added to refs/heads/master by this push:
new 62e8200d60 fix(websocket): register endpoints once across context
refreshes (#7272)
62e8200d60 is described below
commit 62e8200d60681a215b11f2d6f3eb98c737a22243
Author: Liming Deng <[email protected]>
AuthorDate: Sun Sep 27 11:07:48 2026 +0800
fix(websocket): register endpoints once across context refreshes (#7272)
Co-authored-by: aias00 <[email protected]>
---
.../init/SpringWebSocketClientEventListener.java | 5 ++-
.../SpringWebSocketClientEventListenerTest.java | 38 ++++++++++++++++++++++
2 files changed, 42 insertions(+), 1 deletion(-)
diff --git
a/shenyu-client/shenyu-client-websocket/shenyu-client-spring-websocket/src/main/java/org/apache/shenyu/client/spring/websocket/init/SpringWebSocketClientEventListener.java
b/shenyu-client/shenyu-client-websocket/shenyu-client-spring-websocket/src/main/java/org/apache/shenyu/client/spring/websocket/init/SpringWebSocketClientEventListener.java
index 1461ff7c0b..e6eb1e4b1c 100644
---
a/shenyu-client/shenyu-client-websocket/shenyu-client-spring-websocket/src/main/java/org/apache/shenyu/client/spring/websocket/init/SpringWebSocketClientEventListener.java
+++
b/shenyu-client/shenyu-client-websocket/shenyu-client-spring-websocket/src/main/java/org/apache/shenyu/client/spring/websocket/init/SpringWebSocketClientEventListener.java
@@ -55,6 +55,7 @@ import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Properties;
+import java.util.concurrent.atomic.AtomicBoolean;
/**
* The type Shenyu websocket client event listener.
@@ -69,6 +70,8 @@ public class SpringWebSocketClientEventListener extends
AbstractContextRefreshed
private final String protocol;
+ private final AtomicBoolean endpointsRegistered = new AtomicBoolean();
+
/**
* Instantiates a new Spring websocket client event listener.
*
@@ -251,7 +254,7 @@ public class SpringWebSocketClientEventListener extends
AbstractContextRefreshed
}
private void registerEndpointsBeans(final ApplicationContext context,
final Map<String, Object> endpointBeans) {
- if (CollectionUtils.isEmpty(endpointBeans)) {
+ if (CollectionUtils.isEmpty(endpointBeans) ||
!endpointsRegistered.compareAndSet(false, true)) {
return;
}
ShenyuServerEndpointerExporter exporter =
(ShenyuServerEndpointerExporter) registerBean(context,
ShenyuServerEndpointerExporter.class, "shenyuServerEndpointerExporter");
diff --git
a/shenyu-client/shenyu-client-websocket/shenyu-client-spring-websocket/src/test/java/org/apache/shenyu/client/spring/websocket/init/SpringWebSocketClientEventListenerTest.java
b/shenyu-client/shenyu-client-websocket/shenyu-client-spring-websocket/src/test/java/org/apache/shenyu/client/spring/websocket/init/SpringWebSocketClientEventListenerTest.java
index 9f973b28f5..831906283c 100644
---
a/shenyu-client/shenyu-client-websocket/shenyu-client-spring-websocket/src/test/java/org/apache/shenyu/client/spring/websocket/init/SpringWebSocketClientEventListenerTest.java
+++
b/shenyu-client/shenyu-client-websocket/shenyu-client-spring-websocket/src/test/java/org/apache/shenyu/client/spring/websocket/init/SpringWebSocketClientEventListenerTest.java
@@ -20,6 +20,7 @@ package org.apache.shenyu.client.spring.websocket.init;
import org.apache.shenyu.client.core.constant.ShenyuClientConstants;
import
org.apache.shenyu.client.core.disruptor.ShenyuClientRegisterEventPublisher;
import
org.apache.shenyu.client.spring.websocket.annotation.ShenyuSpringWebSocketClient;
+import
org.apache.shenyu.client.spring.websocket.annotation.ShenyuServerEndpoint;
import org.apache.shenyu.common.constant.Constants;
import org.apache.shenyu.common.enums.RpcTypeEnum;
import org.apache.shenyu.register.client.api.ShenyuClientRegisterRepository;
@@ -36,6 +37,8 @@ import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.context.ApplicationContext;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.util.ReflectionUtils;
@@ -108,6 +111,41 @@ public class SpringWebSocketClientEventListenerTest {
verify(publisher, never()).publishEvent(any());
}
+ @Test
+ void registersEndpointsOnceAcrossRepeatedRefreshEvents() {
+ ConfigurableApplicationContext context =
mock(ConfigurableApplicationContext.class);
+ DefaultListableBeanFactory beanFactory = new
DefaultListableBeanFactory();
+ beanFactory.setAllowBeanDefinitionOverriding(false);
+ ShenyuServerEndpointerExporter exporter =
mock(ShenyuServerEndpointerExporter.class);
+ when(context.getAutowireCapableBeanFactory()).thenReturn(beanFactory);
+
when(context.getBean(ShenyuServerEndpointerExporter.class)).thenReturn(exporter);
+
when(context.getBeansWithAnnotation(ShenyuServerEndpoint.class)).thenReturn(Collections.singletonMap("endpoint",
new MockClass()));
+ ContextRefreshedEvent event = new ContextRefreshedEvent(context);
+
+ eventListener.onApplicationEvent(event);
+ eventListener.onApplicationEvent(event);
+
+ verify(exporter).registerEndpoint(MockClass.class);
+ assertEquals(1, beanFactory.getBeanDefinitionCount());
+ }
+
+ @Test
+ void emptyParentContextDoesNotConsumeEndpointRegistrationGuard() {
+ eventListener.getBeans(applicationContext);
+ ConfigurableApplicationContext child =
mock(ConfigurableApplicationContext.class);
+ DefaultListableBeanFactory beanFactory = new
DefaultListableBeanFactory();
+ beanFactory.setAllowBeanDefinitionOverriding(false);
+ ShenyuServerEndpointerExporter exporter =
mock(ShenyuServerEndpointerExporter.class);
+ when(child.getAutowireCapableBeanFactory()).thenReturn(beanFactory);
+
when(child.getBean(ShenyuServerEndpointerExporter.class)).thenReturn(exporter);
+
when(child.getBeansWithAnnotation(ShenyuServerEndpoint.class)).thenReturn(Collections.singletonMap("endpoint",
new MockClass()));
+
+ eventListener.getBeans(child);
+ eventListener.getBeans(child);
+
+ verify(exporter).registerEndpoint(MockClass.class);
+ }
+
@Test
public void testBuildURIRegisterDTO() {
URIRegisterDTO uriRegisterDTO =
eventListener.buildURIRegisterDTO(applicationContext, Collections.emptyMap(),
Constants.SYS_DEFAULT_NAMESPACE_ID);