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