You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@shenyu.apache.org by zh...@apache.org on 2022/06/11 10:27:17 UTC

[incubator-shenyu] branch master updated: [ISSUE #3484] fix springcloud client lossless registration (#3529)

This is an automated email from the ASF dual-hosted git repository.

zhangzicheng pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-shenyu.git


The following commit(s) were added to refs/heads/master by this push:
     new 75c4b5b4b [ISSUE #3484] fix springcloud client lossless registration (#3529)
75c4b5b4b is described below

commit 75c4b5b4b42eb2bb2a9f8f9fc0afdb99d3505dbf
Author: renzhuyan <40...@qq.com>
AuthorDate: Sat Jun 11 05:27:12 2022 -0500

    [ISSUE #3484] fix springcloud client lossless registration (#3529)
    
    * fix springcloud client lossless registration
---
 ...or.java => SpringCloudClientEventListener.java} | 37 +++++++++++--------
 ...ava => SpringCloudClientEventListenerTest.java} | 42 ++++++++++++++--------
 .../ShenyuSpringCloudClientConfiguration.java      | 10 +++---
 .../ShenyuSpringCloudClientConfigurationTest.java  |  4 +--
 4 files changed, 57 insertions(+), 36 deletions(-)

diff --git a/shenyu-client/shenyu-client-http/shenyu-client-springcloud/src/main/java/org/apache/shenyu/client/springcloud/init/SpringCloudClientBeanPostProcessor.java b/shenyu-client/shenyu-client-http/shenyu-client-springcloud/src/main/java/org/apache/shenyu/client/springcloud/init/SpringCloudClientEventListener.java
similarity index 90%
rename from shenyu-client/shenyu-client-http/shenyu-client-springcloud/src/main/java/org/apache/shenyu/client/springcloud/init/SpringCloudClientBeanPostProcessor.java
rename to shenyu-client/shenyu-client-http/shenyu-client-springcloud/src/main/java/org/apache/shenyu/client/springcloud/init/SpringCloudClientEventListener.java
index 80479b35d..db85bb5ea 100644
--- a/shenyu-client/shenyu-client-http/shenyu-client-springcloud/src/main/java/org/apache/shenyu/client/springcloud/init/SpringCloudClientBeanPostProcessor.java
+++ b/shenyu-client/shenyu-client-http/shenyu-client-springcloud/src/main/java/org/apache/shenyu/client/springcloud/init/SpringCloudClientEventListener.java
@@ -31,8 +31,8 @@ import org.apache.shenyu.register.common.dto.MetaDataRegisterDTO;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.aop.support.AopUtils;
-import org.springframework.beans.BeansException;
-import org.springframework.beans.factory.config.BeanPostProcessor;
+import org.springframework.context.ApplicationListener;
+import org.springframework.context.event.ContextRefreshedEvent;
 import org.springframework.core.annotation.AnnotatedElementUtils;
 import org.springframework.core.annotation.AnnotationUtils;
 import org.springframework.core.env.Environment;
@@ -46,21 +46,22 @@ import java.lang.annotation.Annotation;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.Properties;
 
 /**
- * The type Shenyu client bean post processor.
+ * The type Spring cloud client event listener.
  */
-public class SpringCloudClientBeanPostProcessor implements BeanPostProcessor {
+public class SpringCloudClientEventListener implements ApplicationListener<ContextRefreshedEvent> {
     
     /**
      * api path separator.
      */
     private static final String PATH_SEPARATOR = "/";
     
-    private static final Logger LOG = LoggerFactory.getLogger(SpringCloudClientBeanPostProcessor.class);
+    private static final Logger LOG = LoggerFactory.getLogger(SpringCloudClientEventListener.class);
     
     private final ShenyuClientRegisterEventPublisher publisher = ShenyuClientRegisterEventPublisher.getInstance();
     
@@ -83,9 +84,9 @@ public class SpringCloudClientBeanPostProcessor implements BeanPostProcessor {
      * @param shenyuClientRegisterRepository the shenyu client register repository
      * @param env                            the env
      */
-    public SpringCloudClientBeanPostProcessor(final PropertiesConfig clientConfig,
-                                              final ShenyuClientRegisterRepository shenyuClientRegisterRepository,
-                                              final Environment env) {
+    public SpringCloudClientEventListener(final PropertiesConfig clientConfig,
+                                          final ShenyuClientRegisterRepository shenyuClientRegisterRepository,
+                                          final Environment env) {
         String appName = env.getProperty("spring.application.name");
         Properties props = clientConfig.getProps();
         this.contextPath = Optional.ofNullable(props.getProperty(ShenyuClientConstants.CONTEXT_PATH)).map(UriUtils::repairData).orElse(null);
@@ -101,24 +102,31 @@ public class SpringCloudClientBeanPostProcessor implements BeanPostProcessor {
         mappingAnnotation.add(RequestMapping.class);
         publisher.start(shenyuClientRegisterRepository);
     }
-    
+
     @Override
-    public Object postProcessAfterInitialization(@NonNull final Object bean, @NonNull final String beanName) throws BeansException {
+    public void onApplicationEvent(final ContextRefreshedEvent contextRefreshedEvent) {
+        Map<String, Object> beans = contextRefreshedEvent.getApplicationContext().getBeansWithAnnotation(Controller.class);
+        for (Map.Entry<String, Object> entry : beans.entrySet()) {
+            handler(entry.getValue());
+        }
+    }
+
+    private void handler(final Object bean) {
         Class<?> clazz = bean.getClass();
         if (AopUtils.isAopProxy(bean)) {
             clazz = AopUtils.getTargetClass(bean);
         }
         // Filter out is not controller out
-        if (Boolean.TRUE.equals(isFull) || !hasAnnotation(clazz, Controller.class)) {
-            return bean;
+        if (Boolean.TRUE.equals(isFull)) {
+            return;
         }
-        
+
         final ShenyuSpringCloudClient beanShenyuClient = AnnotatedElementUtils.findMergedAnnotation(clazz, ShenyuSpringCloudClient.class);
         final String superPath = buildApiSuperPath(clazz, beanShenyuClient);
         // Compatible with previous versions
         if (Objects.nonNull(beanShenyuClient) && superPath.contains("*")) {
             publisher.publishEvent(buildMetaDataDTO(beanShenyuClient, pathJoin(contextPath, superPath)));
-            return bean;
+            return;
         }
         final Method[] methods = ReflectionUtils.getUniqueDeclaredMethods(clazz);
         for (Method method : methods) {
@@ -131,7 +139,6 @@ public class SpringCloudClientBeanPostProcessor implements BeanPostProcessor {
                 publisher.publishEvent(buildMetaDataDTO(methodShenyuClient, buildApiPath(method, superPath, methodShenyuClient)));
             }
         }
-        return bean;
     }
     
     private <A extends Annotation> boolean hasAnnotation(final @NonNull Class<?> clazz, final @NonNull Class<A> annotationType) {
diff --git a/shenyu-client/shenyu-client-http/shenyu-client-springcloud/src/test/java/org/apache/shenyu/client/springcloud/init/SpringCloudClientBeanPostProcessorTest.java b/shenyu-client/shenyu-client-http/shenyu-client-springcloud/src/test/java/org/apache/shenyu/client/springcloud/init/SpringCloudClientEventListenerTest.java
similarity index 70%
rename from shenyu-client/shenyu-client-http/shenyu-client-springcloud/src/test/java/org/apache/shenyu/client/springcloud/init/SpringCloudClientBeanPostProcessorTest.java
rename to shenyu-client/shenyu-client-http/shenyu-client-springcloud/src/test/java/org/apache/shenyu/client/springcloud/init/SpringCloudClientEventListenerTest.java
index 7d352fb4a..921c40b72 100644
--- a/shenyu-client/shenyu-client-http/shenyu-client-springcloud/src/test/java/org/apache/shenyu/client/springcloud/init/SpringCloudClientBeanPostProcessorTest.java
+++ b/shenyu-client/shenyu-client-http/shenyu-client-springcloud/src/test/java/org/apache/shenyu/client/springcloud/init/SpringCloudClientEventListenerTest.java
@@ -31,27 +31,31 @@ import org.mockito.Mock;
 import org.mockito.MockedStatic;
 import org.mockito.junit.jupiter.MockitoExtension;
 import org.mockito.stubbing.Answer;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.event.ContextRefreshedEvent;
 import org.springframework.core.env.Environment;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
+import java.util.LinkedHashMap;
+import java.util.Map;
 import java.util.Optional;
 import java.util.Properties;
 
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.equalTo;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 /**
- * Test for {@link SpringCloudClientBeanPostProcessor}.
+ * Test for {@link SpringCloudClientEventListener}.
  */
 @ExtendWith(MockitoExtension.class)
 @TestMethodOrder(MethodOrderer.Alphanumeric.class)
-public final class SpringCloudClientBeanPostProcessorTest {
+public final class SpringCloudClientEventListenerTest {
 
     @Mock
     private static Environment env;
@@ -60,27 +64,36 @@ public final class SpringCloudClientBeanPostProcessorTest {
 
     private final SpringCloudClientTestBean springCloudClientTestBean = new SpringCloudClientTestBean();
 
+    @Mock
+    private ApplicationContext applicationContext;
+
+    private ContextRefreshedEvent contextRefreshedEvent;
+
     @BeforeEach
     public void init() {
         when(env.getProperty("spring.application.name")).thenReturn("spring-cloud-test");
+        Map<String, Object> results = new LinkedHashMap();
+        results.put("springCloudClientTestBean", springCloudClientTestBean);
+        when(applicationContext.getBeansWithAnnotation(any())).thenReturn(results);
+        contextRefreshedEvent = new ContextRefreshedEvent(applicationContext);
     }
 
     @Test
     public void testShenyuBeanProcess() {
         registerUtilsMockedStatic.when(() -> RegisterUtils.doLogin(any(), any(), any())).thenReturn(Optional.of("token"));
         // config with full
-        SpringCloudClientBeanPostProcessor springCloudClientBeanPostProcessor = buildSpringCloudClientBeanPostProcessor(true);
-        assertThat(springCloudClientTestBean, equalTo(springCloudClientBeanPostProcessor.postProcessAfterInitialization(springCloudClientTestBean, "springCloudClientTestBean")));
+        SpringCloudClientEventListener springCloudClientEventListener = buildSpringCloudClienttEventListener(true);
+        springCloudClientEventListener.onApplicationEvent(contextRefreshedEvent);
+        verify(applicationContext, times(1)).getBeansWithAnnotation(any());
         registerUtilsMockedStatic.close();
     }
 
     @Test
     public void testNormalBeanProcess() {
         registerUtilsMockedStatic.when(() -> RegisterUtils.doLogin(any(), any(), any())).thenReturn(Optional.of("token"));
-        SpringCloudClientBeanPostProcessor springCloudClientBeanPostProcessor = buildSpringCloudClientBeanPostProcessor(false);
-        Object normalBean = new Object();
-
-        assertThat(normalBean, equalTo(springCloudClientBeanPostProcessor.postProcessAfterInitialization(normalBean, "normalBean")));
+        SpringCloudClientEventListener springCloudClientEventListener = buildSpringCloudClienttEventListener(false);
+        springCloudClientEventListener.onApplicationEvent(contextRefreshedEvent);
+        verify(applicationContext, times(1)).getBeansWithAnnotation(any());
         registerUtilsMockedStatic.close();
     }
 
@@ -89,12 +102,13 @@ public final class SpringCloudClientBeanPostProcessorTest {
         registerUtilsMockedStatic.when(() -> RegisterUtils.doLogin(any(), any(), any())).thenReturn(Optional.of("token"));
         registerUtilsMockedStatic.when(() -> RegisterUtils.doRegister(any(), any(), any()))
                 .thenAnswer((Answer<Void>) invocation -> null);
-        SpringCloudClientBeanPostProcessor springCloudClientBeanPostProcessor = buildSpringCloudClientBeanPostProcessor(false);
-        assertThat(springCloudClientTestBean, equalTo(springCloudClientBeanPostProcessor.postProcessAfterInitialization(springCloudClientTestBean, "normalBean")));
+        SpringCloudClientEventListener springCloudClientEventListener = buildSpringCloudClienttEventListener(false);
+        springCloudClientEventListener.onApplicationEvent(contextRefreshedEvent);
+        verify(applicationContext, times(1)).getBeansWithAnnotation(any());
         registerUtilsMockedStatic.close();
     }
 
-    private SpringCloudClientBeanPostProcessor buildSpringCloudClientBeanPostProcessor(final boolean full) {
+    private SpringCloudClientEventListener buildSpringCloudClienttEventListener(final boolean full) {
         Properties properties = new Properties();
         properties.setProperty("contextPath", "/test");
         properties.setProperty("isFull", full + "");
@@ -108,7 +122,7 @@ public final class SpringCloudClientBeanPostProcessorTest {
         mockRegisterCenter.setServerLists("http://127.0.0.1:8080");
         mockRegisterCenter.setRegisterType("http");
         mockRegisterCenter.setProps(properties);
-        return new SpringCloudClientBeanPostProcessor(config, ShenyuClientRegisterRepositoryFactory.newInstance(mockRegisterCenter), env);
+        return new SpringCloudClientEventListener(config, ShenyuClientRegisterRepositoryFactory.newInstance(mockRegisterCenter), env);
     }
 
     @RestController
diff --git a/shenyu-spring-boot-starter/shenyu-spring-boot-starter-client/shenyu-spring-boot-starter-client-springcloud/src/main/java/org/apache/shenyu/springboot/starter/client/springcloud/ShenyuSpringCloudClientConfiguration.java b/shenyu-spring-boot-starter/shenyu-spring-boot-starter-client/shenyu-spring-boot-starter-client-springcloud/src/main/java/org/apache/shenyu/springboot/starter/client/springcloud/ShenyuSpringCloudClientConfiguration.java
index e58fddc41..96d607cea 100644
--- a/shenyu-spring-boot-starter/shenyu-spring-boot-starter-client/shenyu-spring-boot-starter-client-springcloud/src/main/java/org/apache/shenyu/springboot/starter/client/springcloud/ShenyuSpringCloudClientConfiguration.java
+++ b/shenyu-spring-boot-starter/shenyu-spring-boot-starter-client/shenyu-spring-boot-starter-client-springcloud/src/main/java/org/apache/shenyu/springboot/starter/client/springcloud/ShenyuSpringCloudClientConfiguration.java
@@ -18,7 +18,7 @@
 package org.apache.shenyu.springboot.starter.client.springcloud;
 
 import org.apache.shenyu.client.springcloud.init.ContextRegisterListener;
-import org.apache.shenyu.client.springcloud.init.SpringCloudClientBeanPostProcessor;
+import org.apache.shenyu.client.springcloud.init.SpringCloudClientEventListener;
 import org.apache.shenyu.common.enums.RpcTypeEnum;
 import org.apache.shenyu.register.client.api.ShenyuClientRegisterRepository;
 import org.apache.shenyu.register.common.config.ShenyuClientConfig;
@@ -44,10 +44,10 @@ public class ShenyuSpringCloudClientConfiguration {
      * @return the spring cloud client bean post processor
      */
     @Bean
-    public SpringCloudClientBeanPostProcessor springCloudClientBeanPostProcessor(final ShenyuClientConfig clientConfig,
-                                                                                 final ShenyuClientRegisterRepository shenyuClientRegisterRepository,
-                                                                                 final Environment env) {
-        return new SpringCloudClientBeanPostProcessor(clientConfig.getClient().get(RpcTypeEnum.SPRING_CLOUD.getName()), shenyuClientRegisterRepository, env);
+    public SpringCloudClientEventListener springCloudClientEventListener(final ShenyuClientConfig clientConfig,
+                                                                        final ShenyuClientRegisterRepository shenyuClientRegisterRepository,
+                                                                        final Environment env) {
+        return new SpringCloudClientEventListener(clientConfig.getClient().get(RpcTypeEnum.SPRING_CLOUD.getName()), shenyuClientRegisterRepository, env);
     }
     
     /**
diff --git a/shenyu-spring-boot-starter/shenyu-spring-boot-starter-client/shenyu-spring-boot-starter-client-springcloud/src/test/java/org/apache/shenyu/springboot/starter/client/springcloud/ShenyuSpringCloudClientConfigurationTest.java b/shenyu-spring-boot-starter/shenyu-spring-boot-starter-client/shenyu-spring-boot-starter-client-springcloud/src/test/java/org/apache/shenyu/springboot/starter/client/springcloud/ShenyuSpringCloudClientConfigurationTest.java
index 3520d5ab3..4dbe1cdf1 100644
--- a/shenyu-spring-boot-starter/shenyu-spring-boot-starter-client/shenyu-spring-boot-starter-client-springcloud/src/test/java/org/apache/shenyu/springboot/starter/client/springcloud/ShenyuSpringCloudClientConfigurationTest.java
+++ b/shenyu-spring-boot-starter/shenyu-spring-boot-starter-client/shenyu-spring-boot-starter-client-springcloud/src/test/java/org/apache/shenyu/springboot/starter/client/springcloud/ShenyuSpringCloudClientConfigurationTest.java
@@ -18,7 +18,7 @@
 package org.apache.shenyu.springboot.starter.client.springcloud;
 
 import org.apache.shenyu.client.springcloud.init.ContextRegisterListener;
-import org.apache.shenyu.client.springcloud.init.SpringCloudClientBeanPostProcessor;
+import org.apache.shenyu.client.springcloud.init.SpringCloudClientEventListener;
 import org.apache.shenyu.register.client.http.utils.RegisterUtils;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
@@ -65,7 +65,7 @@ public class ShenyuSpringCloudClientConfigurationTest {
         MockedStatic<RegisterUtils> registerUtilsMockedStatic = mockStatic(RegisterUtils.class);
         registerUtilsMockedStatic.when(() -> RegisterUtils.doLogin(any(), any(), any())).thenReturn(Optional.ofNullable("token"));
         applicationContextRunner.run(context -> {
-            SpringCloudClientBeanPostProcessor repository = context.getBean("springCloudClientBeanPostProcessor", SpringCloudClientBeanPostProcessor.class);
+            SpringCloudClientEventListener repository = context.getBean("springCloudClientEventListener", SpringCloudClientEventListener.class);
             assertNotNull(repository);
         });
         registerUtilsMockedStatic.close();