diff --git a/CHANGELOG.md b/CHANGELOG.md index 80e984266..28cbc5e5e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,3 +5,4 @@ - [Optimize/optimize annotation.](https://github.com/Tencent/spring-cloud-tencent/pull/672) - [Optimize: Register the service with the ProviderAPI#registerInstance method.](https://github.com/Tencent/spring-cloud-tencent/pull/686) - [docs:update PR template.](https://github.com/Tencent/spring-cloud-tencent/pull/690) +- [enhancement: revert default value when the field is deleted in @ConfigurationProperties bean](https://github.com/Tencent/spring-cloud-tencent/issues/681) 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..ec248d2b1 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,11 +18,17 @@ 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.polaris.api.utils.MapUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.BeansException; import org.springframework.boot.context.properties.ConfigurationPropertiesBean; import org.springframework.cloud.context.environment.EnvironmentChangeEvent; @@ -31,6 +37,8 @@ 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.ReflectionUtils; +import org.springframework.util.StringUtils; /** * Optimize {@link ConfigurationPropertiesRebinder}, only rebuild affected beans. @@ -39,9 +47,13 @@ import org.springframework.util.CollectionUtils; */ 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 +65,7 @@ public class AffectedConfigurationPropertiesRebinder extends ConfigurationProper this.applicationContext = applicationContext; propertiesBeans = ConfigurationPropertiesBean.getAll(applicationContext); + initPropertiesBeanDefaultValues(propertiesBeans); } @Override @@ -75,8 +88,56 @@ 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); + assert 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); + }); + }catch (Exception ignored){} + + propertiesBeanDefaultValues.put(propertiesBean.getName(), defaultValues); + } + } }