You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by ky...@apache.org on 2021/08/19 12:32:07 UTC
[dubbo] 01/02: Add ExtensionDirector and Models
This is an automated email from the ASF dual-hosted git repository.
kylixs pushed a commit to branch 3.0-multi-instances
in repository https://gitbox.apache.org/repos/asf/dubbo.git
commit 8183aafb9173d003f3662d2c6abf9acf8dd5348c
Author: gongdewei <ky...@qq.com>
AuthorDate: Thu Aug 19 20:27:05 2021 +0800
Add ExtensionDirector and Models
---
.../dubbo/common/extension/ExtensionDirector.java | 125 ++++++++++++++++++
.../dubbo/common/extension/ExtensionLoader.java | 136 ++++++++++++--------
.../common/extension/ExtensionPostProcessor.java | 32 +++++
.../dubbo/common/extension/ExtensionScope.java | 39 ++++++
.../org/apache/dubbo/common/extension/SPI.java | 4 +
.../apache/dubbo/rpc/model/ApplicationModel.java | 120 +++++++++---------
.../org/apache/dubbo/rpc/model/FrameworkModel.java | 50 ++++++++
.../org/apache/dubbo/rpc/model/ModelAware.java | 33 +++++
.../dubbo/rpc/model/ModelAwarePostProcessor.java | 57 +++++++++
.../org/apache/dubbo/rpc/model/ModuleModel.java | 44 +++++++
.../common/extension/ExtensionDirectorTest.java | 140 +++++++++++++++++++++
.../common/extension/ExtensionLoaderTest.java | 11 +-
.../extension/director/ApplicationService.java | 25 ++++
.../extension/director/FrameworkService.java | 25 ++++
.../common/extension/director/ModuleService.java | 25 ++++
.../extension/director/impl/BaseTestService.java | 55 ++++++++
.../director/impl/TestApplicationService.java | 22 ++++
.../director/impl/TestFrameworkService.java | 23 ++++
.../extension/director/impl/TestModuleService.java | 22 ++++
...bo.common.extension.director.ApplicationService | 1 +
...ubbo.common.extension.director.FrameworkService | 1 +
...e.dubbo.common.extension.director.ModuleService | 1 +
22 files changed, 878 insertions(+), 113 deletions(-)
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
new file mode 100644
index 0000000..ae686fd
--- /dev/null
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionDirector.java
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.common.extension;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * ExtensionDirector is a scoped extension loader manager.
+ *
+ * <p></p>
+ * <p>ExtensionDirector supports multiple levels, and the child can inherit the parent's extension instances. </p>
+ * <p>The way to find and create an extension instance is similar to Java classloader.</p>
+ */
+public class ExtensionDirector {
+
+ private final ConcurrentMap<Class<?>, ExtensionLoader<?>> extensionLoadersMap = new ConcurrentHashMap<>(64);
+ private ExtensionDirector parent;
+ private final ExtensionScope scope;
+ private List<ExtensionPostProcessor> extensionPostProcessors = new ArrayList<>();
+
+ public ExtensionDirector(ExtensionDirector parent, ExtensionScope scope) {
+ this.parent = parent;
+ this.scope = scope;
+ }
+
+ public void addExtensionPostProcessor(ExtensionPostProcessor processor) {
+ if (!this.extensionPostProcessors.contains(processor)) {
+ this.extensionPostProcessors.add(processor);
+ }
+ }
+
+ public List<ExtensionPostProcessor> getExtensionPostProcessors() {
+ return extensionPostProcessors;
+ }
+
+ public <T> T getExtension(Class<T> type, String name) {
+ ExtensionLoader<T> extensionLoader = getExtensionLoader(type);
+ return extensionLoader != null ? extensionLoader.getExtension(name) : null;
+ }
+
+ public <T> T getAdaptiveExtension(Class<T> type) {
+ ExtensionLoader<T> extensionLoader = getExtensionLoader(type);
+ return extensionLoader != null ? extensionLoader.getAdaptiveExtension() : null;
+ }
+
+ public <T> T getDefaultExtension(Class<T> type) {
+ ExtensionLoader<T> extensionLoader = getExtensionLoader(type);
+ return extensionLoader != null ? extensionLoader.getDefaultExtension() : null;
+ }
+
+ public <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
+ if (type == null) {
+ throw new IllegalArgumentException("Extension type == null");
+ }
+ if (!type.isInterface()) {
+ throw new IllegalArgumentException("Extension type (" + type + ") is not an interface!");
+ }
+ if (!withExtensionAnnotation(type)) {
+ throw new IllegalArgumentException("Extension type (" + type +
+ ") is not an extension, because it is NOT annotated with @" + SPI.class.getSimpleName() + "!");
+ }
+
+ // 1. find in local cache
+ ExtensionLoader<T> loader = (ExtensionLoader<T>) extensionLoadersMap.get(type);
+
+ // 2. find in parent
+ if (loader == null) {
+ if (this.parent != null) {
+ loader = this.parent.getExtensionLoader(type);
+ }
+ }
+
+ // 3. create it
+ if (loader == null) {
+ loader = createExtensionLoader(type);
+ }
+
+ return loader;
+ }
+
+ private <T> ExtensionLoader<T> createExtensionLoader(Class<T> type) {
+ ExtensionLoader<T> loader = null;
+ if (isScopeMatched(type)) {
+ // if scope is matched, just create it
+ extensionLoadersMap.putIfAbsent(type, new ExtensionLoader<T>(type, this));
+ loader = (ExtensionLoader<T>) extensionLoadersMap.get(type);
+ } else {
+ // if scope is not matched, redirect to parent director
+ if (this.parent != null) {
+ loader = this.parent.createExtensionLoader(type);
+ }
+ }
+ return loader;
+ }
+
+ private boolean isScopeMatched(Class<?> type) {
+ final SPI defaultAnnotation = type.getAnnotation(SPI.class);
+ return defaultAnnotation.scope().equals(scope);
+ }
+
+ private static boolean withExtensionAnnotation(Class<?> type) {
+ return type.isAnnotationPresent(SPI.class);
+ }
+
+ protected ExtensionDirector getParent() {
+ return parent;
+ }
+}
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 d2beedc..4d30c22 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
@@ -17,6 +17,8 @@
package org.apache.dubbo.common.extension;
import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.config.Environment;
+import org.apache.dubbo.common.context.FrameworkExt;
import org.apache.dubbo.common.context.Lifecycle;
import org.apache.dubbo.common.extension.support.ActivateComparator;
import org.apache.dubbo.common.extension.support.WrapperComparator;
@@ -32,6 +34,8 @@ import org.apache.dubbo.common.utils.Holder;
import org.apache.dubbo.common.utils.ReflectUtils;
import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.rpc.model.ApplicationModel;
+import org.apache.dubbo.rpc.model.FrameworkModel;
+import org.apache.dubbo.rpc.model.ModuleModel;
import java.io.BufferedReader;
import java.io.InputStreamReader;
@@ -90,9 +94,7 @@ public class ExtensionLoader<T> {
private static final Pattern NAME_SEPARATOR = Pattern.compile("\\s*[,]+\\s*");
- private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<>(64);
-
- private static final ConcurrentMap<Class<?>, Object> EXTENSION_INSTANCES = new ConcurrentHashMap<>(64);
+ private final ConcurrentMap<Class<?>, Object> extensionInstances = new ConcurrentHashMap<>(64);
private final Class<?> type;
@@ -121,6 +123,9 @@ public class ExtensionLoader<T> {
* Record all unacceptable exceptions when using SPI
*/
private Set<String> unacceptableExceptions = new ConcurrentHashSet<>();
+ private ExtensionDirector extensionDirector;
+ private List<ExtensionPostProcessor> extensionPostProcessors;
+ private Environment environment;
public static void setLoadingStrategies(LoadingStrategy... strategies) {
if (ArrayUtils.isNotEmpty(strategies)) {
@@ -152,52 +157,43 @@ public class ExtensionLoader<T> {
return asList(strategies);
}
- private ExtensionLoader(Class<?> type) {
+ ExtensionLoader(Class<?> type, ExtensionDirector extensionDirector) {
+ this.extensionDirector = extensionDirector;
+ this.extensionPostProcessors = extensionDirector.getExtensionPostProcessors();
this.type = type;
- objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
- }
-
- private static <T> boolean withExtensionAnnotation(Class<T> type) {
- return type.isAnnotationPresent(SPI.class);
+ this.objectFactory = (type == ExtensionFactory.class ? null : extensionDirector.getExtensionLoader(ExtensionFactory.class)
+ .getAdaptiveExtension());
}
- @SuppressWarnings("unchecked")
+ /**
+ * @deprecated get extension loader from extension director of some module.
+ *
+ * @see ApplicationModel#getExtensionDirector()
+ * @see FrameworkModel#getExtensionDirector()
+ * @see ModuleModel#getExtensionDirector()
+ * @see ExtensionDirector#getExtensionLoader(java.lang.Class)
+ */
+ @Deprecated
public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
- if (type == null) {
- throw new IllegalArgumentException("Extension type == null");
- }
- if (!type.isInterface()) {
- throw new IllegalArgumentException("Extension type (" + type + ") is not an interface!");
- }
- if (!withExtensionAnnotation(type)) {
- throw new IllegalArgumentException("Extension type (" + type +
- ") is not an extension, because it is NOT annotated with @" + SPI.class.getSimpleName() + "!");
- }
-
- ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
- if (loader == null) {
- EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
- loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
- }
- return loader;
+ return ApplicationModel.defaultModel().getExtensionDirector().getExtensionLoader(type);
}
// For testing purposes only
public static void resetExtensionLoader(Class type) {
- ExtensionLoader loader = EXTENSION_LOADERS.get(type);
- if (loader != null) {
- // Remove all instances associated with this loader as well
- Map<String, Class<?>> classes = loader.getExtensionClasses();
- for (Map.Entry<String, Class<?>> entry : classes.entrySet()) {
- EXTENSION_INSTANCES.remove(entry.getValue());
- }
- classes.clear();
- EXTENSION_LOADERS.remove(type);
- }
+// ExtensionLoader loader = EXTENSION_LOADERS.get(type);
+// if (loader != null) {
+// // Remove all instances associated with this loader as well
+// Map<String, Class<?>> classes = loader.getExtensionClasses();
+// for (Map.Entry<String, Class<?>> entry : classes.entrySet()) {
+// EXTENSION_INSTANCES.remove(entry.getValue());
+// }
+// classes.clear();
+// EXTENSION_LOADERS.remove(type);
+// }
}
- public static void destroyAll() {
- EXTENSION_INSTANCES.forEach((_type, instance) -> {
+ public void destroy() {
+ extensionInstances.forEach((_type, instance) -> {
if (instance instanceof Lifecycle) {
Lifecycle lifecycle = (Lifecycle) instance;
try {
@@ -207,13 +203,9 @@ public class ExtensionLoader<T> {
}
}
});
+ extensionInstances.clear();
- // TODO Improve extension loader, clear static refer extension instance.
- // Some extension instances may be referenced by static fields, if clear EXTENSION_INSTANCES may cause inconsistent.
- // e.g. org.apache.dubbo.registry.client.metadata.MetadataUtils.localMetadataService
- // EXTENSION_INSTANCES.clear();
-
- EXTENSION_LOADERS.clear();
+ // TODO destroy extension loader, release resources.
}
private static ClassLoader findClassLoader() {
@@ -695,11 +687,12 @@ public class ExtensionLoader<T> {
throw findException(name);
}
try {
- T instance = (T) EXTENSION_INSTANCES.get(clazz);
+ T instance = (T) extensionInstances.get(clazz);
if (instance == null) {
- EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.getDeclaredConstructor().newInstance());
- instance = (T) EXTENSION_INSTANCES.get(clazz);
+ extensionInstances.putIfAbsent(clazz, clazz.getDeclaredConstructor().newInstance());
+ instance = (T) extensionInstances.get(clazz);
}
+ instance = postProcessBeforeInitialization(instance, name);
injectExtension(instance);
@@ -723,6 +716,7 @@ public class ExtensionLoader<T> {
}
}
+ instance = postProcessAfterInitialization(instance, name);
initExtension(instance);
return instance;
} catch (Throwable t) {
@@ -731,6 +725,24 @@ public class ExtensionLoader<T> {
}
}
+ private T postProcessBeforeInitialization(T instance, String name) throws Exception {
+ if (extensionPostProcessors != null) {
+ for (ExtensionPostProcessor processor : extensionPostProcessors) {
+ instance = (T) processor.postProcessBeforeInitialization(instance, name);
+ }
+ }
+ return instance;
+ }
+
+ private T postProcessAfterInitialization(T instance, String name) throws Exception {
+ if (extensionPostProcessors != null) {
+ for (ExtensionPostProcessor processor : extensionPostProcessors) {
+ instance = (T) processor.postProcessAfterInitialization(instance, name);
+ }
+ }
+ return instance;
+ }
+
private boolean containsExtension(String name) {
return getExtensionClasses().containsKey(name);
}
@@ -839,8 +851,11 @@ public class ExtensionLoader<T> {
Map<String, Class<?>> extensionClasses = new HashMap<>();
for (LoadingStrategy strategy : strategies) {
- loadDirectory(extensionClasses, strategy.directory(), type.getName(), strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages());
- loadDirectory(extensionClasses, strategy.directory(), type.getName().replace("org.apache", "com.alibaba"), strategy.preferExtensionClassLoader(), strategy.overridden(), strategy.excludedPackages());
+ loadDirectory(extensionClasses, strategy.directory(), type.getName(), strategy.preferExtensionClassLoader(),
+ strategy.overridden(), strategy.excludedPackages());
+ String oldType = this.type.getName().replace("org.apache", "com.alibaba");
+ loadDirectory(extensionClasses, strategy.directory(), oldType, strategy.preferExtensionClassLoader(),
+ strategy.overridden(), strategy.excludedPackages());
}
return extensionClasses;
@@ -933,7 +948,8 @@ public class ExtensionLoader<T> {
loadClass(extensionClasses, resourceURL, Class.forName(clazz, true, classLoader), name, overridden);
}
} catch (Throwable t) {
- IllegalStateException e = new IllegalStateException("Failed to load extension class (interface: " + type + ", class line: " + line + ") in " + resourceURL + ", cause: " + t.getMessage(), t);
+ IllegalStateException e = new IllegalStateException("Failed to load extension class (interface: " + type +
+ ", class line: " + line + ") in " + resourceURL + ", cause: " + t.getMessage(), t);
exceptions.put(line, e);
}
}
@@ -1086,7 +1102,11 @@ public class ExtensionLoader<T> {
@SuppressWarnings("unchecked")
private T createAdaptiveExtension() {
try {
- return injectExtension((T) getAdaptiveExtensionClass().newInstance());
+ T instance = (T) getAdaptiveExtensionClass().newInstance();
+ instance = postProcessBeforeInitialization(instance, null);
+ instance = injectExtension(instance);
+ instance = postProcessAfterInitialization(instance, null);
+ return instance;
} catch (Exception e) {
throw new IllegalStateException("Can't create adaptive extension " + type + ", cause: " + e.getMessage(), e);
}
@@ -1103,17 +1123,25 @@ public class ExtensionLoader<T> {
private Class<?> createAdaptiveExtensionClass() {
ClassLoader classLoader = findClassLoader();
try {
- if (ApplicationModel.getEnvironment().getConfiguration().getBoolean(NATIVE, false)) {
+ if (getEnvironment().getConfiguration().getBoolean(NATIVE, false)) {
return classLoader.loadClass(type.getName() + "$Adaptive");
}
} catch (Throwable ignore) {
}
String code = new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate();
- org.apache.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
+ org.apache.dubbo.common.compiler.Compiler compiler = extensionDirector.getExtensionLoader(
+ org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
return compiler.compile(code, classLoader);
}
+ private Environment getEnvironment() {
+ if (environment == null) {
+ environment = (Environment) extensionDirector.getExtensionLoader(FrameworkExt.class).getExtension(Environment.NAME);
+ }
+ return environment;
+ }
+
@Override
public String toString() {
return this.getClass().getName() + "[" + type.getName() + "]";
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionPostProcessor.java b/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionPostProcessor.java
new file mode 100644
index 0000000..fcc4822
--- /dev/null
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionPostProcessor.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.common.extension;
+
+/**
+ * A Post-processor called before or after extension initialization.
+ */
+public interface ExtensionPostProcessor {
+
+ default Object postProcessBeforeInitialization(Object instance, String name) throws Exception {
+ return instance;
+ }
+
+ default Object postProcessAfterInitialization(Object instance, String name) throws Exception {
+ return instance;
+ }
+
+}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionScope.java b/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionScope.java
new file mode 100644
index 0000000..4391e52
--- /dev/null
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/extension/ExtensionScope.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.common.extension;
+
+/**
+ * Extension SPI Scope
+ */
+public enum ExtensionScope {
+
+ /**
+ * The extension instance is used within framework, shared with all applications and modules.
+ */
+ FRAMEWORK,
+
+ /**
+ * The extension instance is used within one application, shared with all modules of the application,
+ * and different applications create different extension instances.
+ */
+ APPLICATION,
+
+ /**
+ * The extension instance is used within one module, and different modules create different extension instances.
+ */
+ MODULE
+}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/extension/SPI.java b/dubbo-common/src/main/java/org/apache/dubbo/common/extension/SPI.java
index 70aa5b7..76e9fd5 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/extension/SPI.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/extension/SPI.java
@@ -61,4 +61,8 @@ public @interface SPI {
*/
String value() default "";
+ /**
+ * scope of SPI
+ */
+ ExtensionScope scope() default ExtensionScope.FRAMEWORK;
}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ApplicationModel.java b/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ApplicationModel.java
index 9e0521b..0d47697 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ApplicationModel.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ApplicationModel.java
@@ -18,7 +18,9 @@ package org.apache.dubbo.rpc.model;
import org.apache.dubbo.common.config.Environment;
import org.apache.dubbo.common.context.FrameworkExt;
+import org.apache.dubbo.common.extension.ExtensionDirector;
import org.apache.dubbo.common.extension.ExtensionLoader;
+import org.apache.dubbo.common.extension.ExtensionScope;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.threadpool.manager.ExecutorRepository;
@@ -46,14 +48,43 @@ import java.util.concurrent.atomic.AtomicBoolean;
public class ApplicationModel {
protected static final Logger LOGGER = LoggerFactory.getLogger(ApplicationModel.class);
public static final String NAME = "application";
+ private static volatile ApplicationModel defaultInstance;
- private static AtomicBoolean INIT_FLAG = new AtomicBoolean(false);
- private static Environment environment;
- private static ConfigManager configManager;
- private static ServiceRepository serviceRepository;
+ private AtomicBoolean initFlag = new AtomicBoolean(false);
+ private Environment environment;
+ private ConfigManager configManager;
+ private ServiceRepository serviceRepository;
- public static void init() {
- if (INIT_FLAG.compareAndSet(false, true)) {
+ private FrameworkModel frameworkModel;
+ private ExtensionDirector extensionDirector;
+
+ public ApplicationModel(FrameworkModel frameworkModel) {
+ this.frameworkModel = frameworkModel;
+ extensionDirector = new ExtensionDirector(frameworkModel.getExtensionDirector(), ExtensionScope.APPLICATION);
+ extensionDirector.addExtensionPostProcessor(new ModelAwarePostProcessor(this));
+ }
+
+ public static ApplicationModel defaultModel() {
+ if (defaultInstance == null) {
+ synchronized (ApplicationModel.class) {
+ if (defaultInstance == null) {
+ defaultInstance = new ApplicationModel(FrameworkModel.defaultModel());
+ }
+ }
+ }
+ return defaultInstance;
+ }
+
+ public FrameworkModel getFrameworkModel() {
+ return frameworkModel;
+ }
+
+ public ExtensionDirector getExtensionDirector() {
+ return extensionDirector;
+ }
+
+ public void init() {
+ if (initFlag.compareAndSet(false, true)) {
ExtensionLoader<ApplicationInitListener> extensionLoader = ExtensionLoader.getExtensionLoader(ApplicationInitListener.class);
Set<String> listenerNames = extensionLoader.getSupportedExtensions();
for (String listenerName : listenerNames) {
@@ -62,99 +93,76 @@ public class ApplicationModel {
}
}
- public static Collection<ConsumerModel> allConsumerModels() {
+ public void destroy() {
+ // TODO destroy application resources
+ }
+
+ public Collection<ConsumerModel> allConsumerModels() {
return getServiceRepository().getReferredServices();
}
- public static Collection<ProviderModel> allProviderModels() {
+ public Collection<ProviderModel> allProviderModels() {
return getServiceRepository().getExportedServices();
}
- public static ProviderModel getProviderModel(String serviceKey) {
+ public ProviderModel getProviderModel(String serviceKey) {
return getServiceRepository().lookupExportedService(serviceKey);
}
- public static ConsumerModel getConsumerModel(String serviceKey) {
+ public ConsumerModel getConsumerModel(String serviceKey) {
return getServiceRepository().lookupReferredService(serviceKey);
}
- private static ExtensionLoader<FrameworkExt> LOADER = ExtensionLoader.getExtensionLoader(FrameworkExt.class);
-
- public static void initFrameworkExts() {
- Set<FrameworkExt> exts = ExtensionLoader.getExtensionLoader(FrameworkExt.class).getSupportedExtensionInstances();
+ public void initFrameworkExts() {
+ Set<FrameworkExt> exts = extensionDirector.getExtensionLoader(FrameworkExt.class).getSupportedExtensionInstances();
for (FrameworkExt ext : exts) {
ext.initialize();
}
}
- public static Environment getEnvironment() {
+ public Environment getEnvironment() {
if (environment == null) {
- environment = (Environment) LOADER.getExtension(Environment.NAME);
+ environment = (Environment) extensionDirector.getExtensionLoader(FrameworkExt.class)
+ .getExtension(Environment.NAME);
}
return environment;
}
- public static ConfigManager getConfigManager() {
+ public ConfigManager getConfigManager() {
if (configManager == null) {
- configManager = (ConfigManager) LOADER.getExtension(ConfigManager.NAME);
+ configManager = (ConfigManager) extensionDirector.getExtensionLoader(FrameworkExt.class)
+ .getExtension(ConfigManager.NAME);
}
return configManager;
}
- public static ServiceRepository getServiceRepository() {
+ public ServiceRepository getServiceRepository() {
if (serviceRepository == null) {
- serviceRepository = (ServiceRepository) LOADER.getExtension(ServiceRepository.NAME);
+ serviceRepository = (ServiceRepository) extensionDirector.getExtensionLoader(FrameworkExt.class)
+ .getExtension(ServiceRepository.NAME);
}
return serviceRepository;
}
- public static ExecutorRepository getExecutorRepository() {
- return ExtensionLoader.getExtensionLoader(ExecutorRepository.class).getDefaultExtension();
+ public ExecutorRepository getExecutorRepository() {
+ return extensionDirector.getExtensionLoader(ExecutorRepository.class).getDefaultExtension();
}
- public static ApplicationConfig getApplicationConfig() {
+ public ApplicationConfig getApplicationConfig() {
return getConfigManager().getApplicationOrElseThrow();
}
- public static String getName() {
+ public String getName() {
return getApplicationConfig().getName();
}
- @Deprecated
- //It will be remove at next version
- private static String application;
-
- /**
- *
- * @deprecated Use {@link #getName()} instead. It will be remove at next version.
- */
- @Deprecated
- public static String getApplication() {
- return application == null ? getName() : application;
- }
-
- // Currently used by UT, it will be remove at next version.
- @Deprecated
- public static void setApplication(String application) {
- ApplicationModel.application = application;
- }
-
// only for unit test
+ @Deprecated
public static void reset() {
- if (serviceRepository!=null){
- serviceRepository.destroy();
- serviceRepository = null;
- }
- if (configManager != null) {
- configManager.destroy();
- configManager = null;
- }
- if (environment != null) {
- environment.destroy();
- environment = null;
+ if (defaultInstance != null) {
+ defaultInstance.destroy();
+ defaultInstance = null;
}
- ExtensionLoader.resetExtensionLoader(FrameworkExt.class);
- LOADER = ExtensionLoader.getExtensionLoader(FrameworkExt.class);
}
}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/FrameworkModel.java b/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/FrameworkModel.java
new file mode 100644
index 0000000..859f5e8
--- /dev/null
+++ b/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/FrameworkModel.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.model;
+
+import org.apache.dubbo.common.extension.ExtensionDirector;
+import org.apache.dubbo.common.extension.ExtensionScope;
+
+/**
+ * Model of dubbo framework, it can be shared with multiple applications.
+ */
+public class FrameworkModel {
+
+ private volatile static FrameworkModel defaultInstance;
+
+ private final ExtensionDirector extensionDirector;
+
+ public FrameworkModel() {
+ extensionDirector = new ExtensionDirector(null, ExtensionScope.FRAMEWORK);
+ extensionDirector.addExtensionPostProcessor(new ModelAwarePostProcessor(this));
+ }
+
+ public ExtensionDirector getExtensionDirector() {
+ return extensionDirector;
+ }
+
+ public static FrameworkModel defaultModel() {
+ if (defaultInstance == null) {
+ synchronized (FrameworkModel.class) {
+ if (defaultInstance == null) {
+ defaultInstance = new FrameworkModel();
+ }
+ }
+ }
+ return defaultInstance;
+ }
+}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ModelAware.java b/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ModelAware.java
new file mode 100644
index 0000000..dafa769
--- /dev/null
+++ b/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ModelAware.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.model;
+
+/**
+ * Interface to inject FrameworkModel/ApplicationModel/ModuleModel for SPI extension.
+ */
+public interface ModelAware {
+
+ default void setFrameworkModel(FrameworkModel frameworkModel) {
+ }
+
+ default void setApplicationModel(ApplicationModel applicationModel) {
+ }
+
+ default void setModuleModel(ModuleModel moduleModel) {
+ }
+
+}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ModelAwarePostProcessor.java b/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ModelAwarePostProcessor.java
new file mode 100644
index 0000000..2e93318
--- /dev/null
+++ b/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ModelAwarePostProcessor.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.model;
+
+import org.apache.dubbo.common.extension.ExtensionPostProcessor;
+
+public class ModelAwarePostProcessor implements ExtensionPostProcessor {
+ private Object model;
+ private FrameworkModel frameworkModel;
+ private ApplicationModel applicationModel;
+ private ModuleModel moduleModel;
+
+ public ModelAwarePostProcessor(Object model) {
+ this.model = model;
+ if (model instanceof FrameworkModel) {
+ frameworkModel = (FrameworkModel) model;
+ } else if (model instanceof ApplicationModel) {
+ applicationModel = (ApplicationModel) model;
+ frameworkModel = applicationModel.getFrameworkModel();
+ } else if (model instanceof ModuleModel) {
+ moduleModel = (ModuleModel) model;
+ applicationModel = moduleModel.getApplicationModel();
+ frameworkModel = applicationModel.getFrameworkModel();
+ }
+ }
+
+ @Override
+ public Object postProcessAfterInitialization(Object instance, String name) throws Exception {
+ if (instance instanceof ModelAware) {
+ ModelAware modelAware = (ModelAware) instance;
+ if (this.applicationModel != null) {
+ modelAware.setApplicationModel(this.applicationModel);
+ }
+ if (this.moduleModel != null) {
+ modelAware.setModuleModel(this.moduleModel);
+ }
+ if (this.frameworkModel != null) {
+ modelAware.setFrameworkModel(this.frameworkModel);
+ }
+ }
+ return instance;
+ }
+}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ModuleModel.java b/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ModuleModel.java
new file mode 100644
index 0000000..1334b80
--- /dev/null
+++ b/dubbo-common/src/main/java/org/apache/dubbo/rpc/model/ModuleModel.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.rpc.model;
+
+import org.apache.dubbo.common.extension.ExtensionDirector;
+import org.apache.dubbo.common.extension.ExtensionScope;
+
+/**
+ * Model of a service module
+ */
+public class ModuleModel {
+
+ private final ApplicationModel applicationModel;
+ private final ExtensionDirector extensionDirector;
+
+ public ModuleModel(ApplicationModel applicationModel) {
+ this.applicationModel = applicationModel;
+ extensionDirector = new ExtensionDirector(applicationModel.getExtensionDirector(), ExtensionScope.MODULE);
+ extensionDirector.addExtensionPostProcessor(new ModelAwarePostProcessor(this));
+ }
+
+ public ApplicationModel getApplicationModel() {
+ return applicationModel;
+ }
+
+ public ExtensionDirector getExtensionDirector() {
+ return extensionDirector;
+ }
+
+}
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
new file mode 100644
index 0000000..1c09a53
--- /dev/null
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/extension/ExtensionDirectorTest.java
@@ -0,0 +1,140 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.common.extension;
+
+import org.apache.dubbo.common.extension.ExtensionDirector;
+import org.apache.dubbo.common.extension.ExtensionScope;
+import org.apache.dubbo.common.extension.director.ApplicationService;
+import org.apache.dubbo.common.extension.director.FrameworkService;
+import org.apache.dubbo.common.extension.director.ModuleService;
+import org.apache.dubbo.common.extension.director.impl.TestApplicationService;
+import org.apache.dubbo.common.extension.director.impl.TestFrameworkService;
+import org.apache.dubbo.common.extension.director.impl.TestModuleService;
+import org.apache.dubbo.rpc.model.ApplicationModel;
+import org.apache.dubbo.rpc.model.FrameworkModel;
+import org.apache.dubbo.rpc.model.ModuleModel;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class ExtensionDirectorTest {
+
+ String testFwSrvName = "testFwSrv";
+ String testAppSrvName = "testAppSrv";
+ String testMdSrvName = "testMdSrv";
+
+ @Test
+ public void testInheritanceAndScope() {
+
+ // expecting:
+ // 1. SPI extension only be created in ExtensionDirector which matched scope
+ // 2. Child ExtensionDirector can get extension instance from parent
+ // 3. Parent ExtensionDirector can't get extension instance from child
+
+ ExtensionDirector fwExtensionDirector = new ExtensionDirector(null, ExtensionScope.FRAMEWORK);
+ ExtensionDirector appExtensionDirector = new ExtensionDirector(fwExtensionDirector, ExtensionScope.APPLICATION);
+ ExtensionDirector moduleExtensionDirector = new ExtensionDirector(appExtensionDirector, ExtensionScope.MODULE);
+
+ // test module extension loader
+ FrameworkService testFwSrvFromModule = moduleExtensionDirector.getExtension(FrameworkService.class, testFwSrvName);
+ ApplicationService testAppSrvFromModule = moduleExtensionDirector.getExtension(ApplicationService.class, testAppSrvName);
+ ModuleService testMdSrvFromModule = moduleExtensionDirector.getExtension(ModuleService.class, testMdSrvName);
+
+ Assertions.assertNotNull(testFwSrvFromModule);
+ Assertions.assertNotNull(testAppSrvFromModule);
+ Assertions.assertNotNull(testMdSrvFromModule);
+
+ // test app extension loader
+ FrameworkService testFwSrvFromApp = appExtensionDirector.getExtension(FrameworkService.class, testFwSrvName);
+ ApplicationService testAppSrvFromApp = appExtensionDirector.getExtension(ApplicationService.class, testAppSrvName);
+ ModuleService testMdSrvFromApp = appExtensionDirector.getExtension(ModuleService.class, testMdSrvName);
+
+ Assertions.assertSame(testFwSrvFromApp, testFwSrvFromModule);
+ Assertions.assertSame(testAppSrvFromApp, testAppSrvFromModule);
+ Assertions.assertNull(testMdSrvFromApp);
+
+ // test framework extension loader
+ FrameworkService testFwSrvFromFw = fwExtensionDirector.getExtension(FrameworkService.class, testFwSrvName);
+ ApplicationService testAppSrvFromFw = fwExtensionDirector.getExtension(ApplicationService.class, testAppSrvName);
+ ModuleService testMdSrvFromFw = fwExtensionDirector.getExtension(ModuleService.class, testMdSrvName);
+
+ Assertions.assertSame(testFwSrvFromFw, testFwSrvFromApp);
+ Assertions.assertNull(testAppSrvFromFw);
+ Assertions.assertNull(testMdSrvFromFw);
+ }
+
+ @Test
+ public void testPostProcessor() {
+
+ }
+
+ @Test
+ public void testModelAware() {
+ // Expecting:
+ // 1. Module scope SPI can be injected ModuleModel, ApplicationModel, FrameworkModel
+ // 2. Application scope SPI can be injected ApplicationModel, FrameworkModel, but not ModuleModel
+ // 3. Framework scope SPI can be injected FrameworkModel, but not ModuleModel, ApplicationModel
+
+ FrameworkModel frameworkModel = new FrameworkModel();
+ ApplicationModel applicationModel = new ApplicationModel(frameworkModel);
+ ModuleModel moduleModel = new ModuleModel(applicationModel);
+
+ ExtensionDirector moduleExtensionDirector = moduleModel.getExtensionDirector();
+ ExtensionDirector appExtensionDirector = applicationModel.getExtensionDirector();
+ ExtensionDirector fwExtensionDirector = frameworkModel.getExtensionDirector();
+
+ // check extension director inheritance
+ Assertions.assertSame(appExtensionDirector, moduleExtensionDirector.getParent());
+ Assertions.assertSame(fwExtensionDirector, appExtensionDirector.getParent());
+ Assertions.assertSame(null, fwExtensionDirector.getParent());
+
+ // check module extension aware
+ TestFrameworkService testFwSrvFromModule = (TestFrameworkService) moduleExtensionDirector.getExtension(FrameworkService.class, testFwSrvName);
+ TestApplicationService testAppSrvFromModule = (TestApplicationService) moduleExtensionDirector.getExtension(ApplicationService.class, testAppSrvName);
+ TestModuleService testMdSrvFromModule = (TestModuleService) moduleExtensionDirector.getExtension(ModuleService.class, testMdSrvName);
+
+ Assertions.assertSame(frameworkModel, testFwSrvFromModule.getFrameworkModel());
+ Assertions.assertSame(null, testFwSrvFromModule.getApplicationModel());
+ Assertions.assertSame(null, testFwSrvFromModule.getModuleModel());
+
+ Assertions.assertSame(frameworkModel, testAppSrvFromModule.getFrameworkModel());
+ Assertions.assertSame(applicationModel, testAppSrvFromModule.getApplicationModel());
+ Assertions.assertSame(null, testAppSrvFromModule.getModuleModel());
+
+ Assertions.assertSame(frameworkModel, testMdSrvFromModule.getFrameworkModel());
+ Assertions.assertSame(applicationModel, testMdSrvFromModule.getApplicationModel());
+ Assertions.assertSame(moduleModel, testMdSrvFromModule.getModuleModel());
+
+ // check app extension aware
+ TestFrameworkService testFwSrvFromApp = (TestFrameworkService) appExtensionDirector.getExtension(FrameworkService.class, testFwSrvName);
+ TestApplicationService testAppSrvFromApp = (TestApplicationService) appExtensionDirector.getExtension(ApplicationService.class, testAppSrvName);
+ TestModuleService testMdSrvFromApp = (TestModuleService) appExtensionDirector.getExtension(ModuleService.class, testMdSrvName);
+
+ Assertions.assertSame(testFwSrvFromApp, testFwSrvFromModule);
+ Assertions.assertSame(testAppSrvFromApp, testAppSrvFromModule);
+ Assertions.assertNull(testMdSrvFromApp);
+
+ // check framework extension aware
+ FrameworkService testFwSrvFromFw = fwExtensionDirector.getExtension(FrameworkService.class, testFwSrvName);
+ ApplicationService testAppSrvFromFw = fwExtensionDirector.getExtension(ApplicationService.class, testAppSrvName);
+ ModuleService testMdSrvFromFw = fwExtensionDirector.getExtension(ModuleService.class, testMdSrvName);
+
+ Assertions.assertSame(testFwSrvFromFw, testFwSrvFromApp);
+ Assertions.assertNull(testAppSrvFromFw);
+ Assertions.assertNull(testMdSrvFromFw);
+
+ }
+}
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/extension/ExtensionLoaderTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/extension/ExtensionLoaderTest.java
index 57736b8..b9b80b2 100644
--- a/dubbo-common/src/test/java/org/apache/dubbo/common/extension/ExtensionLoaderTest.java
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/extension/ExtensionLoaderTest.java
@@ -61,6 +61,7 @@ import org.apache.dubbo.common.extension.injection.impl.InjectExtImpl;
import org.apache.dubbo.common.lang.Prioritized;
import org.apache.dubbo.common.url.component.ServiceConfigURL;
+import org.apache.dubbo.rpc.model.ApplicationModel;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@@ -70,7 +71,6 @@ import java.util.List;
import java.util.Set;
import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
-import static org.apache.dubbo.common.extension.ExtensionLoader.getExtensionLoader;
import static org.apache.dubbo.common.extension.ExtensionLoader.getLoadingStrategies;
import static org.hamcrest.CoreMatchers.allOf;
import static org.hamcrest.CoreMatchers.anyOf;
@@ -84,6 +84,11 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
public class ExtensionLoaderTest {
+
+ private <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
+ return ApplicationModel.defaultModel().getExtensionDirector().getExtensionLoader(type);
+ }
+
@Test
public void test_getExtensionLoader_Null() throws Exception {
try {
@@ -559,7 +564,7 @@ public class ExtensionLoaderTest {
List<LoadingStrategy> loadingStrategies = ExtensionLoader.getLoadingStrategies();
ExtensionLoader.setLoadingStrategies(new DubboExternalLoadingStrategyTest(false),
new DubboInternalLoadingStrategyTest(false));
- ExtensionLoader<DuplicatedWithoutOverriddenExt> extensionLoader = ExtensionLoader.getExtensionLoader(DuplicatedWithoutOverriddenExt.class);
+ ExtensionLoader<DuplicatedWithoutOverriddenExt> extensionLoader = getExtensionLoader(DuplicatedWithoutOverriddenExt.class);
try {
extensionLoader.getExtension("duplicated");
fail();
@@ -577,7 +582,7 @@ public class ExtensionLoaderTest {
List<LoadingStrategy> loadingStrategies = ExtensionLoader.getLoadingStrategies();
ExtensionLoader.setLoadingStrategies(new DubboExternalLoadingStrategyTest(true),
new DubboInternalLoadingStrategyTest(true));
- ExtensionLoader<DuplicatedOverriddenExt> extensionLoader = ExtensionLoader.getExtensionLoader(DuplicatedOverriddenExt.class);
+ ExtensionLoader<DuplicatedOverriddenExt> extensionLoader = getExtensionLoader(DuplicatedOverriddenExt.class);
DuplicatedOverriddenExt duplicatedOverriddenExt = extensionLoader.getExtension("duplicated");
assertEquals("DuplicatedOverriddenExt1", duplicatedOverriddenExt.echo());
//recover the loading strategies
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/extension/director/ApplicationService.java b/dubbo-common/src/test/java/org/apache/dubbo/common/extension/director/ApplicationService.java
new file mode 100644
index 0000000..c0dff97
--- /dev/null
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/extension/director/ApplicationService.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.common.extension.director;
+
+import org.apache.dubbo.common.extension.ExtensionScope;
+import org.apache.dubbo.common.extension.SPI;
+
+@SPI(scope = ExtensionScope.APPLICATION)
+public interface ApplicationService {
+
+}
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/extension/director/FrameworkService.java b/dubbo-common/src/test/java/org/apache/dubbo/common/extension/director/FrameworkService.java
new file mode 100644
index 0000000..9703689
--- /dev/null
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/extension/director/FrameworkService.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.common.extension.director;
+
+import org.apache.dubbo.common.extension.ExtensionScope;
+import org.apache.dubbo.common.extension.SPI;
+
+@SPI(scope = ExtensionScope.FRAMEWORK)
+public interface FrameworkService {
+
+}
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/extension/director/ModuleService.java b/dubbo-common/src/test/java/org/apache/dubbo/common/extension/director/ModuleService.java
new file mode 100644
index 0000000..a9b940f
--- /dev/null
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/extension/director/ModuleService.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.common.extension.director;
+
+import org.apache.dubbo.common.extension.ExtensionScope;
+import org.apache.dubbo.common.extension.SPI;
+
+@SPI(scope = ExtensionScope.MODULE)
+public interface ModuleService {
+
+}
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
new file mode 100644
index 0000000..c3399b8
--- /dev/null
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/extension/director/impl/BaseTestService.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.common.extension.director.impl;
+
+import org.apache.dubbo.rpc.model.ApplicationModel;
+import org.apache.dubbo.rpc.model.FrameworkModel;
+import org.apache.dubbo.rpc.model.ModelAware;
+import org.apache.dubbo.rpc.model.ModuleModel;
+
+public class BaseTestService implements ModelAware {
+ private FrameworkModel frameworkModel;
+ private ApplicationModel applicationModel;
+ private ModuleModel moduleModel;
+
+ @Override
+ public void setFrameworkModel(FrameworkModel frameworkModel) {
+ this.frameworkModel = frameworkModel;
+ }
+
+ @Override
+ public void setApplicationModel(ApplicationModel applicationModel) {
+ this.applicationModel = applicationModel;
+ }
+
+ @Override
+ public void setModuleModel(ModuleModel moduleModel) {
+ this.moduleModel = moduleModel;
+ }
+
+ public FrameworkModel getFrameworkModel() {
+ return frameworkModel;
+ }
+
+ public ApplicationModel getApplicationModel() {
+ return applicationModel;
+ }
+
+ public ModuleModel getModuleModel() {
+ return moduleModel;
+ }
+}
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/extension/director/impl/TestApplicationService.java b/dubbo-common/src/test/java/org/apache/dubbo/common/extension/director/impl/TestApplicationService.java
new file mode 100644
index 0000000..9a0e1ef
--- /dev/null
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/extension/director/impl/TestApplicationService.java
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.common.extension.director.impl;
+
+import org.apache.dubbo.common.extension.director.ApplicationService;
+
+public class TestApplicationService extends BaseTestService implements ApplicationService {
+}
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/extension/director/impl/TestFrameworkService.java b/dubbo-common/src/test/java/org/apache/dubbo/common/extension/director/impl/TestFrameworkService.java
new file mode 100644
index 0000000..416ba0d
--- /dev/null
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/extension/director/impl/TestFrameworkService.java
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.common.extension.director.impl;
+
+import org.apache.dubbo.common.extension.director.FrameworkService;
+
+public class TestFrameworkService extends BaseTestService implements FrameworkService {
+
+}
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/extension/director/impl/TestModuleService.java b/dubbo-common/src/test/java/org/apache/dubbo/common/extension/director/impl/TestModuleService.java
new file mode 100644
index 0000000..afdbecb
--- /dev/null
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/extension/director/impl/TestModuleService.java
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.common.extension.director.impl;
+
+import org.apache.dubbo.common.extension.director.ModuleService;
+
+public class TestModuleService extends BaseTestService implements ModuleService {
+}
diff --git a/dubbo-common/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.common.extension.director.ApplicationService b/dubbo-common/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.common.extension.director.ApplicationService
new file mode 100644
index 0000000..10d253b
--- /dev/null
+++ b/dubbo-common/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.common.extension.director.ApplicationService
@@ -0,0 +1 @@
+testAppSrv=org.apache.dubbo.common.extension.director.impl.TestApplicationService
diff --git a/dubbo-common/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.common.extension.director.FrameworkService b/dubbo-common/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.common.extension.director.FrameworkService
new file mode 100644
index 0000000..f695488
--- /dev/null
+++ b/dubbo-common/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.common.extension.director.FrameworkService
@@ -0,0 +1 @@
+testFwSrv=org.apache.dubbo.common.extension.director.impl.TestFrameworkService
diff --git a/dubbo-common/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.common.extension.director.ModuleService b/dubbo-common/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.common.extension.director.ModuleService
new file mode 100644
index 0000000..9d3ef32
--- /dev/null
+++ b/dubbo-common/src/test/resources/META-INF/dubbo/internal/org.apache.dubbo.common.extension.director.ModuleService
@@ -0,0 +1 @@
+testMdSrv=org.apache.dubbo.common.extension.director.impl.TestModuleService