You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@shenyu.apache.org by xi...@apache.org on 2022/01/12 13:30:29 UTC

[incubator-shenyu] branch master updated: [type:bug] plugins register spring bean fix. (#2757)

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

xiaoyu 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 bcf180a  [type:bug] plugins register spring bean fix. (#2757)
bcf180a is described below

commit bcf180aa41ea4ca390fd439107924e0b73fae4d1
Author: Sixh-PrFor <ch...@163.com>
AuthorDate: Wed Jan 12 21:30:20 2022 +0800

    [type:bug] plugins register spring bean fix. (#2757)
    
    * plugins register spring bean fix.
    
    * ext:plugins test case.
---
 .../shenyu/plugin/api/utils/SpringBeanUtils.java   | 31 ++++++++++++++++
 .../shenyu/web/loader/ShenyuLoaderService.java     | 43 ++++++++++++++--------
 .../shenyu/web/loader/ShenyuPluginLoader.java      | 27 ++++++--------
 .../shenyu/web/loader/ShenyuPluginPathBuilder.java | 29 +++++++++------
 .../shenyu/web/loader/ShenyuPluginLoaderTest.java  | 39 +++++++++++++-------
 .../web/loader/ShenyuPluginPathBuilderTest.java    | 20 +++++-----
 6 files changed, 122 insertions(+), 67 deletions(-)

diff --git a/shenyu-plugin/shenyu-plugin-api/src/main/java/org/apache/shenyu/plugin/api/utils/SpringBeanUtils.java b/shenyu-plugin/shenyu-plugin-api/src/main/java/org/apache/shenyu/plugin/api/utils/SpringBeanUtils.java
index 92d6c7f..bbf1ed1 100644
--- a/shenyu-plugin/shenyu-plugin-api/src/main/java/org/apache/shenyu/plugin/api/utils/SpringBeanUtils.java
+++ b/shenyu-plugin/shenyu-plugin-api/src/main/java/org/apache/shenyu/plugin/api/utils/SpringBeanUtils.java
@@ -18,6 +18,7 @@
 package org.apache.shenyu.plugin.api.utils;
 
 import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.BeansException;
 import org.springframework.beans.factory.config.BeanDefinition;
 import org.springframework.beans.factory.support.DefaultListableBeanFactory;
 import org.springframework.context.ApplicationContext;
@@ -85,6 +86,36 @@ public final class SpringBeanUtils {
         return beanName;
     }
     
+    /**
+     * Exist spring bean boolean.
+     * Only applies to successful beans registered by the {@linkplain #registerBean(BeanDefinition, ClassLoader)} method.
+     *
+     * @param className the class name
+     * @return the boolean
+     */
+    public boolean existBean(final String className) {
+        String beanName = this.getBeanName(className);
+        return this.applicationContext.containsBean(beanName);
+    }
+    
+    /**
+     * Get bean boolean.
+     * Only applies to successful beans registered by the {@linkplain #registerBean(BeanDefinition, ClassLoader)} method.
+     *
+     * @param <T>       the type parameter
+     * @param className the class name
+     * @return boolean bean by class name
+     */
+    @SuppressWarnings("all")
+    public <T> T getBeanByClassName(final String className) {
+        String beanName = this.getBeanName(className);
+        try {
+            return this.getBean(beanName);
+        } catch (BeansException e) {
+            return null;
+        }
+    }
+    
     private String getBeanName(final String className) {
         String name = className.substring(className.lastIndexOf(".") + 1);
         String start = name.substring(0, 1);
diff --git a/shenyu-web/src/main/java/org/apache/shenyu/web/loader/ShenyuLoaderService.java b/shenyu-web/src/main/java/org/apache/shenyu/web/loader/ShenyuLoaderService.java
index f9fad7f..d5ca071 100644
--- a/shenyu-web/src/main/java/org/apache/shenyu/web/loader/ShenyuLoaderService.java
+++ b/shenyu-web/src/main/java/org/apache/shenyu/web/loader/ShenyuLoaderService.java
@@ -41,31 +41,42 @@ public class ShenyuLoaderService {
     
     private static final Logger LOG = LoggerFactory.getLogger(ShenyuWebHandler.class);
     
+    private final ShenyuWebHandler webHandler;
+    
+    private final CommonPluginDataSubscriber subscriber;
+    
+    private final ShenyuConfig shenyuConfig;
+    
     /**
      * Instantiates a new Shenyu loader service.
      *
-     * @param webHandler the web handler
-     * @param subscriber the subscriber
+     * @param webHandler   the web handler
+     * @param subscriber   the subscriber
      * @param shenyuConfig the shenyu config
      */
     public ShenyuLoaderService(final ShenyuWebHandler webHandler, final CommonPluginDataSubscriber subscriber, final ShenyuConfig shenyuConfig) {
+        this.subscriber = subscriber;
+        this.webHandler = webHandler;
+        this.shenyuConfig = shenyuConfig;
         ExtPlugin config = shenyuConfig.getExtPlugin();
         if (config.getEnabled()) {
             ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(config.getThreads(), ShenyuThreadFactory.create("plugin-ext-loader", true));
-            executor.scheduleAtFixedRate(() -> {
-                try {
-                    List<ShenyuLoaderResult> results = ShenyuPluginLoader.getInstance().loadExtendPlugins(config.getPath());
-                    if (CollectionUtils.isEmpty(results)) {
-                        return;
-                    }
-                    List<ShenyuPlugin> shenyuExtendPlugins = results.stream().map(ShenyuLoaderResult::getShenyuPlugin).filter(Objects::nonNull).collect(Collectors.toList());
-                    webHandler.putExtPlugins(shenyuExtendPlugins);
-                    List<PluginDataHandler> handlers = results.stream().map(ShenyuLoaderResult::getPluginDataHandler).filter(Objects::nonNull).collect(Collectors.toList());
-                    subscriber.putExtendPluginDataHandler(handlers);
-                } catch (Exception e) {
-                    LOG.error("shenyu ext plugins load has error ", e);
-                }
-            }, config.getScheduleDelay(), config.getScheduleTime(), TimeUnit.SECONDS);
+            executor.scheduleAtFixedRate(this::loaderExtPlugins, config.getScheduleDelay(), config.getScheduleTime(), TimeUnit.SECONDS);
+        }
+    }
+    
+    private void loaderExtPlugins() {
+        try {
+            List<ShenyuLoaderResult> results = ShenyuPluginLoader.getInstance().loadExtendPlugins(shenyuConfig.getExtPlugin().getPath());
+            if (CollectionUtils.isEmpty(results)) {
+                return;
+            }
+            List<ShenyuPlugin> shenyuExtendPlugins = results.stream().map(ShenyuLoaderResult::getShenyuPlugin).filter(Objects::nonNull).collect(Collectors.toList());
+            webHandler.putExtPlugins(shenyuExtendPlugins);
+            List<PluginDataHandler> handlers = results.stream().map(ShenyuLoaderResult::getPluginDataHandler).filter(Objects::nonNull).collect(Collectors.toList());
+            subscriber.putExtendPluginDataHandler(handlers);
+        } catch (Exception e) {
+            LOG.error("shenyu ext plugins load has error ", e);
         }
     }
 }
diff --git a/shenyu-web/src/main/java/org/apache/shenyu/web/loader/ShenyuPluginLoader.java b/shenyu-web/src/main/java/org/apache/shenyu/web/loader/ShenyuPluginLoader.java
index 9f2ae84..1141f63 100644
--- a/shenyu-web/src/main/java/org/apache/shenyu/web/loader/ShenyuPluginLoader.java
+++ b/shenyu-web/src/main/java/org/apache/shenyu/web/loader/ShenyuPluginLoader.java
@@ -66,8 +66,6 @@ public final class ShenyuPluginLoader extends ClassLoader implements Closeable {
     
     private static volatile ShenyuPluginLoader pluginLoader;
     
-    private final ConcurrentHashMap<String, Object> objectPool = new ConcurrentHashMap<>();
-    
     private final ReentrantLock lock = new ReentrantLock();
     
     private final List<PluginJar> jars = Lists.newArrayList();
@@ -107,7 +105,7 @@ public final class ShenyuPluginLoader extends ClassLoader implements Closeable {
      * @throws IllegalAccessException the illegal access exception
      */
     public List<ShenyuLoaderResult> loadExtendPlugins(final String path) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {
-        File[] jarFiles = ShenyuPluginPathBuilder.getPluginPath(path).listFiles(file -> file.getName().endsWith(".jar"));
+        File[] jarFiles = ShenyuPluginPathBuilder.getPluginFile(path).listFiles(file -> file.getName().endsWith(".jar"));
         if (null == jarFiles) {
             return Collections.emptyList();
         }
@@ -134,9 +132,10 @@ public final class ShenyuPluginLoader extends ClassLoader implements Closeable {
                 instance = getOrCreateSpringBean(className);
                 if (Objects.nonNull(instance)) {
                     results.add(buildResult(instance));
+                    LOG.info("The class successfully loaded into a ext-plugin {} is registered as a spring bean", className);
                 }
             } catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
-                e.printStackTrace();
+                LOG.warn("Registering ext-plugins succeeds spring bean fails:{}", className);
             }
         });
         return results;
@@ -224,33 +223,31 @@ public final class ShenyuPluginLoader extends ClassLoader implements Closeable {
         }
     }
     
-    @SuppressWarnings("unchecked")
     private <T> T getOrCreateSpringBean(final String className) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
-        if (objectPool.containsKey(className)) {
-            return (T) objectPool.get(className);
+        if (SpringBeanUtils.getInstance().existBean(className)) {
+            return SpringBeanUtils.getInstance().getBeanByClassName(className);
         }
         lock.lock();
         try {
-            Object inst = objectPool.get(className);
+            T inst = SpringBeanUtils.getInstance().getBeanByClassName(className);
             if (Objects.isNull(inst)) {
                 Class<?> clazz = Class.forName(className, false, this);
                 Annotation[] annotations = clazz.getAnnotations();
-                boolean b = Arrays.stream(annotations).anyMatch(e -> e.annotationType().equals(Component.class) || e.annotationType().equals(Service.class));
-                if (b) {
+                boolean next = Arrays.stream(annotations).anyMatch(e -> e.annotationType().equals(Component.class)
+                        || e.annotationType().equals(Service.class));
+                if (next) {
                     GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
                     beanDefinition.setBeanClassName(className);
                     beanDefinition.setAutowireCandidate(true);
                     beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
-                    String bean = SpringBeanUtils.getInstance().registerBean(beanDefinition, this);
-                    inst = SpringBeanUtils.getInstance().getBean(bean);
-                    objectPool.put(className, inst);
-                    return (T) inst;
+                    String beanName = SpringBeanUtils.getInstance().registerBean(beanDefinition, this);
+                    inst = SpringBeanUtils.getInstance().getBeanByClassName(beanName);
                 }
             }
+            return inst;
         } finally {
             lock.unlock();
         }
-        return null;
     }
     
     private ShenyuLoaderResult buildResult(final Object instance) {
diff --git a/shenyu-web/src/main/java/org/apache/shenyu/web/loader/ShenyuPluginPathBuilder.java b/shenyu-web/src/main/java/org/apache/shenyu/web/loader/ShenyuPluginPathBuilder.java
index 213b359..5b7fa32 100644
--- a/shenyu-web/src/main/java/org/apache/shenyu/web/loader/ShenyuPluginPathBuilder.java
+++ b/shenyu-web/src/main/java/org/apache/shenyu/web/loader/ShenyuPluginPathBuilder.java
@@ -27,11 +27,21 @@ import java.util.Optional;
  * The type Shenyu plugin path builder.
  */
 public final class ShenyuPluginPathBuilder {
-
+    
     private static final String PLUGIN_PATH = "plugin-ext";
     
     private static final String DEFAULT_EXT_PLUGIN_PATH = "/ext-lib/";
-
+    
+    /**
+     * Gets plugin file.
+     *
+     * @param path the path
+     * @return the plugin jar file.
+     */
+    public static File getPluginFile(final String path) {
+        String pluginPath = getPluginPath(path);
+        return new File(pluginPath);
+    }
     
     /**
      * Gets plugin path.
@@ -39,20 +49,15 @@ public final class ShenyuPluginPathBuilder {
      * @param path the path
      * @return the plugin path
      */
-    public static File getPluginPath(final String path) {
+    public static String getPluginPath(final String path) {
         if (StringUtils.isNotEmpty(path)) {
-            return new File(path);
+            return path;
         }
         String pluginPath = System.getProperty(PLUGIN_PATH);
         if (StringUtils.isNotEmpty(pluginPath)) {
-            return new File(pluginPath);
+            return pluginPath;
         }
-        return buildPluginJarPath();
+        URL resource = ShenyuPluginPathBuilder.class.getResource(DEFAULT_EXT_PLUGIN_PATH);
+        return Optional.ofNullable(resource).map(URL::getPath).orElse(DEFAULT_EXT_PLUGIN_PATH);
     }
-    
-    private static File buildPluginJarPath() {
-        URL url = ShenyuPluginPathBuilder.class.getResource(DEFAULT_EXT_PLUGIN_PATH);
-        return Optional.ofNullable(url).map(u -> new File(u.getFile())).orElse(new File(DEFAULT_EXT_PLUGIN_PATH));
-    }
-
 }
diff --git a/shenyu-web/src/test/java/org/apache/shenyu/web/loader/ShenyuPluginLoaderTest.java b/shenyu-web/src/test/java/org/apache/shenyu/web/loader/ShenyuPluginLoaderTest.java
index d410ff2..8899aec 100644
--- a/shenyu-web/src/test/java/org/apache/shenyu/web/loader/ShenyuPluginLoaderTest.java
+++ b/shenyu-web/src/test/java/org/apache/shenyu/web/loader/ShenyuPluginLoaderTest.java
@@ -17,24 +17,26 @@
 
 package org.apache.shenyu.web.loader;
 
+import org.apache.shenyu.plugin.api.utils.SpringBeanUtils;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
+import org.springframework.context.ApplicationContext;
 
 import java.io.BufferedOutputStream;
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
-import java.lang.reflect.Field;
 import java.util.List;
-import java.util.concurrent.ConcurrentHashMap;
 import java.util.jar.JarOutputStream;
 import java.util.zip.ZipEntry;
 
 import static org.hamcrest.CoreMatchers.is;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
 
 /**
  * Test for  ShenyuPluginLoader.
@@ -42,11 +44,11 @@ import static org.mockito.Mockito.spy;
 public class ShenyuPluginLoaderTest {
     @Rule
     public TemporaryFolder folder = new TemporaryFolder();
-
+    
     private ShenyuPluginLoader shenyuPluginLoader;
-
+    
     private String path;
-
+    
     @Before
     public void setUp() throws IOException, NoSuchFieldException, IllegalAccessException {
         shenyuPluginLoader = ShenyuPluginLoader.getInstance();
@@ -60,25 +62,34 @@ public class ShenyuPluginLoaderTest {
             jos.write(pluginClz.getBytes());
             jos.closeEntry();
         }
-
-        Field objectPool = shenyuPluginLoader.getClass().getDeclaredField("objectPool");
-        objectPool.setAccessible(true);
-        ConcurrentHashMap<String, Object> objectPoolMap = new ConcurrentHashMap<>();
-        objectPoolMap.put("org.apache.shenyu.plugin.DividePlugin", new Object());
-        objectPool.set(shenyuPluginLoader, objectPoolMap);
+        ApplicationContext mockApplication =
+                mock(ApplicationContext.class);
+        when(mockApplication.getBean("dividePlugin")).thenReturn(new Object());
+        when(mockApplication.containsBean("dividePlugin")).thenReturn(true);
+        SpringBeanUtils instance = SpringBeanUtils.getInstance();
+        instance.setApplicationContext(mockApplication);
+        
     }
-
+    
+    @Test
+    public void testGetBean() {
+        boolean exist = SpringBeanUtils.getInstance().existBean("dividePlugin");
+        Assert.assertTrue(exist);
+        Object dividePlugin = SpringBeanUtils.getInstance().getBean("dividePlugin");
+        Assert.assertNotNull(dividePlugin);
+    }
+    
     @Test
     public void testGetInstance() {
         Assert.assertThat(shenyuPluginLoader, is(ShenyuPluginLoader.getInstance()));
     }
-
+    
     @Test
     public void testGetPluginPathWithNoJar() throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {
         List<ShenyuLoaderResult> pluginList = shenyuPluginLoader.loadExtendPlugins("test");
         Assert.assertThat(pluginList.size(), is(0));
     }
-
+    
     @Test
     public void testGetPluginPathWithJar() throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {
         ShenyuPluginLoader loader = spy(shenyuPluginLoader);
diff --git a/shenyu-web/src/test/java/org/apache/shenyu/web/loader/ShenyuPluginPathBuilderTest.java b/shenyu-web/src/test/java/org/apache/shenyu/web/loader/ShenyuPluginPathBuilderTest.java
index a6a4d82..a64007b 100644
--- a/shenyu-web/src/test/java/org/apache/shenyu/web/loader/ShenyuPluginPathBuilderTest.java
+++ b/shenyu-web/src/test/java/org/apache/shenyu/web/loader/ShenyuPluginPathBuilderTest.java
@@ -26,17 +26,17 @@ import java.io.File;
  * Test for  ShenyuPluginPathBuilder.
  */
 public final class ShenyuPluginPathBuilderTest {
-
-
+    
+    
     /**
      * test for  Custom path.
      */
     @Test
     public void testGetPluginPathByCustomPath() {
-        File pluginPath = ShenyuPluginPathBuilder.getPluginPath("/testpath");
-        Assert.assertNotNull(pluginPath);
+        File jarFile = ShenyuPluginPathBuilder.getPluginFile("/testpath");
+        Assert.assertNotNull(jarFile);
     }
-
+    
     /**
      * test  for plugin-ext.
      * -Dplugin-ext=D:\testUrl
@@ -44,16 +44,16 @@ public final class ShenyuPluginPathBuilderTest {
     @Test
     public void testGetPluginPathByPluginExt() {
         System.setProperty("plugin-ext", "/testUrl");
-        File pluginPath = ShenyuPluginPathBuilder.getPluginPath("");
-        Assert.assertNotNull(pluginPath);
+        File jarFile = ShenyuPluginPathBuilder.getPluginFile("");
+        Assert.assertNotNull(jarFile);
     }
-
+    
     /**
      * test for default path.
      */
     @Test
     public void testGetPluginPathByExtLib() {
-        File pluginPath = ShenyuPluginPathBuilder.getPluginPath("");
-        Assert.assertNotNull(pluginPath);
+        File jarFile = ShenyuPluginPathBuilder.getPluginFile("");
+        Assert.assertNotNull(jarFile);
     }
 }