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 <[email protected]> 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
