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 7f5c03f10c fix(web): unregister removed ext plugins (#7196)
7f5c03f10c is described below

commit 7f5c03f10cf5bca9cd63bb3e9c697960c9465d88
Author: Liming Deng <[email protected]>
AuthorDate: Thu Sep 24 22:02:28 2026 +0800

    fix(web): unregister removed ext plugins (#7196)
    
    Co-authored-by: aias00 <[email protected]>
---
 .../shenyu/web/handler/ShenyuWebHandler.java       | 15 ++++++++
 .../web/loader/ShenyuExtPathPluginJarLoader.java   | 42 +++++++++++++++++++---
 .../shenyu/web/loader/ShenyuLoaderService.java     |  6 ++--
 .../shenyu/web/loader/ShenyuPluginClassLoader.java | 17 ++++++++-
 .../web/loader/ShenyuPluginClassLoaderHolder.java  | 14 ++++++--
 .../shenyu/web/handler/ShenyuWebHandlerTest.java   |  8 +++++
 6 files changed, 92 insertions(+), 10 deletions(-)

diff --git 
a/shenyu-web/src/main/java/org/apache/shenyu/web/handler/ShenyuWebHandler.java 
b/shenyu-web/src/main/java/org/apache/shenyu/web/handler/ShenyuWebHandler.java
index 3bb84adcfc..d26861764f 100644
--- 
a/shenyu-web/src/main/java/org/apache/shenyu/web/handler/ShenyuWebHandler.java
+++ 
b/shenyu-web/src/main/java/org/apache/shenyu/web/handler/ShenyuWebHandler.java
@@ -44,6 +44,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
+import java.util.Set;
 import java.util.stream.Collectors;
 
 /**
@@ -190,6 +191,20 @@ public final class ShenyuWebHandler implements WebHandler, 
ApplicationListener<P
         plugins = sortPlugins(newPluginList);
     }
 
+    /**
+     * Remove ext plugins.
+     *
+     * @param pluginNames plugin names
+     */
+    public synchronized void removeExtPlugins(final Set<String> pluginNames) {
+        if (CollectionUtils.isEmpty(pluginNames)) {
+            return;
+        }
+        pluginNames.forEach(pluginName -> LOG.info("shenyu auto remove extends 
plugin:{}", pluginName));
+        sourcePlugins.removeIf(plugin -> pluginNames.contains(plugin.named()));
+        plugins = plugins.stream().filter(plugin -> 
!pluginNames.contains(plugin.named())).collect(Collectors.toList());
+    }
+
     /**
      * listen plugin handler event and handle plugin.
      *
diff --git 
a/shenyu-web/src/main/java/org/apache/shenyu/web/loader/ShenyuExtPathPluginJarLoader.java
 
b/shenyu-web/src/main/java/org/apache/shenyu/web/loader/ShenyuExtPathPluginJarLoader.java
index 0113b9d2e4..1ec0f36a32 100644
--- 
a/shenyu-web/src/main/java/org/apache/shenyu/web/loader/ShenyuExtPathPluginJarLoader.java
+++ 
b/shenyu-web/src/main/java/org/apache/shenyu/web/loader/ShenyuExtPathPluginJarLoader.java
@@ -41,10 +41,10 @@ public class ShenyuExtPathPluginJarLoader {
      * @return the list
      * @throws IOException the io exception
      */
-    public static synchronized List<PluginJarParser.PluginJar> 
loadExtendPlugins(final String path) throws IOException {
+    public static synchronized ExtPluginLoadResult loadExtendPlugins(final 
String path) throws IOException {
         File[] jarFiles = 
ShenyuPluginPathBuilder.getPluginFile(path).listFiles(file -> 
file.getName().endsWith(".jar"));
         if (Objects.isNull(jarFiles)) {
-            return Collections.emptyList();
+            return new ExtPluginLoadResult(Collections.emptyList(), 
Collections.emptySet());
         }
         List<PluginJarParser.PluginJar> uploadPluginJars = new ArrayList<>();
         Set<String> currentPaths = new HashSet<>();
@@ -60,11 +60,45 @@ public class ShenyuExtPathPluginJarLoader {
             uploadPluginJars.add(uploadPluginJar);
         }
         Sets.SetView<String> removePluginSet = Sets.difference(pluginJarName, 
currentPaths);
+        Set<String> removedPluginNames = new HashSet<>();
         for (String removePath : removePluginSet) {
-            
ShenyuPluginClassLoaderHolder.getSingleton().removePluginClassLoader(removePath);
+            
removedPluginNames.addAll(ShenyuPluginClassLoaderHolder.getSingleton().removePluginClassLoader(removePath));
         }
         pluginJarName = currentPaths;
-        return uploadPluginJars;
+        return new ExtPluginLoadResult(uploadPluginJars, removedPluginNames);
+    }
+
+    /**
+     * Ext plugin load result.
+     */
+    public static final class ExtPluginLoadResult {
+
+        private final List<PluginJarParser.PluginJar> pluginJars;
+
+        private final Set<String> removedPluginNames;
+
+        private ExtPluginLoadResult(final List<PluginJarParser.PluginJar> 
pluginJars, final Set<String> removedPluginNames) {
+            this.pluginJars = pluginJars;
+            this.removedPluginNames = removedPluginNames;
+        }
+
+        /**
+         * Get plugin jars.
+         *
+         * @return plugin jars
+         */
+        public List<PluginJarParser.PluginJar> getPluginJars() {
+            return pluginJars;
+        }
+
+        /**
+         * Get removed plugin names.
+         *
+         * @return removed plugin names
+         */
+        public Set<String> getRemovedPluginNames() {
+            return removedPluginNames;
+        }
     }
 
 }
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 24b135de66..5776ec3817 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
@@ -26,6 +26,7 @@ import org.apache.shenyu.plugin.api.ShenyuPlugin;
 import org.apache.shenyu.plugin.base.cache.CommonPluginDataSubscriber;
 import org.apache.shenyu.plugin.base.handler.PluginDataHandler;
 import org.apache.shenyu.web.handler.ShenyuWebHandler;
+import 
org.apache.shenyu.web.loader.ShenyuExtPathPluginJarLoader.ExtPluginLoadResult;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -78,8 +79,9 @@ public class ShenyuLoaderService {
             List<ShenyuLoaderResult> plugins = new ArrayList<>();
             ShenyuPluginClassLoaderHolder singleton = 
ShenyuPluginClassLoaderHolder.getSingleton();
             if (Objects.isNull(uploadedJarResource)) {
-                List<PluginJarParser.PluginJar> uploadPluginJars = 
ShenyuExtPathPluginJarLoader.loadExtendPlugins(shenyuConfig.getExtPlugin().getPath());
-                for (PluginJarParser.PluginJar extPath : uploadPluginJars) {
+                ExtPluginLoadResult loadResult = 
ShenyuExtPathPluginJarLoader.loadExtendPlugins(shenyuConfig.getExtPlugin().getPath());
+                
webHandler.removeExtPlugins(loadResult.getRemovedPluginNames());
+                for (PluginJarParser.PluginJar extPath : 
loadResult.getPluginJars()) {
                     LOG.info("shenyu extPlugin find new {} to load", 
extPath.getAbsolutePath());
                     ShenyuPluginClassLoader extPathClassLoader = 
singleton.createPluginClassLoader(extPath);
                     
plugins.addAll(extPathClassLoader.loadUploadedJarPlugins());
diff --git 
a/shenyu-web/src/main/java/org/apache/shenyu/web/loader/ShenyuPluginClassLoader.java
 
b/shenyu-web/src/main/java/org/apache/shenyu/web/loader/ShenyuPluginClassLoader.java
index fe705f36b6..bf4e74b8bc 100644
--- 
a/shenyu-web/src/main/java/org/apache/shenyu/web/loader/ShenyuPluginClassLoader.java
+++ 
b/shenyu-web/src/main/java/org/apache/shenyu/web/loader/ShenyuPluginClassLoader.java
@@ -56,6 +56,8 @@ public final class ShenyuPluginClassLoader extends 
ClassLoader implements Closea
 
     private final Map<String, byte[]> resourceCache = new 
ConcurrentHashMap<>();
 
+    private final Set<String> loadedPluginNames = 
ConcurrentHashMap.newKeySet();
+
     private final PluginJarParser.PluginJar pluginJar;
 
     public ShenyuPluginClassLoader(final PluginJarParser.PluginJar pluginJar) {
@@ -90,7 +92,11 @@ public final class ShenyuPluginClassLoader extends 
ClassLoader implements Closea
             try {
                 instance = getOrCreateSpringBean(className);
                 if (Objects.nonNull(instance)) {
-                    results.add(buildResult(instance));
+                    ShenyuLoaderResult result = buildResult(instance);
+                    results.add(result);
+                    if (Objects.nonNull(result.getShenyuPlugin())) {
+                        
loadedPluginNames.add(result.getShenyuPlugin().named());
+                    }
                     LOG.info("The class successfully loaded into a 
upload-Jar-plugin {} is registered as a spring bean", className);
                 }
             } catch (ClassNotFoundException | IllegalAccessException | 
InstantiationException e) {
@@ -218,4 +224,13 @@ public final class ShenyuPluginClassLoader extends 
ClassLoader implements Closea
         return pluginJar.getVersion().equals(version);
     }
 
+    /**
+     * Get loaded plugin names.
+     *
+     * @return loaded plugin names
+     */
+    public Set<String> getLoadedPluginNames() {
+        return Set.copyOf(loadedPluginNames);
+    }
+
 }
diff --git 
a/shenyu-web/src/main/java/org/apache/shenyu/web/loader/ShenyuPluginClassLoaderHolder.java
 
b/shenyu-web/src/main/java/org/apache/shenyu/web/loader/ShenyuPluginClassLoaderHolder.java
index 388911914c..d5af90eafb 100644
--- 
a/shenyu-web/src/main/java/org/apache/shenyu/web/loader/ShenyuPluginClassLoaderHolder.java
+++ 
b/shenyu-web/src/main/java/org/apache/shenyu/web/loader/ShenyuPluginClassLoaderHolder.java
@@ -17,8 +17,11 @@
 
 package org.apache.shenyu.web.loader;
 
+import java.util.Collections;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Optional;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 
 /**
@@ -62,11 +65,16 @@ public final class ShenyuPluginClassLoaderHolder {
      * removePluginClassLoader.
      *
      * @param jarKey jarKey
+     * @return removed plugin names
      */
-    public void removePluginClassLoader(final String jarKey) {
-        if (pluginCache.containsKey(jarKey)) {
-            pluginCache.remove(jarKey).close();
+    public Set<String> removePluginClassLoader(final String jarKey) {
+        ShenyuPluginClassLoader classLoader = pluginCache.remove(jarKey);
+        if (Objects.nonNull(classLoader)) {
+            Set<String> pluginNames = classLoader.getLoadedPluginNames();
+            classLoader.close();
+            return pluginNames;
         }
+        return Collections.emptySet();
     }
 
 }
diff --git 
a/shenyu-web/src/test/java/org/apache/shenyu/web/handler/ShenyuWebHandlerTest.java
 
b/shenyu-web/src/test/java/org/apache/shenyu/web/handler/ShenyuWebHandlerTest.java
index 2b366f22cf..5234706fde 100644
--- 
a/shenyu-web/src/test/java/org/apache/shenyu/web/handler/ShenyuWebHandlerTest.java
+++ 
b/shenyu-web/src/test/java/org/apache/shenyu/web/handler/ShenyuWebHandlerTest.java
@@ -44,6 +44,7 @@ import java.net.InetSocketAddress;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Set;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
@@ -100,6 +101,13 @@ public final class ShenyuWebHandlerTest {
         
assertTrue(Modifier.isSynchronized(ShenyuWebHandler.class.getMethod("putExtPlugins",
 List.class).getModifiers()));
     }
 
+    @Test
+    public void removeExtPlugins() {
+        shenyuWebHandler.removeExtPlugins(Collections.emptySet());
+        shenyuWebHandler.removeExtPlugins(Set.of(plugin1.named()));
+        assertEquals(Collections.singletonList(plugin2), 
shenyuWebHandler.getPlugins());
+    }
+
     @Test
     public void scheduledEnableTest() {
         final ServerWebExchange exchange = 
MockServerWebExchange.from(MockServerHttpRequest.get("localhost")

Reply via email to