From 55b7a7cc4b46bce1c9ca71dfdbbbea1af02c8d9e Mon Sep 17 00:00:00 2001 From: shedfreewu <49236872+shedfreewu@users.noreply.github.com> Date: Fri, 9 Jan 2026 15:40:38 +0800 Subject: [PATCH] fix: fix parsing ConfigurationProperties value with RefreshScope. (#1780) Skip recursive parsing of JDK built-in classes and limit recursion depth to avoid OOM. --- CHANGELOG.md | 1 + .../annotation/SpringValueProcessor.java | 52 +- .../RefreshScopeSpringProcessorTest.java | 489 +++++++++++++++++- .../callee/QuickstartCalleeController.java | 8 +- .../callee/config/RefreshScopeProperties.java | 63 +++ 5 files changed, 600 insertions(+), 13 deletions(-) create mode 100644 spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/config/RefreshScopeProperties.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 59d3ccf56..62f050c1a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,3 +14,4 @@ - [feat: support kafka lane.](https://github.com/Tencent/spring-cloud-tencent/pull/1765) - [fix: ApplicationContextAwareUtils may not be ready in postProcessAfterInitialization.](https://github.com/Tencent/spring-cloud-tencent/pull/1779) - [refactor:optimize metadata context operation.](https://github.com/Tencent/spring-cloud-tencent/pull/1773) +- [fix: fix parsing ConfigurationProperties value with RefreshScope.](https://github.com/Tencent/spring-cloud-tencent/pull/1780) diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/annotation/SpringValueProcessor.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/annotation/SpringValueProcessor.java index 4a4e2950f..fc676e2e6 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/annotation/SpringValueProcessor.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/annotation/SpringValueProcessor.java @@ -117,6 +117,28 @@ public class SpringValueProcessor extends PolarisProcessor implements BeanDefini return clazz.isArray() || Collection.class.isAssignableFrom(clazz) || Map.class.isAssignableFrom(clazz); } + /** + * whether the class is enum. + * @param clazz the class under analysis. + * @return true if the class is enum, otherwise false. + */ + private static boolean isEnum(Class clazz) { + return clazz.isEnum(); + } + + /** + * whether the class is jdk built-in class. + * @param clazz the class under analysis. + * @return true if the class is jdk built-in class, otherwise false. + */ + private static boolean isJdkBuiltInClass(Class clazz) { + String packageName = clazz.getPackageName(); + // match java.*, javax.* and jakarta.* as built-in classes + return packageName.startsWith("java.") + || packageName.startsWith("javax.") + || packageName.startsWith("jakarta."); + } + @Override public void postProcessBeanFactory(@NonNull ConfigurableListableBeanFactory beanFactory) throws BeansException { @@ -256,24 +278,38 @@ public class SpringValueProcessor extends PolarisProcessor implements BeanDefini * @param prefix prefix or subclass's prefix of @ConfigurationProperties bean. */ private void parseConfigKeys(Class configClazz, String prefix) { + parseConfigKeys(configClazz, prefix, 0); + } + + private void parseConfigKeys(Class configClazz, String prefix, int depth) { + // Prevent infinite recursion and StackOverflowError + if (depth > 5) { + LOGGER.debug("Recursion depth limit reached for class: {}, prefix: {}", configClazz.getName(), prefix); + return; + } + for (Field field : findAllField(configClazz)) { - if (isPrimitiveOrWrapper(field.getType())) { + if (field.getType().equals(configClazz)) { + // ignore self reference + continue; + } + if (isCollection(field.getType())) { // lowerCamel format - springValueRegistry.putRefreshScopeKey(prefix + field.getName()); + springValueRegistry.putRefreshScopePrefixKey(prefix + field.getName()); // lower-hyphen format - springValueRegistry.putRefreshScopeKey( + springValueRegistry.putRefreshScopePrefixKey( prefix + CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN, field.getName())); } - else if (isCollection(field.getType())) { - springValueRegistry.putRefreshScopePrefixKey(prefix + field.getName()); - springValueRegistry.putRefreshScopePrefixKey( + else if (isPrimitiveOrWrapper(field.getType()) || isEnum(field.getType()) || isJdkBuiltInClass(field.getType())) { + springValueRegistry.putRefreshScopeKey(prefix + field.getName()); + springValueRegistry.putRefreshScopeKey( prefix + CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN, field.getName())); } else { // complex type, recursive parse - parseConfigKeys(field.getType(), prefix + field.getName() + "."); + parseConfigKeys(field.getType(), prefix + field.getName() + ".", depth + 1); parseConfigKeys(field.getType(), - prefix + CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN, field.getName()) + "."); + prefix + CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN, field.getName()) + ".", depth + 1); } } } diff --git a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/spring/annotation/RefreshScopeSpringProcessorTest.java b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/spring/annotation/RefreshScopeSpringProcessorTest.java index 7b05d4710..5866ddf46 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/spring/annotation/RefreshScopeSpringProcessorTest.java +++ b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/spring/annotation/RefreshScopeSpringProcessorTest.java @@ -18,11 +18,15 @@ package com.tencent.cloud.polaris.config.spring.annotation; import java.io.IOException; +import java.lang.reflect.Field; import java.net.ServerSocket; import java.util.ArrayList; +import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Objects; +import java.util.Set; +import java.util.concurrent.TimeUnit; import com.tencent.cloud.polaris.config.PolarisConfigBootstrapAutoConfiguration; import com.tencent.cloud.polaris.config.enums.RefreshType; @@ -88,6 +92,7 @@ public class RefreshScopeSpringProcessorTest { .withConfiguration(AutoConfigurations.of(TestBeanProperties1.class)) .withConfiguration(AutoConfigurations.of(TestBeanProperties2.class)) .withConfiguration(AutoConfigurations.of(TestBeanProperties3.class)) + .withConfiguration(AutoConfigurations.of(ComplexConfigurationProperties.class)) .withConfiguration(AutoConfigurations.of(PolarisConfigAutoConfiguration.class)) .withAllowBeanDefinitionOverriding(true) .withPropertyValues("spring.application.name=" + "conditionalOnConfigReflectEnabledTest") @@ -116,6 +121,7 @@ public class RefreshScopeSpringProcessorTest { // @RefreshScope and @Bean on method, @ConfigurationProperties bean in class assertThat(springValueRegistry.isRefreshScopeKey("test.properties2.name")).isTrue(); assertThat(springValueRegistry.isRefreshScopeKey("test.properties2.inner.name")).isTrue(); + assertThat(springValueRegistry.isRefreshScopeKey("test.properties2.inner2.name")).isTrue(); assertThat(springValueRegistry.isRefreshScopeKey("test.properties2.set")).isTrue(); assertThat(springValueRegistry.isRefreshScopeKey("test.properties2.list")).isTrue(); assertThat(springValueRegistry.isRefreshScopeKey("test.properties2.list[0]")).isTrue(); @@ -123,6 +129,9 @@ public class RefreshScopeSpringProcessorTest { assertThat(springValueRegistry.isRefreshScopeKey("test.properties2.array[0]")).isTrue(); assertThat(springValueRegistry.isRefreshScopeKey("test.properties2.map")).isTrue(); assertThat(springValueRegistry.isRefreshScopeKey("test.properties2.map.key")).isTrue(); + assertThat(springValueRegistry.isRefreshScopeKey("test.properties2.timeUnit")).isTrue(); + assertThat(springValueRegistry.isRefreshScopeKey("test.properties2.time-unit")).isTrue(); + assertThat(springValueRegistry.isRefreshScopeKey("test.properties2.date")).isTrue(); assertThat(springValueRegistry.isRefreshScopeKey("test.properties2.notExist")).isFalse(); // @RefreshScope and @ConfigurationProperties on @Component bean @@ -130,6 +139,68 @@ public class RefreshScopeSpringProcessorTest { assertThat(springValueRegistry.isRefreshScopeKey("test.properties3.notExist")).isFalse(); // @RefreshScope and @Bean on method, @Value bean in class assertThat(springValueRegistry.isRefreshScopeKey("test.bean5.name")).isTrue(); + + // Complex ConfigurationProperties tests + // Primitive fields + assertThat(springValueRegistry.isRefreshScopeKey("test.complex.properties.name")).isTrue(); + assertThat(springValueRegistry.isRefreshScopeKey("test.complex.properties.port")).isTrue(); + assertThat(springValueRegistry.isRefreshScopeKey("test.complex.properties.enabled")).isTrue(); + assertThat(springValueRegistry.isRefreshScopeKey("test.complex.properties.timeout")).isTrue(); + // Enum and JDK built-in types + assertThat(springValueRegistry.isRefreshScopeKey("test.complex.properties.timeUnit")).isTrue(); + assertThat(springValueRegistry.isRefreshScopeKey("test.complex.properties.time-unit")).isTrue(); + assertThat(springValueRegistry.isRefreshScopeKey("test.complex.properties.createdDate")).isTrue(); + assertThat(springValueRegistry.isRefreshScopeKey("test.complex.properties.created-date")).isTrue(); + // Collections + assertThat(springValueRegistry.isRefreshScopeKey("test.complex.properties.level1List")).isTrue(); + assertThat(springValueRegistry.isRefreshScopeKey("test.complex.properties.level1-list")).isTrue(); + assertThat(springValueRegistry.isRefreshScopeKey("test.complex.properties.level1Map")).isTrue(); + assertThat(springValueRegistry.isRefreshScopeKey("test.complex.properties.level1-map")).isTrue(); + + // Level 1 nested properties + assertThat(springValueRegistry.isRefreshScopeKey("test.complex.properties.level1.level1Name")).isTrue(); + assertThat(springValueRegistry.isRefreshScopeKey("test.complex.properties.level1.level1-name")).isTrue(); + assertThat(springValueRegistry.isRefreshScopeKey("test.complex.properties.level1.level1Value")).isTrue(); + assertThat(springValueRegistry.isRefreshScopeKey("test.complex.properties.level1.level1-value")).isTrue(); + assertThat(springValueRegistry.isRefreshScopeKey("test.complex.properties.level1.level1List")).isTrue(); + + // Level 2 nested properties + assertThat(springValueRegistry.isRefreshScopeKey("test.complex.properties.level1.level2.level2Name")).isTrue(); + assertThat(springValueRegistry.isRefreshScopeKey("test.complex.properties.level1.level2.level2-name")).isTrue(); + assertThat(springValueRegistry.isRefreshScopeKey("test.complex.properties.level1.level2.level2Enabled")).isTrue(); + assertThat(springValueRegistry.isRefreshScopeKey("test.complex.properties.level1.level2.level2-enabled")).isTrue(); + assertThat(springValueRegistry.isRefreshScopeKey("test.complex.properties.level1.level2.level2Map")).isTrue(); + + // Level 3 nested properties + assertThat(springValueRegistry.isRefreshScopeKey("test.complex.properties.level1.level2.level3.level3Name")).isTrue(); + assertThat(springValueRegistry.isRefreshScopeKey("test.complex.properties.level1.level2.level3.level3-name")).isTrue(); + assertThat(springValueRegistry.isRefreshScopeKey("test.complex.properties.level1.level2.level3.level3Value")).isTrue(); + assertThat(springValueRegistry.isRefreshScopeKey("test.complex.properties.level1.level2.level3.level3-value")).isTrue(); + assertThat(springValueRegistry.isRefreshScopeKey("test.complex.properties.level1.level2.level3.level3Array")).isTrue(); + + // Level 4 nested properties + assertThat(springValueRegistry.isRefreshScopeKey("test.complex.properties.level1.level2.level3.level4.level4Name")).isTrue(); + assertThat(springValueRegistry.isRefreshScopeKey("test.complex.properties.level1.level2.level3.level4.level4-name")).isTrue(); + assertThat(springValueRegistry.isRefreshScopeKey("test.complex.properties.level1.level2.level3.level4.level4Value")).isTrue(); + assertThat(springValueRegistry.isRefreshScopeKey("test.complex.properties.level1.level2.level3.level4.level4-value")).isTrue(); + assertThat(springValueRegistry.isRefreshScopeKey("test.complex.properties.level1.level2.level3.level4.level4Set")).isTrue(); + + // Level 5 nested properties + assertThat(springValueRegistry.isRefreshScopeKey("test.complex.properties.level1.level2.level3.level4.level5.level5Name")).isTrue(); + assertThat(springValueRegistry.isRefreshScopeKey("test.complex.properties.level1.level2.level3.level4.level5.level5-name")).isTrue(); + assertThat(springValueRegistry.isRefreshScopeKey("test.complex.properties.level1.level2.level3.level4.level5.level5Value")).isTrue(); + assertThat(springValueRegistry.isRefreshScopeKey("test.complex.properties.level1.level2.level3.level4.level5.level5-value")).isTrue(); + + // Level 6 should not be registered due to depth limit (depth > 5) + assertThat(springValueRegistry.isRefreshScopeKey("test.complex.properties.level1.level2.level3.level4.level5.level6.level6Name")).isFalse(); + assertThat(springValueRegistry.isRefreshScopeKey("test.complex.properties.level1.level2.level3.level4.level5.level6.level6-name")).isFalse(); + + // not self reference + Field refreshScopeKeysField = SpringValueRegistry.class.getDeclaredField("refreshScopeKeys"); + refreshScopeKeysField.setAccessible(true); + Set callbackMap = (Set) refreshScopeKeysField.get(springValueRegistry); + long selfCont = callbackMap.stream().filter(key -> key.contains("self")).count(); + assertThat(selfCont).isEqualTo(0); }); } @@ -154,12 +225,11 @@ public class RefreshScopeSpringProcessorTest { @RefreshScope private static class ValueTest { - ValueTest() { - } - private static String name; @Value("${timeout:1000}") private int timeout; + ValueTest() { + } public int getTimeout() { return timeout; @@ -274,6 +344,12 @@ public class RefreshScopeSpringProcessorTest { private InnerProperties inner; + private InnerProperties inner2; + + private TimeUnit timeUnit; + + private Date date; + public String getName() { return name; } @@ -321,6 +397,30 @@ public class RefreshScopeSpringProcessorTest { public void setInner(InnerProperties inner) { this.inner = inner; } + + public InnerProperties getInner2() { + return inner2; + } + + public void setInner2(InnerProperties inner2) { + this.inner2 = inner2; + } + + public TimeUnit getTimeUnit() { + return timeUnit; + } + + public void setTimeUnit(TimeUnit timeUnit) { + this.timeUnit = timeUnit; + } + + public Date getDate() { + return date; + } + + public void setDate(Date date) { + this.date = date; + } } @Component @@ -350,4 +450,387 @@ public class RefreshScopeSpringProcessorTest { } } + /** + * Complex ConfigurationProperties for testing various scenarios: + * - Self-referencing nested properties + * - Deep nesting (more than 5 levels) + * - Static fields + * - Final fields + * - Collections with complex types + * - Multiple levels of nested objects + */ + @Component + @RefreshScope + @ConfigurationProperties(prefix = "test.complex.properties") + static class ComplexConfigurationProperties { + + // Static field - should be ignored by Spring + private static String staticField = "static-value"; + + // Final field with default value + private final String finalField = "final-value"; + + // Primitive types + private String name; + private int port; + private boolean enabled; + private long timeout; + + // Self-referencing nested property + private ComplexConfigurationProperties self; + + // Level 1 nested object + private Level1Properties level1; + + // Collection of complex types + private ArrayList level1List; + private HashMap level1Map; + + // Enum type + private TimeUnit timeUnit; + + // JDK built-in types + private Date createdDate; + + public static String getStaticField() { + return staticField; + } + + public static void setStaticField(String staticField) { + ComplexConfigurationProperties.staticField = staticField; + } + + public String getFinalField() { + return finalField; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getPort() { + return port; + } + + public void setPort(int port) { + this.port = port; + } + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public long getTimeout() { + return timeout; + } + + public void setTimeout(long timeout) { + this.timeout = timeout; + } + + public ComplexConfigurationProperties getSelf() { + return self; + } + + public void setSelf(ComplexConfigurationProperties self) { + this.self = self; + } + + public Level1Properties getLevel1() { + return level1; + } + + public void setLevel1(Level1Properties level1) { + this.level1 = level1; + } + + public ArrayList getLevel1List() { + return level1List; + } + + public void setLevel1List(ArrayList level1List) { + this.level1List = level1List; + } + + public HashMap getLevel1Map() { + return level1Map; + } + + public void setLevel1Map(HashMap level1Map) { + this.level1Map = level1Map; + } + + public TimeUnit getTimeUnit() { + return timeUnit; + } + + public void setTimeUnit(TimeUnit timeUnit) { + this.timeUnit = timeUnit; + } + + public Date getCreatedDate() { + return createdDate; + } + + public void setCreatedDate(Date createdDate) { + this.createdDate = createdDate; + } + } + + /** + * Level 1 nested properties + */ + static class Level1Properties { + private String level1Name; + private int level1Value; + + // Level 2 nested object + private Level2Properties level2; + + // Collection at level 1 + private ArrayList level1List; + + public String getLevel1Name() { + return level1Name; + } + + public void setLevel1Name(String level1Name) { + this.level1Name = level1Name; + } + + public int getLevel1Value() { + return level1Value; + } + + public void setLevel1Value(int level1Value) { + this.level1Value = level1Value; + } + + public Level2Properties getLevel2() { + return level2; + } + + public void setLevel2(Level2Properties level2) { + this.level2 = level2; + } + + public ArrayList getLevel1List() { + return level1List; + } + + public void setLevel1List(ArrayList level1List) { + this.level1List = level1List; + } + } + + /** + * Level 2 nested properties + */ + static class Level2Properties { + private String level2Name; + private boolean level2Enabled; + + // Level 3 nested object + private Level3Properties level3; + + // Map at level 2 + private HashMap level2Map; + + public String getLevel2Name() { + return level2Name; + } + + public void setLevel2Name(String level2Name) { + this.level2Name = level2Name; + } + + public boolean isLevel2Enabled() { + return level2Enabled; + } + + public void setLevel2Enabled(boolean level2Enabled) { + this.level2Enabled = level2Enabled; + } + + public Level3Properties getLevel3() { + return level3; + } + + public void setLevel3(Level3Properties level3) { + this.level3 = level3; + } + + public HashMap getLevel2Map() { + return level2Map; + } + + public void setLevel2Map(HashMap level2Map) { + this.level2Map = level2Map; + } + } + + /** + * Level 3 nested properties + */ + static class Level3Properties { + private String level3Name; + private double level3Value; + + // Level 4 nested object + private Level4Properties level4; + + // Array at level 3 + private String[] level3Array; + + public String getLevel3Name() { + return level3Name; + } + + public void setLevel3Name(String level3Name) { + this.level3Name = level3Name; + } + + public double getLevel3Value() { + return level3Value; + } + + public void setLevel3Value(double level3Value) { + this.level3Value = level3Value; + } + + public Level4Properties getLevel4() { + return level4; + } + + public void setLevel4(Level4Properties level4) { + this.level4 = level4; + } + + public String[] getLevel3Array() { + return level3Array; + } + + public void setLevel3Array(String[] level3Array) { + this.level3Array = level3Array; + } + } + + /** + * Level 4 nested properties + */ + static class Level4Properties { + private String level4Name; + private float level4Value; + + // Level 5 nested object + private Level5Properties level5; + + // Set at level 4 + private HashSet level4Set; + + public String getLevel4Name() { + return level4Name; + } + + public void setLevel4Name(String level4Name) { + this.level4Name = level4Name; + } + + public float getLevel4Value() { + return level4Value; + } + + public void setLevel4Value(float level4Value) { + this.level4Value = level4Value; + } + + public Level5Properties getLevel5() { + return level5; + } + + public void setLevel5(Level5Properties level5) { + this.level5 = level5; + } + + public HashSet getLevel4Set() { + return level4Set; + } + + public void setLevel4Set(HashSet level4Set) { + this.level4Set = level4Set; + } + } + + /** + * Level 5 nested properties + */ + static class Level5Properties { + // Final field at deep level + private final String level5FinalField = "level5-final"; + private String level5Name; + private byte level5Value; + // Level 6 nested object - this will exceed the depth limit + private Level6Properties level6; + + public String getLevel5Name() { + return level5Name; + } + + public void setLevel5Name(String level5Name) { + this.level5Name = level5Name; + } + + public byte getLevel5Value() { + return level5Value; + } + + public void setLevel5Value(byte level5Value) { + this.level5Value = level5Value; + } + + public Level6Properties getLevel6() { + return level6; + } + + public void setLevel6(Level6Properties level6) { + this.level6 = level6; + } + + public String getLevel5FinalField() { + return level5FinalField; + } + } + + /** + * Level 6 nested properties - exceeds depth limit + */ + static class Level6Properties { + private String level6Name; + private short level6Value; + + public String getLevel6Name() { + return level6Name; + } + + public void setLevel6Name(String level6Name) { + this.level6Name = level6Name; + } + + public short getLevel6Value() { + return level6Value; + } + + public void setLevel6Value(short level6Value) { + this.level6Value = level6Value; + } + } + } diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java index 08bfb2e2d..e9d75c001 100644 --- a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/QuickstartCalleeController.java @@ -24,6 +24,7 @@ import java.util.concurrent.TimeoutException; import com.tencent.cloud.common.constant.MetadataConstant; import com.tencent.cloud.quickstart.callee.config.DataSourceProperties; +import com.tencent.cloud.quickstart.callee.config.RefreshScopeProperties; import com.tencent.cloud.quickstart.callee.pojo.User; import com.tencent.cloud.quickstart.callee.service.FaultToleranceService; import org.slf4j.Logger; @@ -70,6 +71,9 @@ public class QuickstartCalleeController { @Autowired private FaultToleranceService faultToleranceService; + @Autowired + private RefreshScopeProperties refreshScopeProperties; + /** * Get sum of two value. * @param value1 value 1 @@ -88,8 +92,8 @@ public class QuickstartCalleeController { */ @GetMapping("/info") public String info(@RequestParam(required = false) String param) { - LOG.info("Quickstart [{}] Service [{}:{}] is called with param [{}]. datasource = [{}].", appName, ip, port, param, dataSourceProperties); - return String.format("Quickstart [%s] Service [%s:%s] is called with param [%s]. datasource = [%s].", appName, ip, port, param, dataSourceProperties); + LOG.info("Quickstart [{}] Service [{}:{}] is called with param [{}]. datasource = [{}]. refreshscope = [{}].", appName, ip, port, param, dataSourceProperties, refreshScopeProperties); + return String.format("Quickstart [%s] Service [%s:%s] is called with param [%s]. datasource = [%s]. refreshscope = [%s].", appName, ip, port, param, dataSourceProperties, refreshScopeProperties); } @PostMapping("/user") diff --git a/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/config/RefreshScopeProperties.java b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/config/RefreshScopeProperties.java new file mode 100644 index 000000000..6c5476f8c --- /dev/null +++ b/spring-cloud-tencent-examples/quickstart-example/quickstart-callee-service-a/src/main/java/com/tencent/cloud/quickstart/callee/config/RefreshScopeProperties.java @@ -0,0 +1,63 @@ +/* + * Tencent is pleased to support the open source community by making spring-cloud-tencent available. + * + * Copyright (C) 2021 Tencent. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.quickstart.callee.config; + +import java.util.concurrent.TimeUnit; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.cloud.context.config.annotation.RefreshScope; +import org.springframework.stereotype.Component; + +/** + * Example for ConfigurationProperties with @RefreshScope. + * + * @author Haotian Zhang + */ +@Component +@ConfigurationProperties("refreshscope") +@RefreshScope +public class RefreshScopeProperties { + + private static String staticString; + + private TimeUnit timeUnit = TimeUnit.SECONDS; + + String getStaticString() { + return staticString; + } + + void setStaticString(String staticString) { + RefreshScopeProperties.staticString = staticString; + } + + TimeUnit getTimeUnit() { + return timeUnit; + } + + void setTimeUnit(TimeUnit timeUnit) { + this.timeUnit = timeUnit; + } + + @Override + public String toString() { + return "RefreshScopeProperties{" + + "staticString='" + staticString + '\'' + + ", timeUnit=" + timeUnit + + '}'; + } +}