You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by al...@apache.org on 2021/10/30 02:28:02 UTC

[dubbo] branch 3.0 updated: check destroyed of bean factory and extension (#9165)

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

albumenj 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 b4e8d15  check destroyed of bean factory and extension (#9165)
b4e8d15 is described below

commit b4e8d15efde1d140470e7f4d445f4c579d81ee44
Author: Gong Dewei <ky...@qq.com>
AuthorDate: Sat Oct 30 10:27:52 2021 +0800

    check destroyed of bean factory and extension (#9165)
---
 .../common/beans/factory/ScopeBeanFactory.java     | 30 ++++++++++++++++------
 .../dubbo/common/extension/ExtensionDirector.java  | 18 ++++++++++---
 .../dubbo/common/extension/ExtensionLoader.java    | 23 +++++++++++++++++
 3 files changed, 60 insertions(+), 11 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 d55df7f..e34ea8a 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
@@ -32,6 +32,7 @@ import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.Function;
 import java.util.stream.Collectors;
@@ -49,6 +50,7 @@ public class ScopeBeanFactory {
     private Map<Class, AtomicInteger> beanNameIdCounterMap = new ConcurrentHashMap<>();
     private List<BeanInfo> registeredBeanInfos = Collections.synchronizedList(new ArrayList<>());
     private InstantiationStrategy instantiationStrategy;
+    private AtomicBoolean destroyed = new AtomicBoolean();
 
     public ScopeBeanFactory(ScopeBeanFactory parent, ExtensionAccessor extensionAccessor) {
         this.parent = parent;
@@ -78,6 +80,7 @@ public class ScopeBeanFactory {
     }
 
     private <T> T createAndRegisterBean(String name, Class<T> clazz) {
+        checkDestroyed();
         T instance = getBean(name, clazz);
         if (instance != null) {
             throw new ScopeBeanException("already exists bean with same name and type, name=" + name + ", type=" + clazz.getName());
@@ -96,6 +99,7 @@ public class ScopeBeanFactory {
     }
 
     public void registerBean(String name, Object bean) {
+        checkDestroyed();
         // avoid duplicated register same bean
         if (containsBean(name, bean)) {
             return;
@@ -153,6 +157,7 @@ public class ScopeBeanFactory {
     }
 
     private void initializeBean(String name, Object bean) {
+        checkDestroyed();
         try {
             if (bean instanceof ExtensionAccessorAware) {
                 ((ExtensionAccessorAware) bean).setExtensionAccessor(extensionAccessor);
@@ -192,6 +197,7 @@ public class ScopeBeanFactory {
     }
 
     private <T> T getBeanInternal(String name, Class<T> type) {
+        checkDestroyed();
         // All classes are derived from java.lang.Object, cannot filter bean by it
         if (type == Object.class) {
             return null;
@@ -233,17 +239,25 @@ public class ScopeBeanFactory {
     }
 
     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);
+        if (destroyed.compareAndSet(false, true)){
+            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();
+        }
+    }
+
+    private void checkDestroyed() {
+        if (destroyed.get()) {
+            throw new IllegalStateException("ScopeBeanFactory is destroyed");
         }
-        registeredBeanInfos.clear();
     }
 
     static class BeanInfo {
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 1cb0e3f..0fd29a2 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
@@ -22,6 +22,7 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * ExtensionDirector is a scoped extension loader manager.
@@ -37,6 +38,7 @@ public class ExtensionDirector implements ExtensionAccessor {
     private final ExtensionScope scope;
     private List<ExtensionPostProcessor> extensionPostProcessors = new ArrayList<>();
     private ScopeModel scopeModel;
+    private AtomicBoolean destroyed = new AtomicBoolean();
 
     public ExtensionDirector(ExtensionDirector parent, ExtensionScope scope, ScopeModel scopeModel) {
         this.parent = parent;
@@ -61,6 +63,7 @@ public class ExtensionDirector implements ExtensionAccessor {
 
     @Override
     public <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
+        checkDestroyed();
         if (type == null) {
             throw new IllegalArgumentException("Extension type == null");
         }
@@ -110,6 +113,7 @@ public class ExtensionDirector implements ExtensionAccessor {
     }
 
     private <T> ExtensionLoader<T> createExtensionLoader0(Class<T> type) {
+        checkDestroyed();
         ExtensionLoader<T> loader;
         extensionLoadersMap.putIfAbsent(type, new ExtensionLoader<T>(type, this, scopeModel));
         loader = (ExtensionLoader<T>) extensionLoadersMap.get(type);
@@ -134,9 +138,17 @@ public class ExtensionDirector implements ExtensionAccessor {
     }
 
     public void destroy() {
-        for (ExtensionLoader<?> extensionLoader : extensionLoadersMap.values()) {
-            extensionLoader.destroy();
+        if (destroyed.compareAndSet(false, true)) {
+            for (ExtensionLoader<?> extensionLoader : extensionLoadersMap.values()) {
+                extensionLoader.destroy();
+            }
+            extensionLoadersMap.clear();
+        }
+    }
+
+    private void checkDestroyed() {
+        if (destroyed.get()) {
+            throw new IllegalStateException("ExtensionDirector is destroyed");
         }
-        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 8fa6132..3d2b06d 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
@@ -66,6 +66,7 @@ import java.util.TreeMap;
 import java.util.TreeSet;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.regex.Pattern;
 
 import static java.util.Arrays.asList;
@@ -135,6 +136,7 @@ public class ExtensionLoader<T> {
     private Environment environment;
     private ActivateComparator activateComparator;
     private ScopeModel scopeModel;
+    private AtomicBoolean destroyed = new AtomicBoolean();
 
     public static void setLoadingStrategies(LoadingStrategy... strategies) {
         if (ArrayUtils.isNotEmpty(strategies)) {
@@ -216,6 +218,9 @@ public class ExtensionLoader<T> {
     }
 
     public void destroy() {
+        if (!destroyed.compareAndSet(false, true)) {
+            return;
+        }
         // destroy raw extension instance
         extensionInstances.forEach((type, instance) -> {
             if (instance instanceof Disposable) {
@@ -244,6 +249,12 @@ public class ExtensionLoader<T> {
         cachedInstances.clear();
     }
 
+    private void checkDestroyed() {
+        if (destroyed.get()) {
+            throw new IllegalStateException("ExtensionLoader is destroyed: " + type);
+        }
+    }
+
     private static ClassLoader findClassLoader() {
         return ClassUtils.getClassLoader(ExtensionLoader.class);
     }
@@ -305,6 +316,7 @@ public class ExtensionLoader<T> {
      * @see org.apache.dubbo.common.extension.Activate
      */
     public List<T> getActivateExtension(URL url, String[] values, String group) {
+        checkDestroyed();
         // solve the bug of using @SPI's wrapper method to report a null pointer exception.
         Map<Class<?>, T> activateExtensionsMap = new TreeMap<>(activateComparator);
         List<String> names = values == null ? new ArrayList<>(0) : asList(values);
@@ -385,6 +397,7 @@ public class ExtensionLoader<T> {
     }
 
     public List<T> getActivateExtensions() {
+        checkDestroyed();
         List<T> activateExtensions = new ArrayList<>();
         TreeMap<Class<?>, T> activateExtensionsMap = new TreeMap<>(activateComparator);
         getExtensionClasses();
@@ -447,6 +460,7 @@ public class ExtensionLoader<T> {
      */
     @SuppressWarnings("unchecked")
     public T getLoadedExtension(String name) {
+        checkDestroyed();
         if (StringUtils.isEmpty(name)) {
             throw new IllegalArgumentException("Extension name == null");
         }
@@ -475,6 +489,7 @@ public class ExtensionLoader<T> {
     }
 
     public List<T> getLoadedExtensionInstances() {
+        checkDestroyed();
         List<T> instances = new ArrayList<>();
         cachedInstances.values().forEach(holder -> instances.add((T) holder.get()));
         return instances;
@@ -498,6 +513,7 @@ public class ExtensionLoader<T> {
     }
 
     public T getExtension(String name, boolean wrap) {
+        checkDestroyed();
         if (StringUtils.isEmpty(name)) {
             throw new IllegalArgumentException("Extension name == null");
         }
@@ -544,6 +560,7 @@ public class ExtensionLoader<T> {
     }
 
     public boolean hasExtension(String name) {
+        checkDestroyed();
         if (StringUtils.isEmpty(name)) {
             throw new IllegalArgumentException("Extension name == null");
         }
@@ -552,11 +569,13 @@ public class ExtensionLoader<T> {
     }
 
     public Set<String> getSupportedExtensions() {
+        checkDestroyed();
         Map<String, Class<?>> clazzes = getExtensionClasses();
         return Collections.unmodifiableSet(new TreeSet<>(clazzes.keySet()));
     }
 
     public Set<T> getSupportedExtensionInstances() {
+        checkDestroyed();
         List<T> instances = new LinkedList<>();
         Set<String> supportedExtensions = getSupportedExtensions();
         if (CollectionUtils.isNotEmpty(supportedExtensions)) {
@@ -585,6 +604,7 @@ public class ExtensionLoader<T> {
      * @throws IllegalStateException when extension with the same name has already been registered.
      */
     public void addExtension(String name, Class<?> clazz) {
+        checkDestroyed();
         getExtensionClasses(); // load classes
 
         if (!type.isAssignableFrom(clazz)) {
@@ -626,6 +646,7 @@ public class ExtensionLoader<T> {
      */
     @Deprecated
     public void replaceExtension(String name, Class<?> clazz) {
+        checkDestroyed();
         getExtensionClasses(); // load classes
 
         if (!type.isAssignableFrom(clazz)) {
@@ -661,6 +682,7 @@ public class ExtensionLoader<T> {
 
     @SuppressWarnings("unchecked")
     public T getAdaptiveExtension() {
+        checkDestroyed();
         Object instance = cachedAdaptiveInstance.get();
         if (instance == null) {
             if (createAdaptiveInstanceError != null) {
@@ -883,6 +905,7 @@ public class ExtensionLoader<T> {
      * synchronized in getExtensionClasses
      */
     private Map<String, Class<?>> loadExtensionClasses() {
+        checkDestroyed();
         cacheDefaultExtensionName();
 
         Map<String, Class<?>> extensionClasses = new HashMap<>();