[3.0] Improve resource cleaning (#9129)

This commit is contained in:
Gong Dewei 2021-10-29 10:47:50 +08:00 committed by GitHub
parent afcd8110c2
commit 7a59b4b875
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 588 additions and 207 deletions

View File

@ -568,6 +568,10 @@ class URL implements Serializable {
return ScopeModelUtil.getApplicationModel(getScopeModel());
}
public ApplicationModel getApplicationModel() {
return ScopeModelUtil.getOrNullApplicationModel(getScopeModel());
}
public ModuleModel getOrDefaultModuleModel() {
return ScopeModelUtil.getModuleModel(getScopeModel());
}

View File

@ -24,7 +24,6 @@ import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.apache.dubbo.rpc.model.ScopeModel;
import org.apache.dubbo.rpc.model.ScopeModelUtil;
import java.io.IOException;
import java.io.StringReader;
@ -66,7 +65,7 @@ public class ConfigurationUtils {
* @return
*/
public static Configuration getSystemConfiguration(ScopeModel scopeModel) {
return ScopeModelUtil.getOrDefaultApplicationModel(scopeModel).getModelEnvironment().getSystemConfiguration();
return getScopeModelOrDefaultApplicationModel(scopeModel).getModelEnvironment().getSystemConfiguration();
}
/**
@ -76,7 +75,7 @@ public class ConfigurationUtils {
*/
public static Configuration getEnvConfiguration(ScopeModel scopeModel) {
return ScopeModelUtil.getOrDefaultApplicationModel(scopeModel).getModelEnvironment().getEnvironmentConfiguration();
return getScopeModelOrDefaultApplicationModel(scopeModel).getModelEnvironment().getEnvironmentConfiguration();
}
/**
@ -88,7 +87,7 @@ public class ConfigurationUtils {
*/
public static Configuration getGlobalConfiguration(ScopeModel scopeModel) {
return ScopeModelUtil.getOrDefaultApplicationModel(scopeModel).getModelEnvironment().getConfiguration();
return getScopeModelOrDefaultApplicationModel(scopeModel).getModelEnvironment().getConfiguration();
}
public static Configuration getDynamicGlobalConfiguration(ScopeModel scopeModel) {
@ -127,12 +126,19 @@ public class ConfigurationUtils {
}
public static String getCachedDynamicProperty(ScopeModel realScopeModel, String key, String defaultValue) {
ScopeModel scopeModel = ScopeModelUtil.getOrDefaultApplicationModel(realScopeModel);
ScopeModel scopeModel = getScopeModelOrDefaultApplicationModel(realScopeModel);
ConfigurationCache configurationCache = scopeModel.getBeanFactory().getBean(ConfigurationCache.class);
String value = configurationCache.computeIfAbsent(key, _k -> ConfigurationUtils.getDynamicProperty(scopeModel, _k, ""));
return StringUtils.isEmpty(value) ? defaultValue : value;
}
private static ScopeModel getScopeModelOrDefaultApplicationModel(ScopeModel realScopeModel) {
if (realScopeModel == null) {
return ApplicationModel.defaultModel();
}
return realScopeModel;
}
public static String getDynamicProperty(ScopeModel scopeModel, String property) {
return getDynamicProperty(scopeModel, property, null);
}

View File

@ -158,4 +158,8 @@ public abstract class AbstractDeployer<E extends ScopeModel> implements Deployer
public boolean isInitialized() {
return initialized.get();
}
protected String getIdentifier() {
return scopeModel.getDesc();
}
}

View File

@ -89,5 +89,4 @@ public interface Deployer<E extends ScopeModel> {
void removeDeployListener(DeployListener<E> listener);
String getIdentifier();
}

View File

@ -37,7 +37,7 @@ public class GlobalResourcesRepository {
private volatile static GlobalResourcesRepository instance;
private volatile ExecutorService executorService;
private final List<Disposable> oneoffDisposables = Collections.synchronizedList(new ArrayList<>());
private final List<Disposable> reusedDisposables = Collections.synchronizedList(new ArrayList<>());
private static final List<Disposable> globalReusedDisposables = Collections.synchronizedList(new ArrayList<>());
private GlobalResourcesRepository() {
}
@ -53,6 +53,25 @@ public class GlobalResourcesRepository {
return instance;
}
/**
* Register a global reused disposable. The disposable will be executed when all dubbo FrameworkModels are destroyed.
* Note: the global disposable should be registered in static code, it's reusable and will not be removed when dubbo shutdown.
* @param disposable
*/
public static void registerGlobalDisposable(Disposable disposable) {
synchronized (GlobalResourcesRepository.class) {
if (!globalReusedDisposables.contains(disposable)) {
globalReusedDisposables.add(disposable);
}
}
}
public void removeGlobalDisposable(Disposable disposable) {
synchronized (GlobalResourcesRepository.class) {
this.globalReusedDisposables.remove(disposable);
}
}
public static ExecutorService getGlobalExecutorService() {
return getInstance().getExecutorService();
}
@ -68,7 +87,7 @@ public class GlobalResourcesRepository {
return executorService;
}
public void destroy() {
synchronized public void destroy() {
if (logger.isInfoEnabled()) {
logger.info("Destroying global resources ...");
}
@ -77,16 +96,7 @@ public class GlobalResourcesRepository {
executorService = null;
}
// notify disposables
// NOTE: don't clear reused disposables for reuse purpose
for (Disposable disposable : new ArrayList<>(reusedDisposables)) {
try {
disposable.destroy();
} catch (Exception e) {
logger.warn("destroy resources failed: " + e.getMessage(), e);
}
}
// call one-off disposables
for (Disposable disposable : new ArrayList<>(oneoffDisposables)) {
try {
disposable.destroy();
@ -97,6 +107,15 @@ public class GlobalResourcesRepository {
// clear one-off disposable
oneoffDisposables.clear();
// call global disposable, don't clear globalReusedDisposables for reuse purpose
for (Disposable disposable : new ArrayList<>(globalReusedDisposables)) {
try {
disposable.destroy();
} catch (Exception e) {
logger.warn("destroy resources failed: " + e.getMessage(), e);
}
}
if (logger.isInfoEnabled()) {
logger.info("Dubbo is completely destroyed");
}
@ -106,24 +125,13 @@ public class GlobalResourcesRepository {
* Register a one-off disposable, the disposable is removed automatically on first shutdown.
* @param disposable
*/
public void registerDisposable(Disposable disposable) {
this.registerDisposable(disposable, false);
}
/**
* Register a disposable
* @param disposable
* @param reused true - the disposable is keep and reused. false - the disposable is removed automatically on first shutdown
*/
public void registerDisposable(Disposable disposable, boolean reused) {
List<Disposable> disposables = reused ? reusedDisposables : oneoffDisposables;
if (!disposables.contains(disposable)) {
disposables.add(disposable);
synchronized public void registerDisposable(Disposable disposable) {
if (!oneoffDisposables.contains(disposable)) {
oneoffDisposables.add(disposable);
}
}
public void removeDisposable(Disposable disposable) {
this.reusedDisposables.remove(disposable);
synchronized public void removeDisposable(Disposable disposable) {
this.oneoffDisposables.remove(disposable);
}

View File

@ -39,7 +39,7 @@ public class ClassLoaderResourceLoader {
static {
// register resources destroy listener
GlobalResourcesRepository.getInstance().registerDisposable(()-> destroy(), true);
GlobalResourcesRepository.registerGlobalDisposable(()-> destroy());
}
public static Map<ClassLoader, Set<java.net.URL>> loadResources(String fileName, List<ClassLoader> classLoaders) {
@ -62,7 +62,7 @@ public class ClassLoaderResourceLoader {
public static Set<java.net.URL> loadResources(String fileName, ClassLoader currentClassLoader) {
Map<ClassLoader, Map<String, Set<java.net.URL>>> classLoaderCache;
if (classLoaderResourcesCache == null || (classLoaderCache = classLoaderResourcesCache.get()) == null) {
synchronized (ConfigUtils.class) {
synchronized (ClassLoaderResourceLoader.class) {
if (classLoaderResourcesCache == null || (classLoaderCache = classLoaderResourcesCache.get()) == null) {
classLoaderCache = new ConcurrentHashMap<>();
classLoaderResourcesCache = new SoftReference<>(classLoaderCache);
@ -98,8 +98,8 @@ public class ClassLoaderResourceLoader {
}
public static void destroy() {
if (classLoaderResourcesCache != null) {
classLoaderResourcesCache.clear();
synchronized (ClassLoaderResourceLoader.class) {
classLoaderResourcesCache = null;
}
}

View File

@ -21,6 +21,7 @@ import org.apache.dubbo.common.extension.DisableInject;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.config.AbstractConfig;
import org.apache.dubbo.config.ApplicationConfig;
import org.apache.dubbo.config.ConfigCenterConfig;
@ -255,7 +256,14 @@ public class ConfigManager extends AbstractConfigManager implements ApplicationE
// config centers has bean loaded before starting config center
//loadConfigsOfTypeFromProps(ConfigCenterConfig.class);
refreshAll();
checkConfigs();
// set model name
if (StringUtils.isBlank(applicationModel.getModelName())) {
applicationModel.setModelName(applicationModel.getApplicationName());
}
}
private void checkConfigs() {

View File

@ -53,8 +53,6 @@ import java.util.concurrent.atomic.AtomicInteger;
public class ApplicationModel extends ScopeModel {
protected static final Logger LOGGER = LoggerFactory.getLogger(ApplicationModel.class);
public static final String NAME = "ApplicationModel";
private static volatile ApplicationModel defaultInstance;
private final List<ModuleModel> moduleModels = Collections.synchronizedList(new ArrayList<>());
private final List<ModuleModel> pubModuleModels = Collections.synchronizedList(new ArrayList<>());
private Environment environment;
@ -84,15 +82,15 @@ public class ApplicationModel extends ScopeModel {
}
}
/**
* During destroying the default FrameworkModel, FrameworkModel.defaultModel() or ApplicationModel.defaultModel()
* will get an broken model, maybe cause unpredictable problem.
* Recommendation: Avoid using the default model as much as possible.
* @return the global default ApplicationModel
*/
public static ApplicationModel defaultModel() {
if (defaultInstance == null) {
synchronized (ApplicationModel.class) {
if (defaultInstance == null) {
defaultInstance = new ApplicationModel(FrameworkModel.defaultModel());
}
}
}
return defaultInstance;
// should get from default FrameworkModel, avoid out of sync
return FrameworkModel.defaultModel().defaultApplication();
}
/**
@ -186,9 +184,8 @@ public class ApplicationModel extends ScopeModel {
// only for unit test
@Deprecated
public static void reset() {
if (defaultInstance != null) {
defaultInstance.destroy();
defaultInstance = null;
if (FrameworkModel.defaultModel().getDefaultAppModel() != null) {
FrameworkModel.defaultModel().getDefaultAppModel().destroy();
}
}
@ -204,13 +201,10 @@ public class ApplicationModel extends ScopeModel {
this.isInternal = isInternal;
this.frameworkModel = frameworkModel;
frameworkModel.addApplication(this);
initialize();
// bind to default instance if absent
synchronized (ApplicationModel.class) {
if (!isInternal && defaultInstance == null) {
defaultInstance = this;
}
if (LOGGER.isInfoEnabled()) {
LOGGER.info(getDesc() + " is created");
}
initialize();
}
@Override
@ -244,17 +238,7 @@ public class ApplicationModel extends ScopeModel {
@Override
protected void onDestroy() {
// 1. remove from frameworkModel
if (defaultInstance == this) {
synchronized (ApplicationModel.class) {
frameworkModel.removeApplication(this);
defaultInstance = null;
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Reset default Dubbo application[" + getInternalId() + "] to null ...");
}
}
} else {
frameworkModel.removeApplication(this);
}
frameworkModel.removeApplication(this);
// 2. pre-destroy, set stopping
if (deployer != null) {
@ -343,8 +327,9 @@ public class ApplicationModel extends ScopeModel {
void addModule(ModuleModel moduleModel, boolean isInternal) {
synchronized (moduleLock) {
if (!this.moduleModels.contains(moduleModel)) {
checkDestroyed();
this.moduleModels.add(moduleModel);
moduleModel.setInternalName(buildInternalName(ModuleModel.NAME, getInternalId(), moduleIndex.getAndIncrement()));
moduleModel.setInternalId(buildInternalId(getInternalId(), moduleIndex.getAndIncrement()));
if (!isInternal) {
pubModuleModels.add(moduleModel);
}
@ -369,6 +354,12 @@ public class ApplicationModel extends ScopeModel {
}
}
private void checkDestroyed() {
if (isDestroyed()) {
throw new IllegalStateException("ApplicationModel is destroyed");
}
}
public List<ModuleModel> getModuleModels() {
return Collections.unmodifiableList(moduleModels);
}
@ -379,9 +370,6 @@ public class ApplicationModel extends ScopeModel {
public ModuleModel getDefaultModule() {
if (defaultModule == null) {
if (isDestroyed()) {
return null;
}
synchronized (moduleLock) {
if (defaultModule == null) {
defaultModule = findDefaultModule();

View File

@ -30,6 +30,7 @@ import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;
/**
* Model of dubbo framework, it can be shared with multiple applications.
@ -43,8 +44,12 @@ public class FrameworkModel extends ScopeModel {
// internal app index is 0, default app index is 1
private final AtomicLong appIndex = new AtomicLong(0);
private static Object globalLock = new Object();
private volatile static FrameworkModel defaultInstance;
private volatile ApplicationModel defaultAppModel;
private static List<FrameworkModel> allInstances = Collections.synchronizedList(new ArrayList<>());
private List<ApplicationModel> applicationModels = Collections.synchronizedList(new ArrayList<>());
@ -55,17 +60,26 @@ public class FrameworkModel extends ScopeModel {
private ApplicationModel internalApplicationModel;
private Object instLock = new Object();
public FrameworkModel() {
super(null, ExtensionScope.FRAMEWORK);
this.setInternalId(index.getAndIncrement()+"");
// register FrameworkModel instance early
synchronized (globalLock) {
allInstances.add(this);
resetDefaultFrameworkModel();
}
if (LOGGER.isInfoEnabled()) {
LOGGER.info(getDesc() + " is created");
}
initialize();
this.setInternalName(buildInternalName(NAME, null, index.getAndIncrement()));
}
@Override
protected void initialize() {
super.initialize();
serviceRepository = new FrameworkServiceRepository(this);
allInstances.add(this);
ExtensionLoader<ScopeModelInitializer> initializerExtensionLoader = this.getExtensionLoader(ScopeModelInitializer.class);
Set<ScopeModelInitializer> initializers = initializerExtensionLoader.getSupportedExtensionInstances();
@ -81,45 +95,73 @@ public class FrameworkModel extends ScopeModel {
@Override
protected void onDestroy() {
// destroy all application model
for (ApplicationModel applicationModel : new ArrayList<>(applicationModels)) {
applicationModel.destroy();
if (defaultInstance == this) {
// NOTE: During destroying the default FrameworkModel, FrameworkModel.defaultModel() or ApplicationModel.defaultModel()
// will get an broken model, maybe cause unpredictable problem.
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Destroying default framework model: " + getDesc());
}
}
synchronized (instLock) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info(getDesc() + " is destroying ...");
}
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Dubbo framework[" + getInternalId() + "] is destroying ...");
}
synchronized (FrameworkModel.class) {
allInstances.remove(this);
if (defaultInstance == this) {
defaultInstance = null;
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Reset default Dubbo framework[" + getInternalId() + "] to null ...");
}
// destroy all application model
for (ApplicationModel applicationModel : new ArrayList<>(applicationModels)) {
applicationModel.destroy();
}
// check whether all application models are destroyed
checkApplicationDestroy();
// notify destroy and clean framework resources
// see org.apache.dubbo.config.deploy.FrameworkModelCleaner
notifyDestroy();
checkApplicationDestroy();
if (LOGGER.isInfoEnabled()) {
LOGGER.info(getDesc() + " is destroyed");
}
}
// notify destroy and clean framework resources
// see org.apache.dubbo.config.deploy.FrameworkModelCleaner
notifyDestroy();
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Dubbo framework[" + getInternalId() + "] is destroyed");
// remove from allInstances and reset default FrameworkModel
synchronized (globalLock) {
allInstances.remove(this);
resetDefaultFrameworkModel();
}
// if all FrameworkModels are destroyed, clean global static resources, shutdown dubbo completely
if (allInstances.isEmpty()) {
destroyGlobalResources();
destroyGlobalResources();
}
private void checkApplicationDestroy() {
if (applicationModels.size() > 0) {
List<String> remainApplications = applicationModels.stream()
.map(model -> model.getDesc())
.collect(Collectors.toList());
throw new IllegalStateException("Not all application models are completely destroyed, remaining " +
remainApplications.size() + " application models may be created during destruction: " + remainApplications);
}
}
private void destroyGlobalResources() {
GlobalResourcesRepository.getInstance().destroy();
synchronized (globalLock) {
if (allInstances.isEmpty()) {
GlobalResourcesRepository.getInstance().destroy();
}
}
}
/**
* During destroying the default FrameworkModel, FrameworkModel.defaultModel() or ApplicationModel.defaultModel()
* will get an broken model, maybe cause unpredictable problem.
* Recommendation: Avoid using the default model as much as possible.
* @return the global default FrameworkModel
*/
public static FrameworkModel defaultModel() {
if (defaultInstance == null) {
synchronized (FrameworkModel.class) {
synchronized (globalLock) {
if (defaultInstance == null) {
defaultInstance = new FrameworkModel();
}
@ -128,10 +170,17 @@ public class FrameworkModel extends ScopeModel {
return defaultInstance;
}
/**
* Get all framework model instances
* @return
*/
public static List<FrameworkModel> getAllInstances() {
return Collections.unmodifiableList(allInstances);
return Collections.unmodifiableList(new ArrayList<>(allInstances));
}
/**
* Destroy all framework model instances, shutdown dubbo engine completely.
*/
public static void destroyAll() {
for (FrameworkModel frameworkModel : new ArrayList<>(allInstances)) {
frameworkModel.destroy();
@ -142,29 +191,108 @@ public class FrameworkModel extends ScopeModel {
return new ApplicationModel(this);
}
synchronized void addApplication(ApplicationModel applicationModel) {
if (!this.applicationModels.contains(applicationModel)) {
this.applicationModels.add(applicationModel);
if (!applicationModel.isInternal()) {
this.pubApplicationModels.add(applicationModel);
/**
* Get or create default application model
* @return
*/
public ApplicationModel defaultApplication() {
if (defaultAppModel == null) {
checkDestroyed();
synchronized(instLock){
resetDefaultAppModel();
if (defaultAppModel == null) {
defaultAppModel = newApplication();
}
}
}
return defaultAppModel;
}
ApplicationModel getDefaultAppModel() {
return defaultAppModel;
}
void addApplication(ApplicationModel applicationModel) {
// can not add new application if it's destroying
checkDestroyed();
synchronized (instLock){
if (!this.applicationModels.contains(applicationModel)) {
applicationModel.setInternalId(buildInternalId(getInternalId(), appIndex.getAndIncrement()));
this.applicationModels.add(applicationModel);
if (!applicationModel.isInternal()) {
this.pubApplicationModels.add(applicationModel);
}
resetDefaultAppModel();
}
applicationModel.setInternalName(buildInternalName(ApplicationModel.NAME, getInternalId(), appIndex.getAndIncrement()));
}
}
synchronized void removeApplication(ApplicationModel model) {
this.applicationModels.remove(model);
if (!model.isInternal()) {
this.pubApplicationModels.remove(model);
void removeApplication(ApplicationModel model) {
synchronized (instLock) {
this.applicationModels.remove(model);
if (!model.isInternal()) {
this.pubApplicationModels.remove(model);
}
resetDefaultAppModel();
}
}
synchronized void tryDestroy() {
if (pubApplicationModels.size() == 0) {
destroy();
void tryDestroy() {
synchronized (instLock) {
if (pubApplicationModels.size() == 0) {
destroy();
}
}
}
private void checkDestroyed() {
if (isDestroyed()) {
throw new IllegalStateException("FrameworkModel is destroyed");
}
}
private void resetDefaultAppModel() {
synchronized (instLock) {
if (this.defaultAppModel != null && !this.defaultAppModel.isDestroyed()) {
return;
}
ApplicationModel oldDefaultAppModel = this.defaultAppModel;
if (pubApplicationModels.size() > 0) {
this.defaultAppModel = pubApplicationModels.get(0);
} else {
this.defaultAppModel = null;
}
if (defaultInstance == this && oldDefaultAppModel != this.defaultAppModel) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Reset global default application from " + safeGetModelDesc(oldDefaultAppModel) + " to " + safeGetModelDesc(this.defaultAppModel));
}
}
}
}
private void resetDefaultFrameworkModel() {
synchronized (globalLock) {
if (defaultInstance != null && !defaultInstance.isDestroyed()) {
return;
}
FrameworkModel oldDefaultFrameworkModel = defaultInstance;
if (allInstances.size() > 0) {
defaultInstance = allInstances.get(0);
} else {
defaultInstance = null;
}
if (oldDefaultFrameworkModel != defaultInstance) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Reset global default framework from " + safeGetModelDesc(oldDefaultFrameworkModel) + " to " + safeGetModelDesc(defaultInstance));
}
}
}
}
private String safeGetModelDesc(ScopeModel scopeModel) {
return scopeModel != null ? scopeModel.getDesc() : null;
}
public List<ApplicationModel> getApplicationModels() {
return Collections.unmodifiableList(pubApplicationModels);
}

View File

@ -53,6 +53,10 @@ public class ModuleModel extends ScopeModel {
Assert.notNull(applicationModel, "ApplicationModel can not be null");
this.applicationModel = applicationModel;
applicationModel.addModule(this, isInternal);
if (LOGGER.isInfoEnabled()) {
LOGGER.info(getDesc() + " is created");
}
initialize();
Assert.notNull(serviceRepository, "ModuleServiceRepository can not be null");
Assert.notNull(moduleConfigManager, "ModuleConfigManager can not be null");

View File

@ -24,6 +24,7 @@ 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.utils.ConcurrentHashSet;
import org.apache.dubbo.common.utils.StringUtils;
import java.util.Collections;
import java.util.HashSet;
@ -38,25 +39,27 @@ public abstract class ScopeModel implements ExtensionAccessor {
protected static final Logger LOGGER = LoggerFactory.getLogger(ScopeModel.class);
/**
* The internal name is used to represent the hierarchy of the model tree, such as:
* The internal id is used to represent the hierarchy of the model tree, such as:
* <ol>
* <li>FrameworkModel-1</li>
* <li>1</li>
* FrameworkModel (index=1)
* <li>ApplicationModel-1.2</li>
* <li>1.2</li>
* FrameworkModel (index=1) -> ApplicationModel (index=2)
* <li>ModuleModel-1.2.0</li>
* <li>1.2.0</li>
* FrameworkModel (index=1) -> ApplicationModel (index=2) -> ModuleModel (index=0, internal module)
* <li>ModuleModel-1.2.1</li>
* <li>1.2.1</li>
* FrameworkModel (index=1) -> ApplicationModel (index=2) -> ModuleModel (index=1, first user module)
* </ol>
*/
private String internalName;
private String internalId;
/**
* Public Model Name, can be set from user
*/
private String modelName;
private String desc;
private Set<ClassLoader> classLoaders;
private final ScopeModel parent;
@ -164,15 +167,6 @@ public abstract class ScopeModel implements ExtensionAccessor {
return parent;
}
public String getInternalName() {
return internalName;
}
protected void setInternalName(String internalName) {
this.internalName = internalName;
this.modelName = internalName;
}
public void addClassLoader(ClassLoader classLoader) {
this.classLoaders.add(classLoader);
if (parent != null) {
@ -202,21 +196,21 @@ public abstract class ScopeModel implements ExtensionAccessor {
public abstract Environment getModelEnvironment();
public String getInternalId() {
// XxxModule-1.1
if (this.internalName == null) {
return null;
}
return this.internalName.substring(this.internalName.indexOf('-') + 1);
return this.internalId;
}
protected String buildInternalName(String type, String parentInternalId, long childIndex) {
// FrameworkModel-1
// ApplicationModel-1.1
// ModuleModel-1.1.1
if (parentInternalId != null) {
return type + "-" + parentInternalId + "." + childIndex;
void setInternalId(String internalId) {
this.internalId = internalId;
}
protected String buildInternalId(String parentInternalId, long childIndex) {
// FrameworkModel 1
// ApplicationModel 1.1
// ModuleModel 1.1.1
if (StringUtils.hasText(parentInternalId)) {
return parentInternalId + "." + childIndex;
} else {
return type + "-" + childIndex;
return "" + childIndex;
}
}
@ -226,5 +220,57 @@ public abstract class ScopeModel implements ExtensionAccessor {
public void setModelName(String modelName) {
this.modelName = modelName;
this.desc = buildDesc();
}
/**
* @return the describe string of this scope model
*/
public String getDesc() {
if (this.desc == null) {
this.desc = buildDesc();
}
return this.desc;
}
private String buildDesc() {
// Dubbo Framework[1]
// Dubbo Application[1.1](appName)
// Dubbo Module[1.1.1](appName/moduleName)
String type = this.getClass().getSimpleName().replace("Model", "");
String desc = "Dubbo " + type + "[" + this.getInternalId() + "]";
// append model name path
String modelNamePath = this.getModelNamePath();
if (StringUtils.hasText(modelNamePath)) {
desc += "(" + modelNamePath + ")";
}
return desc;
}
private String getModelNamePath() {
if (this instanceof ApplicationModel) {
return safeGetAppName((ApplicationModel) this);
} else if (this instanceof ModuleModel) {
String modelName = this.getModelName();
if (StringUtils.hasText(modelName)) {
// appName/moduleName
return safeGetAppName(((ModuleModel) this).getApplicationModel()) + "/" + modelName;
}
}
return null;
}
private static String safeGetAppName(ApplicationModel applicationModel) {
String modelName = applicationModel.getModelName();
if (StringUtils.isBlank(modelName)) {
modelName = "unknown"; // unknown application
}
return modelName;
}
@Override
public String toString() {
return getDesc();
}
}

View File

@ -56,9 +56,20 @@ public class ScopeModelUtil {
}
public static ApplicationModel getApplicationModel(ScopeModel scopeModel) {
return getOrDefaultApplicationModel(scopeModel);
}
public static ApplicationModel getOrDefaultApplicationModel(ScopeModel scopeModel) {
if (scopeModel == null) {
return ApplicationModel.defaultModel();
}
return getOrNullApplicationModel(scopeModel);
}
public static ApplicationModel getOrNullApplicationModel(ScopeModel scopeModel) {
if (scopeModel == null) {
return null;
}
if (scopeModel instanceof ApplicationModel) {
return (ApplicationModel) scopeModel;
} else if (scopeModel instanceof ModuleModel) {
@ -69,13 +80,6 @@ public class ScopeModelUtil {
}
}
public static ScopeModel getOrDefaultApplicationModel(ScopeModel scopeModel) {
if (scopeModel == null) {
return ApplicationModel.defaultModel();
}
return scopeModel;
}
public static FrameworkModel getFrameworkModel(ScopeModel scopeModel) {
if (scopeModel == null) {
return FrameworkModel.defaultModel();

View File

@ -0,0 +1,112 @@
/*
* 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.utils.StringUtils;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;
public class ScopeModelTest {
@Test
public void testCreateOnDestroy() throws InterruptedException {
FrameworkModel.destroyAll();
FrameworkModel frameworkModel = new FrameworkModel();
ApplicationModel applicationModel1 = frameworkModel.newApplication();
ApplicationModel applicationModel2 = frameworkModel.newApplication();
List<Throwable> errors = new ArrayList<>();
applicationModel1.addDestroyListener(scopeModel -> {
try {
try {
applicationModel1.getDefaultModule();
Assertions.fail("Cannot create new module after application model destroyed");
} catch (Exception e) {
Assertions.assertEquals("ApplicationModel is destroyed", e.getMessage(), StringUtils.toString(e));
}
try {
applicationModel1.newModule();
Assertions.fail("Cannot create new module after application model destroyed");
} catch (Exception e) {
Assertions.assertEquals("ApplicationModel is destroyed", e.getMessage(), StringUtils.toString(e));
}
} catch (Throwable e) {
errors.add(e);
}
});
CountDownLatch latch = new CountDownLatch(1);
frameworkModel.addDestroyListener(scopeModel -> {
try {
try {
frameworkModel.defaultApplication();
Assertions.fail("Cannot create new application after framework model destroyed");
} catch (Exception e) {
Assertions.assertEquals("FrameworkModel is destroyed", e.getMessage(), StringUtils.toString(e));
}
try {
frameworkModel.newApplication();
Assertions.fail("Cannot create new application after framework model destroyed");
} catch (Exception e) {
Assertions.assertEquals("FrameworkModel is destroyed", e.getMessage(), StringUtils.toString(e));
}
try {
ApplicationModel.defaultModel();
Assertions.fail("Cannot create new application after framework model destroyed");
} catch (Exception e) {
Assertions.assertEquals("FrameworkModel is destroyed", e.getMessage(), StringUtils.toString(e));
}
try {
FrameworkModel.defaultModel().defaultApplication();
Assertions.fail("Cannot create new application after framework model destroyed");
} catch (Exception e) {
Assertions.assertEquals("FrameworkModel is destroyed", e.getMessage(), StringUtils.toString(e));
}
} catch (Throwable ex) {
errors.add(ex);
} finally {
latch.countDown();
}
});
// destroy frameworkModel
frameworkModel.destroy();
latch.await();
String errorMsg = null;
for (Throwable throwable : errors) {
errorMsg = StringUtils.toString(throwable);
errorMsg += "\n";
}
Assertions.assertEquals(0, errors.size(), "Error occurred while destroy FrameworkModel: "+ errorMsg);
// destroy all FrameworkModel
FrameworkModel.destroyAll();
List<String> remainFrameworks = FrameworkModel.getAllInstances().stream().map(m -> m.getDesc()).collect(Collectors.toList());
Assertions.assertEquals(0, FrameworkModel.getAllInstances().size(), "FrameworkModel is not completely destroyed: " + remainFrameworks);
}
}

View File

@ -27,8 +27,15 @@
<param name="ConversionPattern" value="%d %p [%c:%M] - %m%n"/>
</layout>
</appender>
<appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="[%d{dd/MM/yy HH:mm:ss:SSS z}] %t %5p %c{2}: %m%n"/>
</layout>
</appender>
<root>
<level value="DEBUG"/>
<level value="INFO"/>
<appender-ref ref="dubbo"/>
<appender-ref ref="CONSOLE"/>
</root>
</log4j:configuration>
</log4j:configuration>

View File

@ -114,7 +114,6 @@ public class DefaultApplicationDeployer extends AbstractDeployer<ApplicationMode
private volatile MetadataServiceExporter metadataServiceExporter;
private ScheduledFuture<?> asyncMetadataFuture;
private String identifier;
private volatile CompletableFuture startFuture;
private DubboShutdownHook dubboShutdownHook;
private Object stateLock = new Object();
@ -238,6 +237,11 @@ public class DefaultApplicationDeployer extends AbstractDeployer<ApplicationMode
// load application config
configManager.loadConfigsOfTypeFromProps(ApplicationConfig.class);
// try set model name
if (StringUtils.isBlank(applicationModel.getModelName())) {
applicationModel.setModelName(applicationModel.tryGetApplicationName());
}
// load config centers
configManager.loadConfigsOfTypeFromProps(ConfigCenterConfig.class);
@ -273,8 +277,6 @@ public class DefaultApplicationDeployer extends AbstractDeployer<ApplicationMode
}
environment.setDynamicConfiguration(compositeDynamicConfiguration);
}
configManager.refreshAll();
}
private void startMetadataCenter() {
@ -1081,16 +1083,4 @@ public class DefaultApplicationDeployer extends AbstractDeployer<ApplicationMode
return configManager.getApplicationOrElseThrow();
}
@Override
public String getIdentifier() {
if (identifier == null) {
identifier = "Dubbo application[" + applicationModel.getInternalId() + "]";
if (applicationModel.getModelName() != null
&& !StringUtils.isEquals(applicationModel.getModelName(), applicationModel.getInternalName())) {
identifier += "(" + applicationModel.getModelName() + ")";
}
}
return identifier;
}
}

View File

@ -25,7 +25,6 @@ import org.apache.dubbo.common.deploy.ModuleDeployer;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.threadpool.manager.ExecutorRepository;
import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.config.ConsumerConfig;
import org.apache.dubbo.config.ModuleConfig;
import org.apache.dubbo.config.ProviderConfig;
@ -66,7 +65,6 @@ public class DefaultModuleDeployer extends AbstractDeployer<ModuleModel> impleme
private final ModuleConfigManager configManager;
private final SimpleReferenceCache referenceCache;
private String identifier;
private ApplicationDeployer applicationDeployer;
private CompletableFuture startFuture;
@ -436,17 +434,6 @@ public class DefaultModuleDeployer extends AbstractDeployer<ModuleModel> impleme
.isPresent();
}
public String getIdentifier() {
if (identifier == null) {
identifier = "Dubbo module[" + moduleModel.getInternalId() + "]";
if (moduleModel.getModelName() != null
&& !StringUtils.isEquals(moduleModel.getModelName(), moduleModel.getInternalName())) {
identifier += "(" + moduleModel.getModelName() + ")";
}
}
return identifier;
}
@Override
public ReferenceCache getReferenceCache() {
return referenceCache;

View File

@ -209,6 +209,7 @@ public class ServiceConfigTest {
delayService.addServiceListener(new ServiceListener() {
@Override
public void exported(ServiceConfig sc) {
assertEquals(delayService, sc);
assertThat(delayService.getExportedUrls(), hasSize(1));
latch.countDown();
}

View File

@ -129,6 +129,8 @@ public class DubboDeployApplicationListener implements ApplicationListener<Appli
} catch (Exception e) {
logger.error("An error occurred when stop dubbo module: " + e.getMessage(), e);
}
// remove context bind cache
DubboSpringInitializer.remove(event.getApplicationContext());
}
@Override

View File

@ -16,13 +16,18 @@
*/
package org.apache.dubbo.config.spring.context;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.config.spring.util.DubboBeanUtils;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.apache.dubbo.rpc.model.FrameworkModel;
import org.apache.dubbo.rpc.model.ModuleModel;
import org.apache.dubbo.rpc.model.ScopeModel;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.util.ObjectUtils;
import java.util.Map;
import java.util.Set;
@ -33,6 +38,8 @@ import java.util.concurrent.ConcurrentHashMap;
*/
public class DubboSpringInitializer {
private static final Logger logger = LoggerFactory.getLogger(DubboSpringInitializer.class);
private static Map<BeanDefinitionRegistry, DubboSpringInitContext> contextMap = new ConcurrentHashMap<>();
private DubboSpringInitializer() {
@ -40,6 +47,7 @@ public class DubboSpringInitializer {
public static void initialize(BeanDefinitionRegistry registry) {
// Spring ApplicationContext may not ready at this moment (e.g. load from xml), so use registry as key
if (contextMap.putIfAbsent(registry, new DubboSpringInitContext()) != null) {
return;
}
@ -54,6 +62,39 @@ public class DubboSpringInitializer {
initContext(context, registry, beanFactory);
}
public static boolean remove(BeanDefinitionRegistry registry) {
return contextMap.remove(registry) != null;
}
public static boolean remove(ApplicationContext springContext) {
for (Map.Entry<BeanDefinitionRegistry, DubboSpringInitContext> entry : contextMap.entrySet()) {
DubboSpringInitContext initContext = entry.getValue();
if (initContext.getApplicationContext() == springContext ||
initContext.getBeanFactory() == springContext.getAutowireCapableBeanFactory() ||
initContext.getRegistry() == springContext.getAutowireCapableBeanFactory()
) {
DubboSpringInitContext context = contextMap.remove(entry.getKey());
logger.info("Unbind " + safeGetModelDesc(context.getModuleModel()) + " from spring container: " +
ObjectUtils.identityToString(entry.getKey()));
return true;
}
}
return false;
}
static Map<BeanDefinitionRegistry, DubboSpringInitContext> getContextMap() {
return contextMap;
}
static DubboSpringInitContext findBySpringContext(ApplicationContext applicationContext) {
for (Map.Entry<BeanDefinitionRegistry, DubboSpringInitContext> entry : contextMap.entrySet()) {
DubboSpringInitContext initContext = entry.getValue();
if (initContext.getApplicationContext() == applicationContext) {
return initContext;
}
}
return null;
}
private static void initContext(DubboSpringInitContext context, BeanDefinitionRegistry registry,
ConfigurableListableBeanFactory beanFactory) {
@ -63,21 +104,28 @@ public class DubboSpringInitializer {
// customize context, you can change the bind module model via DubboSpringInitCustomizer SPI
customize(context);
// init ApplicationModel
ApplicationModel applicationModel = context.getApplicationModel();
if (applicationModel == null) {
// init ModuleModel
ModuleModel moduleModel = context.getModuleModel();
if (moduleModel == null) {
ApplicationModel applicationModel;
if (findContextForApplication(ApplicationModel.defaultModel()) == null) {
// first spring context use default application instance
applicationModel = ApplicationModel.defaultModel();
logger.info("Use default application: " + safeGetModelDesc(applicationModel));
} else {
// create an new application instance for later spring context
applicationModel = FrameworkModel.defaultModel().newApplication();
logger.info("Create new application: " + safeGetModelDesc(applicationModel));
}
// init ModuleModel
ModuleModel moduleModel = applicationModel.getDefaultModule();
moduleModel = applicationModel.getDefaultModule();
context.setModuleModel(moduleModel);
logger.info("Use default module model of target application: " + safeGetModelDesc(moduleModel));
} else {
logger.info("Use module model from customizer: " + safeGetModelDesc(moduleModel));
}
logger.info("Bind " + safeGetModelDesc(moduleModel) + " to spring container: " + ObjectUtils.identityToString(registry));
// set module attributes
if (context.getModuleAttributes().size() > 0) {
@ -94,6 +142,10 @@ public class DubboSpringInitializer {
DubboBeanUtils.registerCommonBeans(registry);
}
private static String safeGetModelDesc(ScopeModel scopeModel) {
return scopeModel != null ? scopeModel.getDesc() : null;
}
private static ConfigurableListableBeanFactory findBeanFactory(BeanDefinitionRegistry registry) {
ConfigurableListableBeanFactory beanFactory = null;
if (registry instanceof ConfigurableListableBeanFactory) {

View File

@ -14,13 +14,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dubbo.config.spring;
package org.apache.dubbo.config.spring.context;
import org.apache.dubbo.common.deploy.ApplicationDeployer;
import org.apache.dubbo.common.deploy.DeployState;
import org.apache.dubbo.common.deploy.ModuleDeployer;
import org.apache.dubbo.config.bootstrap.DubboBootstrap;
import org.apache.dubbo.config.spring.context.DubboSpringInitCustomizerHolder;
import org.apache.dubbo.config.spring.DubboStateListener;
import org.apache.dubbo.config.spring.SysProps;
import org.apache.dubbo.rpc.model.ModuleModel;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@ -58,6 +59,7 @@ public class KeepRunningOnSpringClosedTest {
Assertions.assertEquals(DeployState.STARTED, applicationDeployer.getState());
Assertions.assertEquals(true, applicationDeployer.isStarted());
Assertions.assertEquals(false, applicationDeployer.isStopped());
Assertions.assertNotNull(DubboSpringInitializer.findBySpringContext(providerContext));
// close spring context
providerContext.close();
@ -66,6 +68,7 @@ public class KeepRunningOnSpringClosedTest {
Assertions.assertEquals(DeployState.STARTED, applicationDeployer.getState());
Assertions.assertEquals(true, applicationDeployer.isStarted());
Assertions.assertEquals(false, applicationDeployer.isStopped());
Assertions.assertNull(DubboSpringInitializer.findBySpringContext(providerContext));
} finally {
DubboBootstrap.getInstance().stop();
SysProps.clear();

View File

@ -24,7 +24,7 @@
</appender>
<logger name="org.apache.dubbo.config" additivity="false">
<level value="WARN"/>
<level value="INFO"/>
<appender-ref ref="CONSOLE"/>
</logger>

View File

@ -508,6 +508,11 @@ public class InstanceAddressURL extends URL {
return instance.getOrDefaultApplicationModel();
}
@Override
public ApplicationModel getApplicationModel() {
return instance.getApplicationModel();
}
@Override
public ServiceModel getServiceModel() {
return RpcContext.getServiceContext().getConsumerUrl().getServiceModel();

View File

@ -23,6 +23,7 @@ import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.metadata.MetadataInfo;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.apache.dubbo.rpc.model.FrameworkModel;
import org.apache.dubbo.rpc.model.ModuleModel;
import org.apache.dubbo.rpc.model.ScopeModel;
import org.apache.dubbo.rpc.model.ServiceModel;
@ -294,6 +295,16 @@ public class OverrideInstanceAddressURL extends InstanceAddressURL {
return originUrl.getOrDefaultApplicationModel();
}
@Override
public ApplicationModel getApplicationModel() {
return originUrl.getApplicationModel();
}
@Override
public ModuleModel getOrDefaultModuleModel() {
return originUrl.getOrDefaultModuleModel();
}
@Override
public ServiceModel getServiceModel() {
return originUrl.getServiceModel();

View File

@ -26,6 +26,7 @@ import org.apache.dubbo.common.serialize.ObjectOutput;
import org.apache.dubbo.common.serialize.Serialization;
import org.apache.dubbo.common.utils.CollectionUtils;
import org.apache.dubbo.remoting.Constants;
import org.apache.dubbo.rpc.model.FrameworkModel;
import org.apache.dubbo.rpc.model.FrameworkServiceRepository;
import java.io.ByteArrayOutputStream;
@ -50,9 +51,10 @@ public class CodecSupport {
private static final ThreadLocal<byte[]> TL_BUFFER = ThreadLocal.withInitial(() -> new byte[1024]);
static {
Set<String> supportedExtensions = ExtensionLoader.getExtensionLoader(Serialization.class).getSupportedExtensions();
ExtensionLoader<Serialization> extensionLoader = FrameworkModel.defaultModel().getExtensionLoader(Serialization.class);
Set<String> supportedExtensions = extensionLoader.getSupportedExtensions();
for (String name : supportedExtensions) {
Serialization serialization = ExtensionLoader.getExtensionLoader(Serialization.class).getExtension(name);
Serialization serialization = extensionLoader.getExtension(name);
byte idByte = serialization.getContentTypeId();
if (ID_SERIALIZATION_MAP.containsKey(idByte)) {
logger.error("Serialization extension " + serialization.getClass().getName()

View File

@ -132,17 +132,19 @@ public class WrappedChannelHandler implements ChannelHandlerDelegate {
* @return
*/
public ExecutorService getSharedExecutorService() {
// Application may be destroyed before channel disconnected, avoid create new application model
// see https://github.com/apache/dubbo/issues/9127
if (url.getApplicationModel() == null || url.getApplicationModel().isDestroyed()) {
return GlobalResourcesRepository.getGlobalExecutorService();
}
// note: url.getOrDefaultApplicationModel() may create new application model
ApplicationModel applicationModel = url.getOrDefaultApplicationModel();
ExecutorRepository executorRepository =
applicationModel.getExtensionLoader(ExecutorRepository.class).getDefaultExtension();
ExecutorService executor = executorRepository.getExecutor(url);
if (executor == null) {
// if application is destroyed, use global executor service
if (applicationModel.isDestroyed()) {
executor = GlobalResourcesRepository.getGlobalExecutorService();
}else {
executor = executorRepository.createExecutorIfAbsent(url);
}
executor = executorRepository.createExecutorIfAbsent(url);
}
return executor;
}

View File

@ -21,7 +21,7 @@ import org.apache.dubbo.remoting.RemotingException;
import org.apache.dubbo.remoting.exchange.Request;
import org.apache.dubbo.remoting.exchange.Response;
import org.apache.dubbo.remoting.transport.dispatcher.connection.ConnectionOrderedChannelHandler;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
@ -35,6 +35,7 @@ public class ConnectChannelHandlerTest extends WrappedChannelHandlerTest {
@BeforeEach
public void setUp() throws Exception {
url = url.setScopeModel(ApplicationModel.defaultModel());
handler = new ConnectionOrderedChannelHandler(new BizChannelHandler(true), url);
}

View File

@ -27,7 +27,7 @@ import org.apache.dubbo.remoting.exchange.Request;
import org.apache.dubbo.remoting.exchange.Response;
import org.apache.dubbo.remoting.exchange.support.DefaultFuture;
import org.apache.dubbo.remoting.transport.dispatcher.WrappedChannelHandler;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -43,6 +43,7 @@ public class WrappedChannelHandlerTest {
@BeforeEach
public void setUp() throws Exception {
url = url.setScopeModel(ApplicationModel.defaultModel());
handler = new WrappedChannelHandler(new BizChannelHandler(true), url);
}

View File

@ -21,7 +21,7 @@ import org.apache.dubbo.common.utils.NetUtils;
import org.apache.dubbo.remoting.Channel;
import org.apache.dubbo.remoting.ChannelHandler;
import org.apache.dubbo.remoting.RemotingException;
import org.apache.dubbo.rpc.model.ApplicationModel;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
@ -51,8 +51,12 @@ public class ThreadNameTest {
@BeforeEach
public void before() throws Exception {
int port = NetUtils.getAvailablePort(20880 + new Random().nextInt(10000));
serverURL = URL.valueOf("telnet://localhost?side=provider").setPort(port);
clientURL = URL.valueOf("telnet://localhost?side=consumer").setPort(port);
serverURL = URL.valueOf("telnet://localhost?side=provider")
.setPort(port)
.setScopeModel(ApplicationModel.defaultModel());
clientURL = URL.valueOf("telnet://localhost?side=consumer")
.setPort(port)
.setScopeModel(ApplicationModel.defaultModel());
serverHandler = new ThreadNameVerifyHandler(serverRegex, false, serverLatch);
clientHandler = new ThreadNameVerifyHandler(clientRegex, true, clientLatch);

View File

@ -30,10 +30,12 @@ import java.lang.reflect.Type;
*/
public class Hessian2ObjectInput implements ObjectInput, Cleanable {
private final Hessian2Input mH2i;
private final Hessian2FactoryInitializer hessian2FactoryInitializer;
public Hessian2ObjectInput(InputStream is) {
mH2i = new Hessian2Input(is);
mH2i.setSerializerFactory(Hessian2FactoryInitializer.getInstance().getSerializerFactory());
hessian2FactoryInitializer = Hessian2FactoryInitializer.getInstance();
mH2i.setSerializerFactory(hessian2FactoryInitializer.getSerializerFactory());
}
@Override
@ -84,7 +86,7 @@ public class Hessian2ObjectInput implements ObjectInput, Cleanable {
@Override
public Object readObject() throws IOException {
if (!mH2i.getSerializerFactory().getClassLoader().equals(Thread.currentThread().getContextClassLoader())) {
mH2i.setSerializerFactory(Hessian2FactoryInitializer.getInstance().getSerializerFactory());
mH2i.setSerializerFactory(hessian2FactoryInitializer.getSerializerFactory());
}
return mH2i.readObject();
}
@ -94,7 +96,7 @@ public class Hessian2ObjectInput implements ObjectInput, Cleanable {
public <T> T readObject(Class<T> cls) throws IOException,
ClassNotFoundException {
if (!mH2i.getSerializerFactory().getClassLoader().equals(Thread.currentThread().getContextClassLoader())) {
mH2i.setSerializerFactory(Hessian2FactoryInitializer.getInstance().getSerializerFactory());
mH2i.setSerializerFactory(hessian2FactoryInitializer.getSerializerFactory());
}
return (T) mH2i.readObject(cls);
}
@ -102,7 +104,7 @@ public class Hessian2ObjectInput implements ObjectInput, Cleanable {
@Override
public <T> T readObject(Class<T> cls, Type type) throws IOException, ClassNotFoundException {
if (!mH2i.getSerializerFactory().getClassLoader().equals(Thread.currentThread().getContextClassLoader())) {
mH2i.setSerializerFactory(Hessian2FactoryInitializer.getInstance().getSerializerFactory());
mH2i.setSerializerFactory(hessian2FactoryInitializer.getSerializerFactory());
}
return readObject(cls);
}

View File

@ -16,23 +16,23 @@
*/
package org.apache.dubbo.common.serialize.hessian2.dubbo;
import com.alibaba.com.caucho.hessian.io.SerializerFactory;
import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.common.extension.ExtensionScope;
import org.apache.dubbo.common.extension.SPI;
import org.apache.dubbo.common.utils.StringUtils;
import com.alibaba.com.caucho.hessian.io.SerializerFactory;
import org.apache.dubbo.rpc.model.FrameworkModel;
@SPI(value = "default", scope = ExtensionScope.FRAMEWORK)
public interface Hessian2FactoryInitializer {
String WHITELIST = "dubbo.application.hessian2.whitelist";
String ALLOW = "dubbo.application.hessian2.allow";
String DENY = "dubbo.application.hessian2.deny";
ExtensionLoader<Hessian2FactoryInitializer> loader = ExtensionLoader.getExtensionLoader(Hessian2FactoryInitializer.class);
SerializerFactory getSerializerFactory();
static Hessian2FactoryInitializer getInstance() {
ExtensionLoader<Hessian2FactoryInitializer> loader = FrameworkModel.defaultModel().getExtensionLoader(Hessian2FactoryInitializer.class);
String whitelist = System.getProperty(WHITELIST);
if (StringUtils.isNotEmpty(whitelist)) {
return loader.getExtension("whitelist");

View File

@ -196,14 +196,14 @@ public class DubboTestChecker implements TestExecutionListener {
@Override
public void executionStarted(TestIdentifier testIdentifier) {
// TestSource testSource = testIdentifier.getSource().orElse(null);
// if (testSource instanceof ClassSource) {
TestSource testSource = testIdentifier.getSource().orElse(null);
if (testSource instanceof ClassSource) {
// ClassSource source = (ClassSource) testSource;
// log("Run test class: " + source.getClassName());
// } else if (testSource instanceof MethodSource) {
// MethodSource source = (MethodSource) testSource;
// log("Run test method: " + source.getClassName() + "#" + source.getMethodName());
// }
} else if (testSource instanceof MethodSource) {
MethodSource source = (MethodSource) testSource;
log("Run test method: " + source.getClassName() + "#" + source.getMethodName());
}
}
@Override