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