diff --git a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/filter/support/ConsumerContextFilter.java b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/filter/support/ConsumerContextFilter.java index fe78983f58..00c5a8e923 100644 --- a/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/filter/support/ConsumerContextFilter.java +++ b/dubbo-cluster/src/main/java/org/apache/dubbo/rpc/cluster/filter/support/ConsumerContextFilter.java @@ -33,12 +33,15 @@ import org.apache.dubbo.rpc.RpcInvocation; import org.apache.dubbo.rpc.TimeoutCountDown; import org.apache.dubbo.rpc.cluster.filter.ClusterFilter; import org.apache.dubbo.rpc.model.ApplicationModel; +import org.apache.dubbo.rpc.support.RpcUtils; import java.util.Map; import java.util.Set; import static org.apache.dubbo.common.constants.CommonConstants.CONSUMER; +import static org.apache.dubbo.common.constants.CommonConstants.ENABLE_TIMEOUT_COUNTDOWN_KEY; import static org.apache.dubbo.common.constants.CommonConstants.REMOTE_APPLICATION_KEY; +import static org.apache.dubbo.common.constants.CommonConstants.TIMEOUT_ATTACHMENT_KEY; import static org.apache.dubbo.common.constants.CommonConstants.TIME_COUNTDOWN_KEY; /** @@ -95,13 +98,21 @@ public class ConsumerContextFilter implements ClusterFilter, ClusterFilter.Liste } // pass default timeout set by end user (ReferenceConfig) - Object countDown = context.getObjectAttachment(TIME_COUNTDOWN_KEY); + Object countDown = RpcContext.getServerAttachment().getObjectAttachment(TIME_COUNTDOWN_KEY); if (countDown != null) { - TimeoutCountDown timeoutCountDown = (TimeoutCountDown) countDown; - if (timeoutCountDown.isExpired()) { - return AsyncRpcResult.newDefaultAsyncResult(new RpcException(RpcException.TIMEOUT_TERMINATE, - "No time left for making the following call: " + invocation.getServiceName() + "." - + invocation.getMethodName() + ", terminate directly."), invocation); + String methodName = RpcUtils.getMethodName(invocation); + // When the client has enabled the timeout-countdown function, + // the subsequent calls launched by the Server side will be enabled by default, + // and support to turn off the function on a node to get rid of the timeout control. + if (invoker.getUrl().getMethodParameter(methodName, ENABLE_TIMEOUT_COUNTDOWN_KEY, true)) { + context.setObjectAttachment(TIMEOUT_ATTACHMENT_KEY, countDown); + + TimeoutCountDown timeoutCountDown = (TimeoutCountDown) countDown; + if (timeoutCountDown.isExpired()) { + return AsyncRpcResult.newDefaultAsyncResult(new RpcException(RpcException.TIMEOUT_TERMINATE, + "No time left for making the following call: " + invocation.getServiceName() + "." + + invocation.getMethodName() + ", terminate directly."), invocation); + } } } RpcContext.removeClientResponseContext(); diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/JdkCompiler.java b/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/JdkCompiler.java index cebeaf7033..55daa1b8ba 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/JdkCompiler.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/compiler/support/JdkCompiler.java @@ -120,7 +120,8 @@ public class JdkCompiler extends AbstractCompiler { Boolean result = compiler.getTask(null, javaFileManager, diagnosticCollector, options, null, Collections.singletonList(javaFileObject)).call(); if (result == null || !result) { - throw new IllegalStateException("Compilation failed. class: " + name + ", diagnostics: " + diagnosticCollector); + throw new IllegalStateException("Compilation failed. class: " + name + ", diagnostics: " + + diagnosticCollector.getDiagnostics()); } return classLoader.loadClass(name); } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/config/Environment.java b/dubbo-common/src/main/java/org/apache/dubbo/common/config/Environment.java index de7ec54b9a..785eb11e8e 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/config/Environment.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/config/Environment.java @@ -81,7 +81,7 @@ public class Environment extends LifecycleAdapter implements ApplicationExt { public void initialize() throws IllegalStateException { if (initialized.compareAndSet(false, true)) { this.propertiesConfiguration = new PropertiesConfiguration(scopeModel); - this.systemConfiguration = new SystemConfiguration(); + this.systemConfiguration = new SystemConfiguration(scopeModel); this.environmentConfiguration = new EnvironmentConfiguration(); this.externalConfiguration = new InmemoryConfiguration("ExternalConfig"); this.appExternalConfiguration = new InmemoryConfiguration("AppExternalConfig"); diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/config/SystemConfiguration.java b/dubbo-common/src/main/java/org/apache/dubbo/common/config/SystemConfiguration.java index 9ea3c207b6..e1cb9d0c7e 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/config/SystemConfiguration.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/config/SystemConfiguration.java @@ -17,8 +17,18 @@ package org.apache.dubbo.common.config; +import org.apache.dubbo.common.logger.ErrorTypeAwareLogger; +import org.apache.dubbo.common.logger.LoggerFactory; +import org.apache.dubbo.common.threadpool.manager.FrameworkExecutorRepository; +import org.apache.dubbo.rpc.model.ScopeModel; +import org.apache.dubbo.rpc.model.ScopeModelUtil; + import java.util.Map; +import java.util.Properties; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; /** * FIXME: is this really necessary? PropertiesConfiguration should have already covered this: @@ -28,8 +38,23 @@ import java.util.concurrent.ConcurrentHashMap; */ public class SystemConfiguration implements Configuration { + private static final ErrorTypeAwareLogger logger = LoggerFactory.getErrorTypeAwareLogger(SystemConfiguration.class); + private final Map cache = new ConcurrentHashMap<>(); + private final ScheduledExecutorService sharedScheduledExecutor; + + public SystemConfiguration(ScopeModel scopeModel) { + sharedScheduledExecutor = ScopeModelUtil.getFrameworkModel(scopeModel).getBeanFactory() + .getBean(FrameworkExecutorRepository.class).getSharedScheduledExecutor(); + sharedScheduledExecutor.scheduleWithFixedDelay(() -> { + if (!cache.isEmpty()) { + Set keys = cache.keySet(); + keys.forEach((key) -> overwriteCache(key, System.getProperty(key))); + } + }, 60000, 60000, TimeUnit.MILLISECONDS); + } + @Override public Object getInternalProperty(String key) { if (cache.containsKey(key)) { @@ -72,8 +97,14 @@ public class SystemConfiguration implements Configuration { } - public Map getProperties() { - return (Map) System.getProperties(); + Properties properties = System.getProperties(); + Map res = new ConcurrentHashMap<>(properties.size()); + try { + res.putAll((Map) properties); + } catch (Exception e) { + logger.warn("System property get failed", e); + } + return res; } } diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractConfig.java b/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractConfig.java index e2bb8dc668..b0494a093e 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractConfig.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/config/AbstractConfig.java @@ -664,47 +664,7 @@ public abstract class AbstractConfig implements Serializable { try { // check and init before do refresh preProcessRefresh(); - - Environment environment = getScopeModel().getModelEnvironment(); - List> configurationMaps = environment.getConfigurationMaps(); - - // Search props starts with PREFIX in order - String preferredPrefix = null; - List prefixes = getPrefixes(); - for (String prefix : prefixes) { - if (ConfigurationUtils.hasSubProperties(configurationMaps, prefix)) { - preferredPrefix = prefix; - break; - } - } - if (preferredPrefix == null) { - preferredPrefix = prefixes.get(0); - } - // Extract sub props (which key was starts with preferredPrefix) - Collection> instanceConfigMaps = environment.getConfigurationMaps(this, preferredPrefix); - Map subProperties = ConfigurationUtils.getSubProperties(instanceConfigMaps, preferredPrefix); - InmemoryConfiguration subPropsConfiguration = new InmemoryConfiguration(subProperties); - - if (logger.isDebugEnabled()) { - String idOrName = ""; - if (StringUtils.hasText(this.getId())) { - idOrName = "[id=" + this.getId() + "]"; - } else { - String name = ReflectUtils.getProperty(this, "getName"); - if (StringUtils.hasText(name)) { - idOrName = "[name=" + name + "]"; - } - } - logger.debug("Refreshing " + this.getClass().getSimpleName() + idOrName + - " with prefix [" + preferredPrefix + - "], extracted props: " + subProperties); - } - - assignProperties(this, environment, subProperties, subPropsConfiguration); - - // process extra refresh of subclass, e.g. refresh method configs - processExtraRefresh(preferredPrefix, subPropsConfiguration); - + refreshWithPrefixes(getPrefixes(), getConfigMode()); } catch (Exception e) { logger.error(COMMON_FAILED_OVERRIDE_FIELD, "", "", "Failed to override field value of config bean: " + this, e); throw new IllegalStateException("Failed to override field value of config bean: " + this, e); @@ -714,12 +674,53 @@ public abstract class AbstractConfig implements Serializable { refreshed.set(true); } - private void assignProperties(Object obj, Environment environment, Map properties, InmemoryConfiguration configuration) { + protected void refreshWithPrefixes(List prefixes, ConfigMode configMode) { + Environment environment = getScopeModel().getModelEnvironment(); + List> configurationMaps = environment.getConfigurationMaps(); + + // Search props starts with PREFIX in order + String preferredPrefix = null; + for (String prefix : prefixes) { + if (ConfigurationUtils.hasSubProperties(configurationMaps, prefix)) { + preferredPrefix = prefix; + break; + } + } + if (preferredPrefix == null) { + preferredPrefix = prefixes.get(0); + } + // Extract sub props (which key was starts with preferredPrefix) + Collection> instanceConfigMaps = environment.getConfigurationMaps(this, preferredPrefix); + Map subProperties = ConfigurationUtils.getSubProperties(instanceConfigMaps, preferredPrefix); + InmemoryConfiguration subPropsConfiguration = new InmemoryConfiguration(subProperties); + + if (logger.isDebugEnabled()) { + String idOrName = ""; + if (StringUtils.hasText(this.getId())) { + idOrName = "[id=" + this.getId() + "]"; + } else { + String name = ReflectUtils.getProperty(this, "getName"); + if (StringUtils.hasText(name)) { + idOrName = "[name=" + name + "]"; + } + } + logger.debug("Refreshing " + this.getClass().getSimpleName() + idOrName + + " with prefix [" + preferredPrefix + + "], extracted props: " + subProperties); + } + + assignProperties(this, environment, subProperties, subPropsConfiguration, configMode); + + // process extra refresh of subclass, e.g. refresh method configs + processExtraRefresh(preferredPrefix, subPropsConfiguration); + } + + private void assignProperties(Object obj, Environment environment, Map properties, InmemoryConfiguration configuration, ConfigMode configMode) { // if old one (this) contains non-null value, do not override - boolean overrideIfAbsent = getConfigMode() == ConfigMode.OVERRIDE_IF_ABSENT; + boolean overrideIfAbsent = configMode == ConfigMode.OVERRIDE_IF_ABSENT; // even if old one (this) contains non-null value, do override - boolean overrideAll = getConfigMode() == ConfigMode.OVERRIDE_ALL; + boolean overrideAll = configMode == ConfigMode.OVERRIDE_ALL; // loop methods, get override value and set the new value back to method List methods = MethodUtils.getMethods(obj.getClass(), method -> method.getDeclaringClass() != Object.class); @@ -807,7 +808,7 @@ public abstract class AbstractConfig implements Serializable { String fieldName = MethodUtils.extractFieldName(method); Map subProperties = ConfigurationUtils.getSubProperties(properties, fieldName); InmemoryConfiguration subPropsConfiguration = new InmemoryConfiguration(subProperties); - assignProperties(inner, environment, subProperties, subPropsConfiguration); + assignProperties(inner, environment, subProperties, subPropsConfiguration, configMode); method.invoke(obj, inner); } catch (ReflectiveOperationException e) { throw new IllegalStateException("Cannot assign nested class when refreshing config: " + obj.getClass().getName(), e); diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/ReferenceConfigBase.java b/dubbo-common/src/main/java/org/apache/dubbo/config/ReferenceConfigBase.java index 493df6b2f0..c0973be012 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/config/ReferenceConfigBase.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/config/ReferenceConfigBase.java @@ -21,6 +21,7 @@ import org.apache.dubbo.common.utils.ClassUtils; import org.apache.dubbo.common.utils.RegexProperties; import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.config.annotation.Reference; +import org.apache.dubbo.config.context.ConfigMode; import org.apache.dubbo.config.support.Parameter; import org.apache.dubbo.rpc.model.ModuleModel; import org.apache.dubbo.rpc.model.ScopeModel; @@ -134,6 +135,8 @@ public abstract class ReferenceConfigBase extends AbstractReferenceConfig { .getDefaultConsumer() .orElseThrow(() -> new IllegalStateException("Default consumer is not initialized")); } + // try set properties from `dubbo.reference` if not set in current config + refreshWithPrefixes(super.getPrefixes(), ConfigMode.OVERRIDE_IF_ABSENT); } @Override diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/ServiceConfigBase.java b/dubbo-common/src/main/java/org/apache/dubbo/config/ServiceConfigBase.java index 35a930baf2..6c7a533152 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/config/ServiceConfigBase.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/config/ServiceConfigBase.java @@ -20,6 +20,7 @@ import org.apache.dubbo.common.URL; import org.apache.dubbo.common.utils.CollectionUtils; import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.config.annotation.Service; +import org.apache.dubbo.config.context.ConfigMode; import org.apache.dubbo.config.support.Parameter; import org.apache.dubbo.rpc.model.ModuleModel; import org.apache.dubbo.rpc.model.ScopeModel; @@ -174,6 +175,8 @@ public abstract class ServiceConfigBase extends AbstractServiceConfig { .getDefaultProvider() .orElseThrow(() -> new IllegalStateException("Default provider is not initialized")); } + // try set properties from `dubbo.service` if not set in current config + refreshWithPrefixes(super.getPrefixes(), ConfigMode.OVERRIDE_IF_ABSENT); } @Override diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigManager.java b/dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigManager.java index 140f9b1a3f..0ed0a3aa51 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigManager.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigManager.java @@ -272,7 +272,6 @@ public class ConfigManager extends AbstractConfigManager implements ApplicationE ApplicationConfig.class, ProtocolConfig.class, RegistryConfig.class, - MetadataReportConfig.class, MonitorConfig.class, MetricsConfig.class, SslConfig.class); diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/config/SystemConfigurationTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/config/SystemConfigurationTest.java index ddb1dfde58..67050f40d6 100644 --- a/dubbo-common/src/test/java/org/apache/dubbo/common/config/SystemConfigurationTest.java +++ b/dubbo-common/src/test/java/org/apache/dubbo/common/config/SystemConfigurationTest.java @@ -16,6 +16,7 @@ */ package org.apache.dubbo.common.config; +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; @@ -44,7 +45,7 @@ class SystemConfigurationTest { @BeforeEach public void init() { - sysConfig = new SystemConfiguration(); + sysConfig = new SystemConfiguration(ApplicationModel.defaultModel().getDefaultModule()); } /** @@ -114,4 +115,4 @@ class SystemConfigurationTest { MockTwo } -} \ No newline at end of file +} diff --git a/dubbo-common/src/test/java/org/apache/dubbo/config/context/ConfigManagerTest.java b/dubbo-common/src/test/java/org/apache/dubbo/config/context/ConfigManagerTest.java index aaa7fc604d..de5bff64f1 100644 --- a/dubbo-common/src/test/java/org/apache/dubbo/config/context/ConfigManagerTest.java +++ b/dubbo-common/src/test/java/org/apache/dubbo/config/context/ConfigManagerTest.java @@ -393,22 +393,33 @@ class ConfigManagerTest { @Test void testLoadConfigsOfTypeFromProps() { try { + System.setProperty("dubbo.protocols.dubbo1.port", "20880"); + System.setProperty("dubbo.protocols.dubbo2.port", "20881"); + System.setProperty("dubbo.protocols.rest1.port", "8080"); + System.setProperty("dubbo.protocols.rest2.port", "8081"); + + ApplicationModel.defaultModel().destroy(); + ApplicationModel applicationModel = ApplicationModel.defaultModel(); + configManager = applicationModel.getApplicationConfigManager(); + moduleConfigManager = applicationModel.getDefaultModule().getConfigManager(); + // dubbo.application.enable-file-cache = false configManager.loadConfigsOfTypeFromProps(ApplicationConfig.class); Optional application = configManager.getApplication(); Assertions.assertTrue(application.isPresent()); configManager.removeConfig(application.get()); - System.setProperty("dubbo.protocols.dubbo1.port", "20880"); - System.setProperty("dubbo.protocols.dubbo2.port", "20881"); - System.setProperty("dubbo.protocols.rest1.port", "8080"); - System.setProperty("dubbo.protocols.rest2.port", "8081"); configManager.loadConfigsOfTypeFromProps(ProtocolConfig.class); Collection protocols = configManager.getProtocols(); Assertions.assertEquals(protocols.size(), 4); System.setProperty("dubbo.applications.app1.name", "app-demo1"); System.setProperty("dubbo.applications.app2.name", "app-demo2"); + + ApplicationModel.defaultModel().destroy(); + applicationModel = ApplicationModel.defaultModel(); + configManager = applicationModel.getApplicationConfigManager(); + moduleConfigManager = applicationModel.getDefaultModule().getConfigManager(); try { configManager.loadConfigsOfTypeFromProps(ApplicationConfig.class); Assertions.fail(); @@ -456,4 +467,4 @@ class ConfigManagerTest { Assertions.assertFalse(moduleConfigManager.getConsumers().isEmpty()); } -} \ No newline at end of file +} diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/DefaultApplicationDeployer.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/DefaultApplicationDeployer.java index 6f50193e7f..04f1ef0ed0 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/DefaultApplicationDeployer.java +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/deploy/DefaultApplicationDeployer.java @@ -65,6 +65,8 @@ import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.concurrent.CompletableFuture; @@ -73,16 +75,17 @@ import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Supplier; +import java.util.stream.Collectors; import static java.lang.String.format; import static org.apache.dubbo.common.config.ConfigurationUtils.parseProperties; import static org.apache.dubbo.common.constants.CommonConstants.REGISTRY_SPLIT_PATTERN; import static org.apache.dubbo.common.constants.CommonConstants.REMOTE_METADATA_STORAGE_TYPE; -import static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_REFRESH_INSTANCE_ERROR; -import static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_REGISTER_INSTANCE_ERROR; -import static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_FAILED_START_MODEL; import static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_FAILED_EXECUTE_DESTORY; import static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_FAILED_INIT_CONFIG_CENTER; +import static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_FAILED_START_MODEL; +import static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_REFRESH_INSTANCE_ERROR; +import static org.apache.dubbo.common.constants.LoggerCodeConstants.CONFIG_REGISTER_INSTANCE_ERROR; import static org.apache.dubbo.common.constants.MetricsConstants.PROTOCOL_PROMETHEUS; import static org.apache.dubbo.common.utils.StringUtils.isEmpty; import static org.apache.dubbo.common.utils.StringUtils.isNotEmpty; @@ -302,8 +305,10 @@ public class DefaultApplicationDeployer extends AbstractDeployer validMetadataReportConfigs = new ArrayList<>(metadataReportConfigs.size()); for (MetadataReportConfig metadataReportConfig : metadataReportConfigs) { - ConfigValidationUtils.validateMetadataConfig(metadataReportConfig); - validMetadataReportConfigs.add(metadataReportConfig); + if (ConfigValidationUtils.isValidMetadataConfig(metadataReportConfig)) { + ConfigValidationUtils.validateMetadataConfig(metadataReportConfig); + validMetadataReportConfigs.add(metadataReportConfig); + } } metadataReportInstance.init(validMetadataReportConfigs); if (!metadataReportInstance.inited()) { @@ -405,41 +410,57 @@ public class DefaultApplicationDeployer extends AbstractDeployer metadataConfigs = configManager.getMetadataConfigs(); - - if (CollectionUtils.isNotEmpty(metadataConfigs)) { + Collection originMetadataConfigs = configManager.getMetadataConfigs(); + if (originMetadataConfigs.stream().anyMatch(m -> Objects.nonNull(m.getAddress()))) { return; } + Collection metadataConfigsToOverride = originMetadataConfigs + .stream() + .filter(m -> Objects.isNull(m.getAddress())) + .collect(Collectors.toList()); + + if (metadataConfigsToOverride.size() > 1) { + return; + } + + MetadataReportConfig metadataConfigToOverride = metadataConfigsToOverride.stream().findFirst().orElse(null); + List defaultRegistries = configManager.getDefaultRegistries(); - if (defaultRegistries.size() > 0) { + if (!defaultRegistries.isEmpty()) { defaultRegistries .stream() .filter(this::isUsedRegistryAsMetadataCenter) - .map(this::registryAsMetadataCenter) + .map(registryConfig -> registryAsMetadataCenter(registryConfig, metadataConfigToOverride)) .forEach(metadataReportConfig -> { - if (metadataReportConfig.getId() == null) { - Collection metadataReportConfigs = configManager.getMetadataConfigs(); - if (CollectionUtils.isNotEmpty(metadataReportConfigs)) { - for (MetadataReportConfig existedConfig : metadataReportConfigs) { - if (existedConfig.getId() == null && existedConfig.getAddress().equals(metadataReportConfig.getAddress())) { - return; - } - } - } - configManager.addMetadataReport(metadataReportConfig); - } else { - Optional configOptional = configManager.getConfig(MetadataReportConfig.class, metadataReportConfig.getId()); - if (configOptional.isPresent()) { - return; - } - configManager.addMetadataReport(metadataReportConfig); - } - logger.info("use registry as metadata-center: " + metadataReportConfig); + overrideMetadataReportConfig(metadataConfigToOverride, metadataReportConfig); }); } } + private void overrideMetadataReportConfig(MetadataReportConfig metadataConfigToOverride, MetadataReportConfig metadataReportConfig) { + if (metadataReportConfig.getId() == null) { + Collection metadataReportConfigs = configManager.getMetadataConfigs(); + if (CollectionUtils.isNotEmpty(metadataReportConfigs)) { + for (MetadataReportConfig existedConfig : metadataReportConfigs) { + if (existedConfig.getId() == null && existedConfig.getAddress().equals(metadataReportConfig.getAddress())) { + return; + } + } + } + configManager.removeConfig(metadataConfigToOverride); + configManager.addMetadataReport(metadataReportConfig); + } else { + Optional configOptional = configManager.getConfig(MetadataReportConfig.class, metadataReportConfig.getId()); + if (configOptional.isPresent()) { + return; + } + configManager.removeConfig(metadataConfigToOverride); + configManager.addMetadataReport(metadataReportConfig); + } + logger.info("use registry as metadata-center: " + metadataReportConfig); + } + private boolean isUsedRegistryAsMetadataCenter(RegistryConfig registryConfig) { return isUsedRegistryAsCenter(registryConfig, registryConfig::getUseAsMetadataCenter, "metadata", MetadataReportFactory.class); @@ -495,24 +516,37 @@ public class DefaultApplicationDeployer extends AbstractDeployer()); } if (CollectionUtils.isNotEmptyMap(registryConfig.getParameters())) { - metadataReportConfig.getParameters().putAll(registryConfig.getParameters()); // copy the parameters + for (Map.Entry entry : registryConfig.getParameters().entrySet()) { + metadataReportConfig.getParameters().putIfAbsent(entry.getKey(), entry.getValue()); // copy the parameters + } } metadataReportConfig.getParameters().put(CLIENT_KEY, registryConfig.getClient()); - metadataReportConfig.setGroup(registryConfig.getGroup()); - metadataReportConfig.setAddress(getRegistryCompatibleAddress(registryConfig)); - metadataReportConfig.setUsername(registryConfig.getUsername()); - metadataReportConfig.setPassword(registryConfig.getPassword()); - metadataReportConfig.setTimeout(registryConfig.getTimeout()); + if (metadataReportConfig.getGroup() == null) { + metadataReportConfig.setGroup(registryConfig.getGroup()); + } + if (metadataReportConfig.getAddress() == null) { + metadataReportConfig.setAddress(getRegistryCompatibleAddress(registryConfig)); + } + if (metadataReportConfig.getUsername() == null) { + metadataReportConfig.setUsername(registryConfig.getUsername()); + } + if (metadataReportConfig.getPassword() == null) { + metadataReportConfig.setPassword(registryConfig.getPassword()); + } + if (metadataReportConfig.getTimeout() == null) { + metadataReportConfig.setTimeout(registryConfig.getTimeout()); + } return metadataReportConfig; } diff --git a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/utils/ConfigValidationUtils.java b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/utils/ConfigValidationUtils.java index 4d8801a72a..78c2b0d9dd 100644 --- a/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/utils/ConfigValidationUtils.java +++ b/dubbo-config/dubbo-config-api/src/main/java/org/apache/dubbo/config/utils/ConfigValidationUtils.java @@ -512,8 +512,21 @@ public class ConfigValidationUtils { } } - public static void validateMetadataConfig(MetadataReportConfig metadataReportConfig) { + public static boolean isValidMetadataConfig(MetadataReportConfig metadataReportConfig) { if (metadataReportConfig == null) { + return false; + } + + if (Boolean.FALSE.equals(metadataReportConfig.getReportMetadata()) && + Boolean.FALSE.equals(metadataReportConfig.getReportDefinition())) { + return false; + } + + return !isEmpty(metadataReportConfig.getAddress()); + } + + public static void validateMetadataConfig(MetadataReportConfig metadataReportConfig) { + if (!isValidMetadataConfig(metadataReportConfig)) { return; } diff --git a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/MultiInstanceTest.java b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/MultiInstanceTest.java index 4ddcb4450f..2737b75c14 100644 --- a/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/MultiInstanceTest.java +++ b/dubbo-config/dubbo-config-api/src/test/java/org/apache/dubbo/config/bootstrap/MultiInstanceTest.java @@ -375,7 +375,7 @@ class MultiInstanceTest { // stop provider app 2 and check threads providerBootstrap2.stop(); // shutdown register center after dubbo application to avoid unregister services blocking - checkUnclosedThreadsOfApp(stackTraces2, "Found unclosed threads of app 2: ", null); + checkUnclosedThreadsOfApp(stackTraces2, "Found unclosed threads of app 2: ", new String[]{"Dubbo-framework-shared-scheduler"}); } finally { if (providerBootstrap1 != null) { diff --git a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/MetadataReportInstance.java b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/MetadataReportInstance.java index 98ed48bb76..65fe2689f3 100644 --- a/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/MetadataReportInstance.java +++ b/dubbo-metadata/dubbo-metadata-api/src/main/java/org/apache/dubbo/metadata/report/MetadataReportInstance.java @@ -29,10 +29,11 @@ import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY; -import static org.apache.dubbo.common.constants.CommonConstants.REGISTRY_LOCAL_FILE_CACHE_ENABLED; import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_DIRECTORY; import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_KEY; import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_METADATA_STORAGE_TYPE; +import static org.apache.dubbo.common.constants.CommonConstants.PORT_KEY; +import static org.apache.dubbo.common.constants.CommonConstants.REGISTRY_LOCAL_FILE_CACHE_ENABLED; import static org.apache.dubbo.common.utils.StringUtils.isEmpty; import static org.apache.dubbo.metadata.report.support.Constants.METADATA_REPORT_KEY; @@ -86,6 +87,7 @@ public class MetadataReportInstance implements Disposable { String protocol = url.getParameter(METADATA_REPORT_KEY, DEFAULT_DIRECTORY); url = URLBuilder.from(url) .setProtocol(protocol) + .setPort(url.getParameter(PORT_KEY, url.getPort())) .setScopeModel(config.getScopeModel()) .removeParameter(METADATA_REPORT_KEY) .build(); diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcInvocation.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcInvocation.java index 34d08ed767..b4aa155890 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcInvocation.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/RpcInvocation.java @@ -112,7 +112,7 @@ public class RpcInvocation implements Invocation, Serializable { * Deep clone of an invocation & put some service params into attachment from invoker (will not change the invoker in invocation) * * @param invocation original invocation - * @param invoker target invoker + * @param invoker target invoker */ public RpcInvocation(Invocation invocation, Invoker invoker) { this(invocation.getTargetServiceUniqueName(), invocation.getServiceModel(), invocation.getMethodName(), invocation.getServiceName(), @@ -384,6 +384,9 @@ public class RpcInvocation implements Invocation, Serializable { public Map getObjectAttachments() { try { attachmentLock.lock(); + if (attachments == null) { + attachments = new HashMap<>(); + } return attachments; } finally { attachmentLock.unlock(); diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ContextFilter.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ContextFilter.java index 6cfe9936a6..487e0238cc 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ContextFilter.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ContextFilter.java @@ -121,7 +121,7 @@ public class ContextFilter implements Filter, Filter.Listener { long timeout = RpcUtils.getTimeout(invocation, -1); if (timeout != -1) { // pass to next hop - RpcContext.getClientAttachment().setObjectAttachment(TIME_COUNTDOWN_KEY, TimeoutCountDown.newCountDown(timeout, TimeUnit.MILLISECONDS)); + RpcContext.getServerAttachment().setObjectAttachment(TIME_COUNTDOWN_KEY, TimeoutCountDown.newCountDown(timeout, TimeUnit.MILLISECONDS)); } // merged from dubbox diff --git a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/TimeoutFilter.java b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/TimeoutFilter.java index dc4aa29ac1..90e7ef9b4d 100644 --- a/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/TimeoutFilter.java +++ b/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/TimeoutFilter.java @@ -47,7 +47,7 @@ public class TimeoutFilter implements Filter, Filter.Listener { @Override public void onResponse(Result appResponse, Invoker invoker, Invocation invocation) { - Object obj = RpcContext.getClientAttachment().getObjectAttachment(TIME_COUNTDOWN_KEY); + Object obj = RpcContext.getServerAttachment().getObjectAttachment(TIME_COUNTDOWN_KEY); if (obj != null) { TimeoutCountDown countDown = (TimeoutCountDown) obj; if (countDown.isExpired()) { diff --git a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DubboInvoker.java b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DubboInvoker.java index d2d324f133..9be288b14b 100644 --- a/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DubboInvoker.java +++ b/dubbo-rpc/dubbo-rpc-dubbo/src/main/java/org/apache/dubbo/rpc/protocol/dubbo/DubboInvoker.java @@ -179,7 +179,7 @@ public class DubboInvoker extends AbstractInvoker { int timeout; if (countdown == null) { timeout = (int) RpcUtils.getTimeout(getUrl(), methodName, RpcContext.getClientAttachment(), invocation, DEFAULT_TIMEOUT); - if (getUrl().getParameter(ENABLE_TIMEOUT_COUNTDOWN_KEY, false)) { + if (getUrl().getMethodParameter(methodName, ENABLE_TIMEOUT_COUNTDOWN_KEY, false)) { invocation.setObjectAttachment(TIMEOUT_ATTACHMENT_KEY, timeout); // pass timeout to remote server } } else { @@ -187,6 +187,8 @@ public class DubboInvoker extends AbstractInvoker { timeout = (int) timeoutCountDown.timeRemaining(TimeUnit.MILLISECONDS); invocation.setObjectAttachment(TIMEOUT_ATTACHMENT_KEY, timeout);// pass timeout to remote server } + + invocation.getObjectAttachments().remove(TIME_COUNTDOWN_KEY); return timeout; } } diff --git a/dubbo-rpc/dubbo-rpc-injvm/src/main/java/org/apache/dubbo/rpc/protocol/injvm/InjvmInvoker.java b/dubbo-rpc/dubbo-rpc-injvm/src/main/java/org/apache/dubbo/rpc/protocol/injvm/InjvmInvoker.java index 99126515b6..15ddb5d598 100644 --- a/dubbo-rpc/dubbo-rpc-injvm/src/main/java/org/apache/dubbo/rpc/protocol/injvm/InjvmInvoker.java +++ b/dubbo-rpc/dubbo-rpc-injvm/src/main/java/org/apache/dubbo/rpc/protocol/injvm/InjvmInvoker.java @@ -286,7 +286,7 @@ public class InjvmInvoker extends AbstractInvoker { int timeout; if (countdown == null) { timeout = (int) RpcUtils.getTimeout(getUrl(), methodName, RpcContext.getClientAttachment(), invocation, DEFAULT_TIMEOUT); - if (getUrl().getParameter(ENABLE_TIMEOUT_COUNTDOWN_KEY, false)) { + if (getUrl().getMethodParameter(methodName, ENABLE_TIMEOUT_COUNTDOWN_KEY, false)) { invocation.setObjectAttachment(TIMEOUT_ATTACHMENT_KEY, timeout); // pass timeout to remote server } } else { @@ -294,6 +294,8 @@ public class InjvmInvoker extends AbstractInvoker { timeout = (int) timeoutCountDown.timeRemaining(TimeUnit.MILLISECONDS); invocation.setObjectAttachment(TIMEOUT_ATTACHMENT_KEY, timeout);// pass timeout to remote server } + + invocation.getObjectAttachments().remove(TIME_COUNTDOWN_KEY); return timeout; } diff --git a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleInvoker.java b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleInvoker.java index 7ad8bce6c5..be582347fb 100644 --- a/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleInvoker.java +++ b/dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/TripleInvoker.java @@ -307,7 +307,7 @@ public class TripleInvoker extends AbstractInvoker { if (countdown == null) { timeout = (int) RpcUtils.getTimeout(getUrl(), methodName, RpcContext.getClientAttachment(), invocation, 3000); - if (getUrl().getParameter(ENABLE_TIMEOUT_COUNTDOWN_KEY, false)) { + if (getUrl().getMethodParameter(methodName, ENABLE_TIMEOUT_COUNTDOWN_KEY, false)) { invocation.setObjectAttachment(TIMEOUT_ATTACHMENT_KEY, timeout); // pass timeout to remote server } @@ -317,6 +317,8 @@ public class TripleInvoker extends AbstractInvoker { invocation.setObjectAttachment(TIMEOUT_ATTACHMENT_KEY, timeout);// pass timeout to remote server } + + invocation.getObjectAttachments().remove(TIME_COUNTDOWN_KEY); return timeout; } }