diff --git a/CHANGELOG.md b/CHANGELOG.md index 383b6ed98..473dfbe13 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,8 +5,10 @@ - [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) - [Feature:support multi register and discovery both to nacos and polaris.](https://github.com/Tencent/spring-cloud-tencent/pull/693) - [Code optimize & add junit tests.](https://github.com/Tencent/spring-cloud-tencent/pull/701) - [Optimize: remote deprecated method](https://github.com/Tencent/spring-cloud-tencent/pull/697) - [Test:support environment variable metadata test](https://github.com/Tencent/spring-cloud-tencent/pull/698) -- [Test: remote deprecated method in test](https://github.com/Tencent/spring-cloud-tencent/pull/706) \ No newline at end of file +- [Test: remote deprecated method in test](https://github.com/Tencent/spring-cloud-tencent/pull/706) +- [docs:update README.](https://github.com/Tencent/spring-cloud-tencent/pull/718) \ No newline at end of file diff --git a/README-zh.md b/README-zh.md index 309365a7e..06875b20a 100644 --- a/README-zh.md +++ b/README-zh.md @@ -7,7 +7,6 @@ [![Build Status](https://github.com/Tencent/spring-cloud-tencent/actions/workflows/junit_test.yml/badge.svg)](https://github.com/Tencent/spring-cloud-tencent/actions/workflows/junit_test.yml) [![codecov.io](https://codecov.io/gh/Tencent/spring-cloud-tencent/branch/2021.0/graph/badge.svg)](https://codecov.io/gh/Tencent/spring-cloud-tencent?branch=2021.0) -[![Language grade: Java](https://img.shields.io/lgtm/grade/java/g/Tencent/spring-cloud-tencent.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/Tencent/spring-cloud-tencent/context:java) [English](./README.md) | 简体中文 @@ -108,23 +107,26 @@ You can build this project with command: ## 文档 - 使用文档 - - [Spring Cloud Tencent Version Management](https://github.com/Tencent/spring-cloud-tencent/wiki/Spring-Cloud-Tencent-%E7%89%88%E6%9C%AC%E7%AE%A1%E7%90%86) - - [Spring Cloud Tencent Discovery](https://github.com/Tencent/spring-cloud-tencent/wiki/Spring-Cloud-Tencent-Discovery-%E4%BD%BF%E7%94%A8%E6%96%87%E6%A1%A3) - - [Spring Cloud Tencent Config](https://github.com/Tencent/spring-cloud-tencent/wiki/Spring-Cloud-Tencent-Config-%E4%BD%BF%E7%94%A8%E6%96%87%E6%A1%A3) - - [Spring Cloud Tencent Rate Limit](https://github.com/Tencent/spring-cloud-tencent/wiki/Spring-Cloud-Tencent-Rate-Limit-%E4%BD%BF%E7%94%A8%E6%96%87%E6%A1%A3) - - [Spring Cloud Tencent CircuitBreaker](https://github.com/Tencent/spring-cloud-tencent/wiki/Spring-Cloud-Tencent-Circuitbreaker-%E4%BD%BF%E7%94%A8%E6%96%87%E6%A1%A3) - - [Spring Cloud Tencent Router](https://github.com/Tencent/spring-cloud-tencent/wiki/Spring-Cloud-Tencent-Router-%E4%BD%BF%E7%94%A8%E6%96%87%E6%A1%A3) - - [Spring Cloud Starter Tencent RPC Enhancement](https://github.com/Tencent/spring-cloud-tencent/wiki/RPC%E5%A2%9E%E5%BC%BA) - - [Spring Cloud Tencent Metadata Transfer](https://github.com/Tencent/spring-cloud-tencent/wiki/Spring-Cloud-Tencent-Metadata-Transfer-%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97) - - [Actuator Endpoint Extension](https://github.com/Tencent/spring-cloud-tencent/wiki/Actuator-Endpoint-%E6%89%A9%E5%B1%95) + - [Spring Cloud Tencent 版本管理](https://github.com/Tencent/spring-cloud-tencent/wiki/Spring-Cloud-Tencent-%E7%89%88%E6%9C%AC%E7%AE%A1%E7%90%86) + - [服务注册与发现](https://github.com/Tencent/spring-cloud-tencent/wiki/Spring-Cloud-Tencent-Discovery-%E4%BD%BF%E7%94%A8%E6%96%87%E6%A1%A3) + - [配置中心](https://github.com/Tencent/spring-cloud-tencent/wiki/Spring-Cloud-Tencent-Config-%E4%BD%BF%E7%94%A8%E6%96%87%E6%A1%A3) + - [服务限流](https://github.com/Tencent/spring-cloud-tencent/wiki/Spring-Cloud-Tencent-Rate-Limit-%E4%BD%BF%E7%94%A8%E6%96%87%E6%A1%A3) + - [服务熔断](https://github.com/Tencent/spring-cloud-tencent/wiki/Spring-Cloud-Tencent-Circuitbreaker-%E4%BD%BF%E7%94%A8%E6%96%87%E6%A1%A3) + - [服务路由](https://github.com/Tencent/spring-cloud-tencent/wiki/Spring-Cloud-Tencent-Router-%E4%BD%BF%E7%94%A8%E6%96%87%E6%A1%A3) + - [RPC增强](https://github.com/Tencent/spring-cloud-tencent/wiki/RPC%E5%A2%9E%E5%BC%BA) + - [元数据传递](https://github.com/Tencent/spring-cloud-tencent/wiki/Spring-Cloud-Tencent-Metadata-Transfer-%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97) + - [场景化插件](https://github.com/Tencent/spring-cloud-tencent/wiki/场景化插件) + - [Actuator Endpoint 扩展](https://github.com/Tencent/spring-cloud-tencent/wiki/Actuator-Endpoint-%E6%89%A9%E5%B1%95) - 最佳实践 - - [Multi-feature environment](https://github.com/Tencent/spring-cloud-tencent/wiki/%E5%A4%9A%E7%89%B9%E6%80%A7%E7%8E%AF%E5%A2%83) - - [Multi-registration and multi-discovery](https://github.com/Tencent/spring-cloud-tencent/wiki/Multi-registration-and-multi-discovery) + - [可观测性实践](https://github.com/Tencent/spring-cloud-tencent/wiki/可观测性实践) + - [测试环境路由](https://github.com/Tencent/spring-cloud-tencent/wiki/%E6%B5%8B%E8%AF%95%E7%8E%AF%E5%A2%83%E8%B7%AF%E7%94%B1) + - [Spring Cloud Gateway 流量染色](https://github.com/Tencent/spring-cloud-tencent/wiki/Spring-Cloud-Gateway-%E6%B5%81%E9%87%8F%E6%9F%93%E8%89%B2) + - [多注册与多发现](https://github.com/Tencent/spring-cloud-tencent/wiki/Multi-registration-and-multi-discovery) - 开发文档 - - [Project Structure Overview](https://github.com/Tencent/spring-cloud-tencent/wiki/%E9%A1%B9%E7%9B%AE%E6%A6%82%E8%A7%88) - - [Participate in co-construction](https://github.com/Tencent/spring-cloud-tencent/wiki/%E5%8F%82%E4%B8%8E%E5%85%B1%E5%BB%BA) + - [项目概览](https://github.com/Tencent/spring-cloud-tencent/wiki/%E9%A1%B9%E7%9B%AE%E6%A6%82%E8%A7%88) + - [参与共建](https://github.com/Tencent/spring-cloud-tencent/wiki/%E5%8F%82%E4%B8%8E%E5%85%B1%E5%BB%BA) ## 交流群 diff --git a/README.md b/README.md index beb5abde4..d54558221 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,6 @@ [![Build Status](https://github.com/Tencent/spring-cloud-tencent/actions/workflows/junit_test.yml/badge.svg)](https://github.com/Tencent/spring-cloud-tencent/actions/workflows/junit_test.yml) [![codecov.io](https://codecov.io/gh/Tencent/spring-cloud-tencent/branch/2021.0/graph/badge.svg)](https://codecov.io/gh/Tencent/spring-cloud-tencent?branch=2021.0) -[![Language grade: Java](https://img.shields.io/lgtm/grade/java/g/Tencent/spring-cloud-tencent.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/Tencent/spring-cloud-tencent/context:java) English | [简体中文](./README-zh.md) @@ -115,10 +114,13 @@ You can build this project with command: - [Spring Cloud Tencent Router](https://github.com/Tencent/spring-cloud-tencent/wiki/Spring-Cloud-Tencent-Router-%E4%BD%BF%E7%94%A8%E6%96%87%E6%A1%A3) - [Spring Cloud Starter Tencent RPC Enhancement](https://github.com/Tencent/spring-cloud-tencent/wiki/RPC%E5%A2%9E%E5%BC%BA) - [Spring Cloud Tencent Metadata Transfer](https://github.com/Tencent/spring-cloud-tencent/wiki/Spring-Cloud-Tencent-Metadata-Transfer-%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97) + - [Spring Cloud Tencent Plugins](https://github.com/Tencent/spring-cloud-tencent/wiki/%E5%9C%BA%E6%99%AF%E5%8C%96%E6%8F%92%E4%BB%B6) - [Actuator Endpoint Extension](https://github.com/Tencent/spring-cloud-tencent/wiki/Actuator-Endpoint-%E6%89%A9%E5%B1%95) - Best Practices + - [Observability Practice](https://github.com/Tencent/spring-cloud-tencent/wiki/%E5%8F%AF%E8%A7%82%E6%B5%8B%E6%80%A7%E5%AE%9E%E8%B7%B5) - [Multi-feature environment](https://github.com/Tencent/spring-cloud-tencent/wiki/%E5%A4%9A%E7%89%B9%E6%80%A7%E7%8E%AF%E5%A2%83) + - [Spring Cloud Gateway Traffic Staining](https://github.com/Tencent/spring-cloud-tencent/wiki/Spring-Cloud-Gateway-%E6%B5%81%E9%87%8F%E6%9F%93%E8%89%B2) - [Multi-registration and multi-discovery](https://github.com/Tencent/spring-cloud-tencent/wiki/Multi-registration-and-multi-discovery) - Development documentation 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..711df1483 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. @@ -39,9 +48,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 +66,7 @@ public class AffectedConfigurationPropertiesRebinder extends ConfigurationProper this.applicationContext = applicationContext; propertiesBeans = ConfigurationPropertiesBean.getAll(applicationContext); + initPropertiesBeanDefaultValues(propertiesBeans); } @Override @@ -75,8 +89,62 @@ 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..bc2e20c9d 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,16 +19,34 @@ 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 boolean writableBeanField(Field field) { + String fieldName = field.getName(); + 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 name.substring(0, 1).toUpperCase(ENGLISH) + name.substring(1); + } + public static Object getFieldValue(Object instance, String fieldName) { Field field = org.springframework.util.ReflectionUtils.findField(instance.getClass(), fieldName); if (field == null) { 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..3b3348ea4 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 @@ -34,6 +34,8 @@ public class Person { private int age; + private boolean isDirector; + public String getName() { return name; } @@ -50,8 +52,17 @@ public class Person { this.age = age; } + + public boolean isDirector() { + return isDirector; + } + + public void setIsDirector(boolean isDirector) { + this.isDirector = isDirector; + } + @Override public String toString() { - return "User{" + "name='" + name + '\'' + ", age=" + age + '}'; + return "User{" + "name='" + name + '\'' + ", age=" + age + ", isDirector=" + isDirector + '\'' + '}'; } }