You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by al...@apache.org on 2022/01/26 03:41:18 UTC
[dubbo] branch 3.0 updated: [3.0] Add ignore properties support (#9628)
This is an automated email from the ASF dual-hosted git repository.
albumenj pushed a commit to branch 3.0
in repository https://gitbox.apache.org/repos/asf/dubbo.git
The following commit(s) were added to refs/heads/3.0 by this push:
new dfe4fca [3.0] Add ignore properties support (#9628)
dfe4fca is described below
commit dfe4fcaea107ac292e6f2e967807a0756f59c7e3
Author: Albumen Kevin <jh...@gmail.com>
AuthorDate: Wed Jan 26 11:40:56 2022 +0800
[3.0] Add ignore properties support (#9628)
---
.../org/apache/dubbo/config/AbstractConfig.java | 143 ++++++++++++++++++++-
.../config/context/AbstractConfigManager.java | 24 +++-
.../apache/dubbo/config/context/ConfigManager.java | 2 +-
.../apache/dubbo/config/context/ConfigMode.java | 10 ++
4 files changed, 171 insertions(+), 8 deletions(-)
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 4dc78b3..563b56d 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
@@ -31,6 +31,7 @@ import org.apache.dubbo.common.utils.MethodUtils;
import org.apache.dubbo.common.utils.ReflectUtils;
import org.apache.dubbo.common.utils.StringUtils;
import org.apache.dubbo.config.context.ConfigManager;
+import org.apache.dubbo.config.context.ConfigMode;
import org.apache.dubbo.config.support.Nested;
import org.apache.dubbo.config.support.Parameter;
import org.apache.dubbo.rpc.model.ApplicationModel;
@@ -255,6 +256,10 @@ public abstract class AbstractConfig implements Serializable {
return propertyName;
}
+ private static String calculatePropertyToGetter(String name) {
+ return "get" + name.substring(0, 1).toUpperCase() + name.substring(1);
+ }
+
private static String calculatePropertyFromGetter(String name) {
int i = name.startsWith("get") ? 3 : 2;
return StringUtils.camelToSplitName(name.substring(i, i + 1).toLowerCase() + name.substring(i + 1), ".");
@@ -415,6 +420,7 @@ public abstract class AbstractConfig implements Serializable {
* }
* }
* </pre>
+ *
* @param oldScopeModel
* @param newScopeModel
*/
@@ -558,6 +564,84 @@ public abstract class AbstractConfig implements Serializable {
return CommonConstants.DUBBO + "." + getTagName(cls);
}
+ public ConfigMode getConfigMode() {
+ return getApplicationModel().getApplicationConfigManager().getConfigMode();
+ }
+
+ public void overrideWithConfig(AbstractConfig newOne, boolean overrideAll) {
+ if (!Objects.equals(this.getClass(), newOne.getClass())) {
+ // ignore if two config is not the same class
+ return;
+ }
+
+ List<Method> methods = MethodUtils.getMethods(this.getClass(), method -> method.getDeclaringClass() != Object.class);
+ for (Method method : methods) {
+ try {
+ Method getterMethod;
+ try {
+ String propertyName = extractPropertyName(method.getName());
+ String getterName = calculatePropertyToGetter(propertyName);
+ getterMethod = this.getClass().getDeclaredMethod(getterName);
+ } catch (Exception ignore) {
+ continue;
+ }
+
+ if (MethodUtils.isSetter(method)) {
+ Object oldOne = getterMethod.invoke(this);
+
+ // if old one is null or need to override
+ if (overrideAll || oldOne == null) {
+ Object newResult = getterMethod.invoke(newOne);
+ // if new one is non-null and new one is not equals old one
+ if (newResult != null && Objects.equals(newResult, oldOne)) {
+ method.invoke(this, newResult);
+ }
+ }
+ } else if (isParametersSetter(method)) {
+ Object oldOne = getterMethod.invoke(this);
+ Object newResult = getterMethod.invoke(newOne);
+
+ Map<String, String> oldMap = null;
+ if (oldOne instanceof Map) {
+ oldMap = (Map) oldOne;
+ }
+
+ Map<String, String> newMap = null;
+ if (newResult instanceof Map) {
+ newMap = (Map) newResult;
+ }
+
+ // if new map is null, skip
+ if (newMap == null) {
+ continue;
+ }
+
+ // if old map is null, override with new map
+ if (oldMap == null) {
+ invokeSetParameters(newMap, this);
+ continue;
+ }
+
+ // if mode is OVERRIDE_IF_ABSENT, put all old map entries to new map, will override the same key
+ // if mode is OVERRIDE_ALL, put all keyed entries not in new map from old map to new map (ignore the same key appeared in old map)
+ if (overrideAll) {
+ oldMap.forEach(newMap::putIfAbsent);
+ } else {
+ newMap.putAll(oldMap);
+ }
+
+ invokeSetParameters(newMap, this);
+ } else if (isNestedSetter(this, method)) {
+ // not support
+ }
+
+ } catch (Throwable t) {
+ logger.error("Failed to override field value of config bean: " + this, t);
+ throw new IllegalStateException("Failed to override field value of config bean: " + this, t);
+ }
+ }
+ }
+
/**
* Dubbo config property override
*/
@@ -615,11 +699,23 @@ public abstract class AbstractConfig implements Serializable {
}
private void assignProperties(Object obj, Environment environment, Map<String, String> properties, InmemoryConfiguration configuration) {
+ // if old one (this) contains non-null value, do not override
+ boolean overrideIfAbsent = getConfigMode() == ConfigMode.OVERRIDE_IF_ABSENT;
+
+ // even if old one (this) contains non-null value, do override
+ boolean overrideAll = getConfigMode() == ConfigMode.OVERRIDE_ALL;
+
// loop methods, get override value and set the new value back to method
List<Method> methods = MethodUtils.getMethods(obj.getClass(), method -> method.getDeclaringClass() != Object.class);
for (Method method : methods) {
if (MethodUtils.isSetter(method)) {
String propertyName = extractPropertyName(method.getName());
+
+ // if config mode is OVERRIDE_IF_ABSENT and property has set, skip
+ if (overrideIfAbsent && isPropertySet(propertyName)) {
+ continue;
+ }
+
// convert camelCase/snake_case to kebab-case
String kebabPropertyName = StringUtils.convertToSplitName(propertyName, "-");
@@ -639,6 +735,20 @@ public abstract class AbstractConfig implements Serializable {
}
} else if (isParametersSetter(method)) {
String propertyName = extractPropertyName(method.getName());
+
+ // get old map from original obj
+ Map<String, String> oldMap = null;
+ try {
+ String getterName = calculatePropertyToGetter(propertyName);
+ Method getterMethod = this.getClass().getDeclaredMethod(getterName);
+ Object oldOne = getterMethod.invoke(this);
+ if (oldOne instanceof Map) {
+ oldMap = (Map) oldOne;
+ }
+ } catch (Exception ignore) {
+
+ }
+
String value = StringUtils.trim(configuration.getString(propertyName));
Map<String, String> parameterMap;
if (StringUtils.hasText(value)) {
@@ -647,7 +757,24 @@ public abstract class AbstractConfig implements Serializable {
// in this case, maybe parameters.item3=value3.
parameterMap = ConfigurationUtils.getSubProperties(properties, PARAMETERS);
}
- invokeSetParameters(convert(parameterMap, ""), obj);
+ Map<String, String> newMap = convert(parameterMap, "");
+
+ // if old map is null, directly set params
+ if (oldMap == null) {
+ invokeSetParameters(newMap, obj);
+ continue;
+ }
+
+ // if mode is OVERRIDE_IF_ABSENT, put all old map entries to new map, will override the same key
+ // if mode is OVERRIDE_ALL, put all keyed entries not in new map from old map to new map (ignore the same key appeared in old map)
+ // if mode is others, override with new map
+ if (overrideIfAbsent) {
+ newMap.putAll(oldMap);
+ } else if (overrideAll) {
+ oldMap.forEach(newMap::putIfAbsent);
+ }
+
+ invokeSetParameters(newMap, obj);
} else if (isNestedSetter(obj, method)) {
try {
Class<?> clazz = method.getParameterTypes()[0];
@@ -664,6 +791,20 @@ public abstract class AbstractConfig implements Serializable {
}
}
+ private boolean isPropertySet(String propertyName) {
+ try {
+ String getterName = calculatePropertyToGetter(propertyName);
+ Method getterMethod = this.getClass().getDeclaredMethod(getterName);
+ Object oldOne = getterMethod.invoke(this);
+ if (oldOne != null) {
+ return true;
+ }
+ } catch (Exception ignore) {
+
+ }
+ return false;
+ }
+
private void invokeSetParameters(Map<String, String> values, Object obj) {
if (CollectionUtils.isEmptyMap(values)) {
return;
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/context/AbstractConfigManager.java b/dubbo-common/src/main/java/org/apache/dubbo/config/context/AbstractConfigManager.java
index 69c6771..ebd903b 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/config/context/AbstractConfigManager.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/config/context/AbstractConfigManager.java
@@ -266,11 +266,7 @@ public abstract class AbstractConfigManager extends LifecycleAdapter {
}
// check unique config
- Optional<C> oldOne = checkUniqueConfig(configsMap, config);
- if (oldOne != null) {
- return oldOne;
- }
- return Optional.empty();
+ return checkUniqueConfig(configsMap, config);
}
public <C extends AbstractConfig> Map<String, C> getConfigsMap(Class<C> cls) {
@@ -448,9 +444,25 @@ public abstract class AbstractConfigManager extends LifecycleAdapter {
}
break;
}
+ case OVERRIDE_ALL: {
+ // override old one's properties with the new one
+ oldOne.overrideWithConfig(config, true);
+ if (logger.isWarnEnabled() && duplicatedConfigs.add(config)) {
+ logger.warn(msgPrefix + "override previous config with later config");
+ }
+ return Optional.of(oldOne);
+ }
+ case OVERRIDE_IF_ABSENT: {
+ // override old one's properties with the new one
+ oldOne.overrideWithConfig(config, false);
+ if (logger.isWarnEnabled() && duplicatedConfigs.add(config)) {
+ logger.warn(msgPrefix + "override previous config with later config");
+ }
+ return Optional.of(oldOne);
+ }
}
}
- return null;
+ return Optional.empty();
}
public abstract void loadConfigs();
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 a6f4484..e599eb7 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
@@ -297,7 +297,7 @@ public class ConfigManager extends AbstractConfigManager implements ApplicationE
}
}
- ConfigMode getConfigMode() {
+ public ConfigMode getConfigMode() {
return configMode;
}
}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigMode.java b/dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigMode.java
index 5474a48..634a907 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigMode.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/config/context/ConfigMode.java
@@ -32,6 +32,16 @@ public enum ConfigMode {
OVERRIDE,
/**
+ * Override mode: accept last config, override previous config
+ */
+ OVERRIDE_ALL,
+
+ /**
+ * Override mode: accept last config, override previous config
+ */
+ OVERRIDE_IF_ABSENT,
+
+ /**
* Ignore mode: accept first config, ignore later configs
*/
IGNORE