diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a9b43101..276d92904 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,4 +14,5 @@ - [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) - [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) diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/AffectedConfigurationPropertiesRebinder.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/AffectedConfigurationPropertiesRebinder.java index c18c7f29e..3df9f295a 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/AffectedConfigurationPropertiesRebinder.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/AffectedConfigurationPropertiesRebinder.java @@ -18,10 +18,18 @@ package com.tencent.cloud.polaris.config.adapter; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; import java.util.HashMap; import java.util.Map; import java.util.Objects; 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.boot.context.properties.ConfigurationPropertiesBean; @@ -31,6 +39,7 @@ import org.springframework.cloud.context.properties.ConfigurationPropertiesRebin import org.springframework.context.ApplicationContext; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; /** * Optimize {@link ConfigurationPropertiesRebinder}, only rebuild affected beans. @@ -38,9 +47,11 @@ import org.springframework.util.CollectionUtils; * @author weihubeats */ public class AffectedConfigurationPropertiesRebinder extends ConfigurationPropertiesRebinder { + private static final Logger LOGGER = LoggerFactory.getLogger(AffectedConfigurationPropertiesRebinder.class); private ApplicationContext applicationContext; private Map propertiesBeans = new HashMap<>(); + private final Map> propertiesBeanDefaultValues = new ConcurrentHashMap<>(); public AffectedConfigurationPropertiesRebinder(ConfigurationPropertiesBeans beans) { super(beans); @@ -53,6 +64,7 @@ public class AffectedConfigurationPropertiesRebinder extends ConfigurationProper this.applicationContext = applicationContext; propertiesBeans = ConfigurationPropertiesBean.getAll(applicationContext); + initPropertiesBeanDefaultValues(propertiesBeans); } @Override @@ -75,8 +87,63 @@ public class AffectedConfigurationPropertiesRebinder extends ConfigurationProper .toString(); if (key.startsWith(propertiesPrefix)) { rebind(name); + rebindDefaultValue(name, key); } }); }); } + + private void rebindDefaultValue(String beanName, String key) { + String changeValue = applicationContext.getEnvironment().getProperty(key); + if (StringUtils.hasLength(changeValue)) { + return; + } + + Map 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 propertiesBeans) { + if (MapUtils.isEmpty(propertiesBeans)) { + return; + } + + for (ConfigurationPropertiesBean propertiesBean : propertiesBeans.values()) { + Map 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); + } + } } diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/ReflectionUtils.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/ReflectionUtils.java index ef706673f..68ff6ac09 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/ReflectionUtils.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/ReflectionUtils.java @@ -19,32 +19,35 @@ package com.tencent.cloud.common.util; import java.lang.reflect.Field; +import org.springframework.util.ClassUtils; + +import static java.util.Locale.ENGLISH; + /** * Reflection Utils. * * @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() { } - public static Object getFieldValue(Object instance, String fieldName) { - Field field = org.springframework.util.ReflectionUtils.findField(instance.getClass(), fieldName); - if (field == null) { - return null; - } + public static boolean writableBeanField(Field field) { + String fieldName = field.getName(); - field.setAccessible(true); - try { - return field.get(instance); - } - catch (IllegalAccessException e) { - // ignore - } - finally { - field.setAccessible(false); + String setMethodName = SET_PREFIX + capitalize(fieldName); + + return ClassUtils.hasMethod(field.getDeclaringClass(), setMethodName, field.getType()); + } + + public static String capitalize(String name) { + if (name == null || name.length() == 0) { + return name; } - return null; + return name.substring(0, 1).toUpperCase(ENGLISH) + name.substring(1); } + } diff --git a/spring-cloud-tencent-examples/polaris-config-example/src/main/java/com/tencent/cloud/polaris/config/example/Person.java b/spring-cloud-tencent-examples/polaris-config-example/src/main/java/com/tencent/cloud/polaris/config/example/Person.java index 1a88235de..38bb2cae6 100644 --- a/spring-cloud-tencent-examples/polaris-config-example/src/main/java/com/tencent/cloud/polaris/config/example/Person.java +++ b/spring-cloud-tencent-examples/polaris-config-example/src/main/java/com/tencent/cloud/polaris/config/example/Person.java @@ -18,6 +18,8 @@ package com.tencent.cloud.polaris.config.example; +import java.util.List; + import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; @@ -34,6 +36,10 @@ public class Person { private int age; + private boolean director; + + private List students; + public String getName() { return name; } @@ -50,8 +56,29 @@ public class Person { this.age = age; } + public boolean isDirector() { + return director; + } + + public void setDirector(boolean director) { + this.director = director; + } + + public List getStudents() { + return students; + } + + public void setStudents(List students) { + this.students = students; + } + @Override public String toString() { - return "User{" + "name='" + name + '\'' + ", age=" + age + '}'; + return "Person{" + + "name='" + name + '\'' + + ", age=" + age + + ", director=" + director + + ", students=" + students + + '}'; } }