support delete config for ConfigurationProperties bean (#755)

Co-authored-by: Haotian Zhang <928016560@qq.com>
pull/767/head
lepdou 2 years ago committed by GitHub
parent 1fcfd5b9b0
commit bed6f384b5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -14,4 +14,5 @@
- [fix:fix discovery junit.](https://github.com/Tencent/spring-cloud-tencent/pull/728) - [fix:fix discovery junit.](https://github.com/Tencent/spring-cloud-tencent/pull/728)
- [adapt polaris-java 1.10.1 version](https://github.com/Tencent/spring-cloud-tencent/pull/748) - [adapt polaris-java 1.10.1 version](https://github.com/Tencent/spring-cloud-tencent/pull/748)
- [Optimize: change RouteArgument.buildCustom to RouteArgument.fromLabel](https://github.com/Tencent/spring-cloud-tencent/pull/750) - [Optimize: change RouteArgument.buildCustom to RouteArgument.fromLabel](https://github.com/Tencent/spring-cloud-tencent/pull/750)
- [Optimize: support delete config for ConfigurationProperties bean](https://github.com/Tencent/spring-cloud-tencent/pull/755)
- [Bugfix: get service instances by Flux.blockLast() to resolve concurrent problem](https://github.com/Tencent/spring-cloud-tencent/pull/763) - [Bugfix: get service instances by Flux.blockLast() to resolve concurrent problem](https://github.com/Tencent/spring-cloud-tencent/pull/763)

@ -18,10 +18,18 @@
package com.tencent.cloud.polaris.config.adapter; package com.tencent.cloud.polaris.config.adapter;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import com.tencent.cloud.common.util.ReflectionUtils;
import com.tencent.polaris.api.utils.MapUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
import org.springframework.boot.context.properties.ConfigurationPropertiesBean; import org.springframework.boot.context.properties.ConfigurationPropertiesBean;
@ -31,6 +39,7 @@ import org.springframework.cloud.context.properties.ConfigurationPropertiesRebin
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
/** /**
* Optimize {@link ConfigurationPropertiesRebinder}, only rebuild affected beans. * Optimize {@link ConfigurationPropertiesRebinder}, only rebuild affected beans.
@ -38,9 +47,11 @@ import org.springframework.util.CollectionUtils;
* @author weihubeats * @author weihubeats
*/ */
public class AffectedConfigurationPropertiesRebinder extends ConfigurationPropertiesRebinder { public class AffectedConfigurationPropertiesRebinder extends ConfigurationPropertiesRebinder {
private static final Logger LOGGER = LoggerFactory.getLogger(AffectedConfigurationPropertiesRebinder.class);
private ApplicationContext applicationContext; private ApplicationContext applicationContext;
private Map<String, ConfigurationPropertiesBean> propertiesBeans = new HashMap<>(); private Map<String, ConfigurationPropertiesBean> propertiesBeans = new HashMap<>();
private final Map<String, Map<String, Object>> propertiesBeanDefaultValues = new ConcurrentHashMap<>();
public AffectedConfigurationPropertiesRebinder(ConfigurationPropertiesBeans beans) { public AffectedConfigurationPropertiesRebinder(ConfigurationPropertiesBeans beans) {
super(beans); super(beans);
@ -53,6 +64,7 @@ public class AffectedConfigurationPropertiesRebinder extends ConfigurationProper
this.applicationContext = applicationContext; this.applicationContext = applicationContext;
propertiesBeans = ConfigurationPropertiesBean.getAll(applicationContext); propertiesBeans = ConfigurationPropertiesBean.getAll(applicationContext);
initPropertiesBeanDefaultValues(propertiesBeans);
} }
@Override @Override
@ -75,8 +87,63 @@ public class AffectedConfigurationPropertiesRebinder extends ConfigurationProper
.toString(); .toString();
if (key.startsWith(propertiesPrefix)) { if (key.startsWith(propertiesPrefix)) {
rebind(name); rebind(name);
rebindDefaultValue(name, key);
} }
}); });
}); });
} }
private void rebindDefaultValue(String beanName, String key) {
String changeValue = applicationContext.getEnvironment().getProperty(key);
if (StringUtils.hasLength(changeValue)) {
return;
}
Map<String, Object> defaultValues = propertiesBeanDefaultValues.get(beanName);
if (MapUtils.isEmpty(defaultValues)) {
return;
}
try {
String fieldName = key.substring(key.lastIndexOf(".") + 1);
Object bean = applicationContext.getBean(beanName);
Field field = ReflectionUtils.findField(bean.getClass(), fieldName);
if (field != null) {
field.setAccessible(true);
field.set(bean, defaultValues.get(fieldName));
}
}
catch (Exception e) {
LOGGER.error("[SCT Config] rebind default value error, bean = {}, key = {}", beanName, key);
}
}
private void initPropertiesBeanDefaultValues(Map<String, ConfigurationPropertiesBean> propertiesBeans) {
if (MapUtils.isEmpty(propertiesBeans)) {
return;
}
for (ConfigurationPropertiesBean propertiesBean : propertiesBeans.values()) {
Map<String, Object> defaultValues = new HashMap<>();
try {
Object instance = propertiesBean.getInstance().getClass().getDeclaredConstructor((Class<?>[]) null)
.newInstance();
ReflectionUtils.doWithFields(instance.getClass(), field -> {
try {
field.setAccessible(true);
defaultValues.put(field.getName(), field.get(instance));
}
catch (Exception ignored) {
}
}, field -> {
int modifiers = field.getModifiers();
return !Modifier.isFinal(modifiers) && !Modifier.isStatic(modifiers) && ReflectionUtils.writableBeanField(field);
});
}
catch (Exception ignored) {
}
propertiesBeanDefaultValues.put(propertiesBean.getName(), defaultValues);
}
}
} }

@ -19,32 +19,35 @@ package com.tencent.cloud.common.util;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import org.springframework.util.ClassUtils;
import static java.util.Locale.ENGLISH;
/** /**
* Reflection Utils. * Reflection Utils.
* *
* @author Haotian Zhang * @author Haotian Zhang
*/ */
public final class ReflectionUtils { public final class ReflectionUtils extends org.springframework.util.ReflectionUtils {
private final static String SET_PREFIX = "set";
private ReflectionUtils() { private ReflectionUtils() {
} }
public static Object getFieldValue(Object instance, String fieldName) { public static boolean writableBeanField(Field field) {
Field field = org.springframework.util.ReflectionUtils.findField(instance.getClass(), fieldName); String fieldName = field.getName();
if (field == null) {
return null;
}
field.setAccessible(true); String setMethodName = SET_PREFIX + capitalize(fieldName);
try {
return field.get(instance); return ClassUtils.hasMethod(field.getDeclaringClass(), setMethodName, field.getType());
} }
catch (IllegalAccessException e) {
// ignore public static String capitalize(String name) {
} if (name == null || name.length() == 0) {
finally { return name;
field.setAccessible(false);
} }
return null; return name.substring(0, 1).toUpperCase(ENGLISH) + name.substring(1);
} }
} }

@ -18,6 +18,8 @@
package com.tencent.cloud.polaris.config.example; package com.tencent.cloud.polaris.config.example;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@ -34,6 +36,10 @@ public class Person {
private int age; private int age;
private boolean director;
private List<String> students;
public String getName() { public String getName() {
return name; return name;
} }
@ -50,8 +56,29 @@ public class Person {
this.age = age; this.age = age;
} }
public boolean isDirector() {
return director;
}
public void setDirector(boolean director) {
this.director = director;
}
public List<String> getStudents() {
return students;
}
public void setStudents(List<String> students) {
this.students = students;
}
@Override @Override
public String toString() { public String toString() {
return "User{" + "name='" + name + '\'' + ", age=" + age + '}'; return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", director=" + director +
", students=" + students +
'}';
} }
} }

Loading…
Cancel
Save