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);

Reply via email to