You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by li...@apache.org on 2021/10/29 00:52:39 UTC

[dubbo] branch 3.0 updated: support destroy scope bean and spi extension instance (#9155)

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

liujun pushed a commit to branch 3.0
in repository https://gitbox.apache.org/repos/asf/dubbo.git


The following commit(s) were added to refs/heads/3.0 by this push:
     new 5ab9afd  support destroy scope bean and spi extension instance (#9155)
5ab9afd is described below

commit 5ab9afdf0c2c2f7b873ef8afe1a0809d9bc5269d
Author: Gong Dewei <ky...@qq.com>
AuthorDate: Fri Oct 29 08:52:20 2021 +0800

    support destroy scope bean and spi extension instance (#9155)
---
 .../common/beans/factory/ScopeBeanFactory.java     | 19 +++++++++++++++++
 .../org/apache/dubbo/common/context/Lifecycle.java |  4 +++-
 .../dubbo/common/extension/ExtensionDirector.java  |  7 +++++++
 .../dubbo/common/extension/ExtensionLoader.java    | 24 +++++++++++++++++-----
 .../org/apache/dubbo/rpc/model/ScopeModel.java     |  6 ++++++
 .../dubbo/common/beans/ScopeBeanFactoryTest.java   |  8 ++++++++
 .../beans/model/FooBeanWithApplicationModel.java   | 13 +++++++++++-
 .../beans/model/FooBeanWithFrameworkModel.java     | 13 +++++++++++-
 .../common/extension/ExtensionDirectorTest.java    |  9 ++++++++
 .../extension/director/impl/BaseTestService.java   | 15 ++++++++++++--
 10 files changed, 108 insertions(+), 10 deletions(-)

diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/beans/factory/ScopeBeanFactory.java b/dubbo-common/src/main/java/org/apache/dubbo/common/beans/factory/ScopeBeanFactory.java
index 8a659de..d55df7f 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/beans/factory/ScopeBeanFactory.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/beans/factory/ScopeBeanFactory.java
@@ -21,6 +21,9 @@ import org.apache.dubbo.common.beans.support.InstantiationStrategy;
 import org.apache.dubbo.common.extension.ExtensionAccessor;
 import org.apache.dubbo.common.extension.ExtensionAccessorAware;
 import org.apache.dubbo.common.extension.ExtensionPostProcessor;
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.common.resource.Disposable;
 import org.apache.dubbo.common.utils.StringUtils;
 import org.apache.dubbo.rpc.model.ScopeModelAccessor;
 
@@ -38,6 +41,8 @@ import java.util.stream.Collectors;
  */
 public class ScopeBeanFactory {
 
+    protected static final Logger LOGGER = LoggerFactory.getLogger(ScopeBeanFactory.class);
+
     private final ScopeBeanFactory parent;
     private ExtensionAccessor extensionAccessor;
     private List<ExtensionPostProcessor> extensionPostProcessors;
@@ -227,6 +232,20 @@ public class ScopeBeanFactory {
         return null;
     }
 
+    public void destroy() {
+        for (BeanInfo beanInfo : registeredBeanInfos) {
+            if (beanInfo.instance instanceof Disposable) {
+                try {
+                    Disposable beanInstance = (Disposable) beanInfo.instance;
+                    beanInstance.destroy();
+                } catch (Throwable e) {
+                    LOGGER.error("An error occurred when destroy bean [name=" + beanInfo.name + ", bean=" + beanInfo.instance + "]: " + e, e);
+                }
+            }
+        }
+        registeredBeanInfos.clear();
+    }
+
     static class BeanInfo {
         private String name;
         private Object instance;
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/context/Lifecycle.java b/dubbo-common/src/main/java/org/apache/dubbo/common/context/Lifecycle.java
index 8f8a273..b3ca3bb 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/context/Lifecycle.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/context/Lifecycle.java
@@ -16,12 +16,14 @@
  */
 package org.apache.dubbo.common.context;
 
+import org.apache.dubbo.common.resource.Disposable;
+
 /**
  * The Lifecycle of Dubbo component
  *
  * @since 2.7.5
  */
-public interface Lifecycle {
+public interface Lifecycle extends Disposable {
 
     /**
      * Initialize the component before {@link #start() start}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionDirector.java b/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionDirector.java
index d65228a..1cb0e3f 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionDirector.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionDirector.java
@@ -132,4 +132,11 @@ public class ExtensionDirector implements ExtensionAccessor {
     public void removeAllCachedLoader() {
         // extensionLoadersMap.clear();
     }
+
+    public void destroy() {
+        for (ExtensionLoader<?> extensionLoader : extensionLoadersMap.values()) {
+            extensionLoader.destroy();
+        }
+        extensionLoadersMap.clear();
+    }
 }
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionLoader.java b/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionLoader.java
index d1dcaae..8fa6132 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionLoader.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionLoader.java
@@ -26,6 +26,7 @@ import org.apache.dubbo.common.extension.support.WrapperComparator;
 import org.apache.dubbo.common.lang.Prioritized;
 import org.apache.dubbo.common.logger.Logger;
 import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.common.resource.Disposable;
 import org.apache.dubbo.common.utils.ArrayUtils;
 import org.apache.dubbo.common.utils.ClassLoaderResourceLoader;
 import org.apache.dubbo.common.utils.ClassUtils;
@@ -215,19 +216,32 @@ public class ExtensionLoader<T> {
     }
 
     public void destroy() {
+        // destroy raw extension instance
         extensionInstances.forEach((type, instance) -> {
-            if (instance instanceof Lifecycle) {
-                Lifecycle lifecycle = (Lifecycle) instance;
+            if (instance instanceof Disposable) {
+                Disposable disposable = (Disposable) instance;
                 try {
-                    lifecycle.destroy();
+                    disposable.destroy();
                 } catch (Exception e) {
-                    logger.error("Error destroying extension " + lifecycle, e);
+                    logger.error("Error destroying extension " + disposable, e);
                 }
             }
         });
         extensionInstances.clear();
 
-        // TODO destroy extension loader, release resources.
+        // destroy wrapped extension instance
+        for (Holder<Object> holder : cachedInstances.values()) {
+            Object wrappedInstance = holder.get();
+            if (wrappedInstance instanceof Disposable) {
+                Disposable disposable = (Disposable) wrappedInstance;
+                try {
+                    disposable.destroy();
+                } catch (Exception e) {
+                    logger.error("Error destroying extension " + disposable, e);
+                }
+            }
+        }
+        cachedInstances.clear();
     }
 
     private static ClassLoader findClassLoader() {
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ScopeModel.java b/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ScopeModel.java
index e4bdcfb..9e3559a 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ScopeModel.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ScopeModel.java
@@ -107,6 +107,12 @@ public abstract class ScopeModel implements ExtensionAccessor {
                 for (ClassLoader classLoader : copyOfClassLoaders) {
                     removeClassLoader(classLoader);
                 }
+                if (beanFactory != null) {
+                    beanFactory.destroy();
+                }
+                if (extensionDirector != null) {
+                    extensionDirector.destroy();
+                }
             } catch (Throwable t) {
                 LOGGER.error("Error happened when destroying ScopeModel.", t);
             }
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/beans/ScopeBeanFactoryTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/beans/ScopeBeanFactoryTest.java
index 573b458..3f95fa8 100644
--- a/dubbo-common/src/test/java/org/apache/dubbo/common/beans/ScopeBeanFactoryTest.java
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/beans/ScopeBeanFactoryTest.java
@@ -44,5 +44,13 @@ public class ScopeBeanFactoryTest {
 
         Object objectBean = applicationModel.getBeanFactory().getBean(Object.class);
         Assertions.assertNull(objectBean);
+
+        Assertions.assertFalse(beanWithApplicationModel.isDestroyed());
+        Assertions.assertFalse(beanWithFrameworkModel.isDestroyed());
+
+        // destroy
+        frameworkModel.destroy();
+        Assertions.assertTrue(beanWithApplicationModel.isDestroyed());
+        Assertions.assertTrue(beanWithFrameworkModel.isDestroyed());
     }
 }
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/beans/model/FooBeanWithApplicationModel.java b/dubbo-common/src/test/java/org/apache/dubbo/common/beans/model/FooBeanWithApplicationModel.java
index f103f7a..c580474 100644
--- a/dubbo-common/src/test/java/org/apache/dubbo/common/beans/model/FooBeanWithApplicationModel.java
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/beans/model/FooBeanWithApplicationModel.java
@@ -16,10 +16,12 @@
  */
 package org.apache.dubbo.common.beans.model;
 
+import org.apache.dubbo.common.resource.Disposable;
 import org.apache.dubbo.rpc.model.ApplicationModel;
 
-public class FooBeanWithApplicationModel {
+public class FooBeanWithApplicationModel implements Disposable {
     private ApplicationModel applicationModel;
+    private boolean destroyed;
 
     public FooBeanWithApplicationModel(ApplicationModel applicationModel) {
         this.applicationModel = applicationModel;
@@ -28,4 +30,13 @@ public class FooBeanWithApplicationModel {
     public ApplicationModel getApplicationModel() {
         return applicationModel;
     }
+
+    @Override
+    public void destroy() {
+        this.destroyed = true;
+    }
+
+    public boolean isDestroyed() {
+        return destroyed;
+    }
 }
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/beans/model/FooBeanWithFrameworkModel.java b/dubbo-common/src/test/java/org/apache/dubbo/common/beans/model/FooBeanWithFrameworkModel.java
index d7e357a..e934185 100644
--- a/dubbo-common/src/test/java/org/apache/dubbo/common/beans/model/FooBeanWithFrameworkModel.java
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/beans/model/FooBeanWithFrameworkModel.java
@@ -16,10 +16,12 @@
  */
 package org.apache.dubbo.common.beans.model;
 
+import org.apache.dubbo.common.resource.Disposable;
 import org.apache.dubbo.rpc.model.FrameworkModel;
 
-public class FooBeanWithFrameworkModel {
+public class FooBeanWithFrameworkModel implements Disposable {
     private FrameworkModel frameworkModel;
+    private boolean destroyed;
 
     public FooBeanWithFrameworkModel(FrameworkModel frameworkModel) {
         this.frameworkModel = frameworkModel;
@@ -28,4 +30,13 @@ public class FooBeanWithFrameworkModel {
     public FrameworkModel getFrameworkModel() {
         return frameworkModel;
     }
+
+    @Override
+    public void destroy() {
+        this.destroyed = true;
+    }
+
+    public boolean isDestroyed() {
+        return destroyed;
+    }
 }
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/extension/ExtensionDirectorTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/extension/ExtensionDirectorTest.java
index e0031d4..372c3f5 100644
--- a/dubbo-common/src/test/java/org/apache/dubbo/common/extension/ExtensionDirectorTest.java
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/extension/ExtensionDirectorTest.java
@@ -265,5 +265,14 @@ public class ExtensionDirectorTest {
         Assertions.assertNull(frameworkService.getAppProvider());
         Assertions.assertNull(frameworkService.getModuleProvider());
 
+        Assertions.assertFalse(moduleService.isDestroyed());
+        Assertions.assertFalse(appService.isDestroyed());
+        Assertions.assertFalse(frameworkService.isDestroyed());
+
+        // destroy
+        frameworkModel.destroy();
+        Assertions.assertTrue(moduleService.isDestroyed());
+        Assertions.assertTrue(appService.isDestroyed());
+        Assertions.assertTrue(frameworkService.isDestroyed());
     }
 }
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/extension/director/impl/BaseTestService.java b/dubbo-common/src/test/java/org/apache/dubbo/common/extension/director/impl/BaseTestService.java
index e3171a4..97944e9 100644
--- a/dubbo-common/src/test/java/org/apache/dubbo/common/extension/director/impl/BaseTestService.java
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/extension/director/impl/BaseTestService.java
@@ -16,15 +16,17 @@
  */
 package org.apache.dubbo.common.extension.director.impl;
 
+import org.apache.dubbo.common.resource.Disposable;
 import org.apache.dubbo.rpc.model.ApplicationModel;
 import org.apache.dubbo.rpc.model.FrameworkModel;
-import org.apache.dubbo.rpc.model.ScopeModelAware;
 import org.apache.dubbo.rpc.model.ModuleModel;
+import org.apache.dubbo.rpc.model.ScopeModelAware;
 
-public class BaseTestService implements ScopeModelAware {
+public class BaseTestService implements ScopeModelAware, Disposable {
     private FrameworkModel frameworkModel;
     private ApplicationModel applicationModel;
     private ModuleModel moduleModel;
+    private volatile boolean destroyed;
 
     @Override
     public void setFrameworkModel(FrameworkModel frameworkModel) {
@@ -52,4 +54,13 @@ public class BaseTestService implements ScopeModelAware {
     public ModuleModel getModuleModel() {
         return moduleModel;
     }
+
+    @Override
+    public void destroy() {
+        this.destroyed = true;
+    }
+
+    public boolean isDestroyed() {
+        return destroyed;
+    }
 }