From db45a57f18c9ac763121189564a6d29cb90c0740 Mon Sep 17 00:00:00 2001
From: shouyuwang <93957183+shouyuwang@users.noreply.github.com>
Date: Thu, 23 Jun 2022 22:07:38 +0800
Subject: [PATCH 1/6] fix:fix UnknownHostException (#292)
---
CHANGELOG.md | 1 +
.../ratelimit-callee-service/pom.xml | 5 +++++
2 files changed, 6 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3427d302d..e92d54042 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,3 +4,4 @@
- [Upgrade: fix third-party lib CVEs & upgrade core spring libs version](https://github.com/Tencent/spring-cloud-tencent/pull/263)
- [feat:support reading configuration from application.yml or application.properties.](https://github.com/Tencent/spring-cloud-tencent/pull/262)
- [fix:fix ClassNotFoundException while not importing openfeign when using circuit-breaker module.](https://github.com/Tencent/spring-cloud-tencent/pull/271)
+- [fix:solve ratelimit-callee-service UnknownHostException.](https://github.com/Tencent/spring-cloud-tencent/pull/292)
diff --git a/spring-cloud-tencent-examples/polaris-ratelimit-example/ratelimit-callee-service/pom.xml b/spring-cloud-tencent-examples/polaris-ratelimit-example/ratelimit-callee-service/pom.xml
index dd28040b5..bf89b34d6 100644
--- a/spring-cloud-tencent-examples/polaris-ratelimit-example/ratelimit-callee-service/pom.xml
+++ b/spring-cloud-tencent-examples/polaris-ratelimit-example/ratelimit-callee-service/pom.xml
@@ -18,6 +18,11 @@
spring-boot-starter-web
+
+ com.tencent.cloud
+ spring-cloud-starter-tencent-polaris-discovery
+
+
com.tencent.cloudspring-cloud-starter-tencent-polaris-ratelimit
From eb72d49506990730d0e4b2e358ba2540dab05c04 Mon Sep 17 00:00:00 2001
From: Haotian Zhang <928016560@qq.com>
Date: Fri, 24 Jun 2022 15:19:44 +0800
Subject: [PATCH 2/6] Add config change listener feature support (#299)
Co-authored-by: lepdou
---
CHANGELOG.md | 1 +
.../PolarisConfigAutoConfiguration.java | 12 +
.../PolarisConfigAnnotationProcessor.java | 105 +++++++
.../PolarisConfigKVFileChangeListener.java | 58 ++++
.../config/listener/ConfigChangeEvent.java | 88 ++++++
.../config/listener/ConfigChangeListener.java | 35 +++
.../PolarisConfigChangeEventListener.java | 111 +++++++
.../PolarisConfigListenerContext.java | 277 ++++++++++++++++++
.../example/PersonConfigChangeListener.java | 49 ++++
9 files changed, 736 insertions(+)
create mode 100644 spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/annotation/PolarisConfigAnnotationProcessor.java
create mode 100644 spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/annotation/PolarisConfigKVFileChangeListener.java
create mode 100644 spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/ConfigChangeEvent.java
create mode 100644 spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/ConfigChangeListener.java
create mode 100644 spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/PolarisConfigChangeEventListener.java
create mode 100644 spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/PolarisConfigListenerContext.java
create mode 100644 spring-cloud-tencent-examples/polaris-config-example/src/main/java/com/tencent/cloud/polaris/config/example/PersonConfigChangeListener.java
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e92d54042..9f272f41d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,3 +5,4 @@
- [feat:support reading configuration from application.yml or application.properties.](https://github.com/Tencent/spring-cloud-tencent/pull/262)
- [fix:fix ClassNotFoundException while not importing openfeign when using circuit-breaker module.](https://github.com/Tencent/spring-cloud-tencent/pull/271)
- [fix:solve ratelimit-callee-service UnknownHostException.](https://github.com/Tencent/spring-cloud-tencent/pull/292)
+- [Feature: Add config change listener feature support](https://github.com/Tencent/spring-cloud-tencent/pull/299)
diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/PolarisConfigAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/PolarisConfigAutoConfiguration.java
index 79255de5f..2b61b69be 100644
--- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/PolarisConfigAutoConfiguration.java
+++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/PolarisConfigAutoConfiguration.java
@@ -20,7 +20,9 @@ package com.tencent.cloud.polaris.config;
import com.tencent.cloud.polaris.config.adapter.PolarisPropertySourceAutoRefresher;
import com.tencent.cloud.polaris.config.adapter.PolarisPropertySourceManager;
+import com.tencent.cloud.polaris.config.annotation.PolarisConfigAnnotationProcessor;
import com.tencent.cloud.polaris.config.config.PolarisConfigProperties;
+import com.tencent.cloud.polaris.config.listener.PolarisConfigChangeEventListener;
import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@@ -46,4 +48,14 @@ public class PolarisConfigAutoConfiguration {
contextRefresher);
}
+ @Bean
+ public PolarisConfigAnnotationProcessor polarisConfigAnnotationProcessor() {
+ return new PolarisConfigAnnotationProcessor();
+ }
+
+ @Bean
+ public PolarisConfigChangeEventListener polarisConfigChangeEventListener() {
+ return new PolarisConfigChangeEventListener();
+ }
+
}
diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/annotation/PolarisConfigAnnotationProcessor.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/annotation/PolarisConfigAnnotationProcessor.java
new file mode 100644
index 000000000..349799f69
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/annotation/PolarisConfigAnnotationProcessor.java
@@ -0,0 +1,105 @@
+/*
+ * Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
+ *
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. 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.polaris.config.annotation;
+
+import java.lang.reflect.Method;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Sets;
+import com.tencent.cloud.polaris.config.listener.ConfigChangeEvent;
+import com.tencent.cloud.polaris.config.listener.ConfigChangeListener;
+
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.BeanPostProcessor;
+import org.springframework.core.Ordered;
+import org.springframework.core.PriorityOrdered;
+import org.springframework.core.annotation.AnnotationUtils;
+import org.springframework.lang.NonNull;
+import org.springframework.util.ReflectionUtils;
+
+import static com.tencent.cloud.polaris.config.listener.PolarisConfigListenerContext.addChangeListener;
+
+/**
+ * {@link PolarisConfigAnnotationProcessor} implementation for spring .
+ *
Refer to the Apollo project implementation:
+ *
+ * ApolloAnnotationProcessor
+ * @author Palmer Xu 2022-06-07
+ */
+public class PolarisConfigAnnotationProcessor implements BeanPostProcessor, PriorityOrdered {
+
+ @Override
+ public Object postProcessBeforeInitialization(@NonNull Object bean, @NonNull String beanName)
+ throws BeansException {
+ Class> clazz = bean.getClass();
+ for (Method method : findAllMethod(clazz)) {
+ this.processPolarisConfigChangeListener(bean, method);
+ }
+ return bean;
+ }
+
+ @Override
+ public Object postProcessAfterInitialization(@NonNull Object bean, @NonNull String beanName) throws BeansException {
+ return bean;
+ }
+
+ @Override
+ public int getOrder() {
+ return Ordered.LOWEST_PRECEDENCE;
+ }
+
+ private List findAllMethod(Class> clazz) {
+ final List res = new LinkedList<>();
+ ReflectionUtils.doWithMethods(clazz, res::add);
+ return res;
+ }
+
+ private void processPolarisConfigChangeListener(final Object bean, final Method method) {
+ PolarisConfigKVFileChangeListener annotation = AnnotationUtils
+ .findAnnotation(method, PolarisConfigKVFileChangeListener.class);
+ if (annotation == null) {
+ return;
+ }
+ Class>[] parameterTypes = method.getParameterTypes();
+ Preconditions.checkArgument(parameterTypes.length == 1,
+ "Invalid number of parameters: %s for method: %s, should be 1", parameterTypes.length,
+ method);
+ Preconditions.checkArgument(ConfigChangeEvent.class.isAssignableFrom(parameterTypes[0]),
+ "Invalid parameter type: %s for method: %s, should be ConfigChangeEvent", parameterTypes[0],
+ method);
+
+ ReflectionUtils.makeAccessible(method);
+ String[] annotatedInterestedKeys = annotation.interestedKeys();
+ String[] annotatedInterestedKeyPrefixes = annotation.interestedKeyPrefixes();
+
+ ConfigChangeListener configChangeListener = changeEvent -> ReflectionUtils.invokeMethod(method, bean, changeEvent);
+
+ Set interestedKeys =
+ annotatedInterestedKeys.length > 0 ? Sets.newHashSet(annotatedInterestedKeys) : null;
+ Set interestedKeyPrefixes =
+ annotatedInterestedKeyPrefixes.length > 0 ? Sets.newHashSet(annotatedInterestedKeyPrefixes)
+ : null;
+
+ addChangeListener(configChangeListener, interestedKeys, interestedKeyPrefixes);
+ }
+
+}
diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/annotation/PolarisConfigKVFileChangeListener.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/annotation/PolarisConfigKVFileChangeListener.java
new file mode 100644
index 000000000..6acbf2336
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/annotation/PolarisConfigKVFileChangeListener.java
@@ -0,0 +1,58 @@
+/*
+ * Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
+ *
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. 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.polaris.config.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Configuring the change listener annotation.
+ *
Refer to the Apollo project implementation:
+ *
+ * ApolloAnnotationProcessor
+ * @author Palmer Xu 2022-05-31
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+@Documented
+public @interface PolarisConfigKVFileChangeListener {
+
+ /**
+ * The keys interested in the listener, will only be notified if any of the interested keys is changed.
+ *
+ * If neither of {@code interestedKeys} and {@code interestedKeyPrefixes} is specified then the {@code listener} will be notified when any key is changed.
+ * @return interested keys in the listener
+ */
+ String[] interestedKeys() default {};
+
+ /**
+ * The key prefixes that the listener is interested in, will be notified if and only if the changed keys start with anyone of the prefixes.
+ * The prefixes will simply be used to determine whether the {@code listener} should be notified or not using {@code changedKey.startsWith(prefix)}.
+ * e.g. "spring." means that {@code listener} is interested in keys that starts with "spring.", such as "spring.banner", "spring.jpa", etc.
+ * and "application" means that {@code listener} is interested in keys that starts with "application", such as "applicationName", "application.port", etc.
+ *
+ * If neither of {@code interestedKeys} and {@code interestedKeyPrefixes} is specified then the {@code listener} will be notified when whatever key is changed.
+ * @return interested key-prefixed in the listener
+ */
+ String[] interestedKeyPrefixes() default {};
+
+}
diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/ConfigChangeEvent.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/ConfigChangeEvent.java
new file mode 100644
index 000000000..119a5ce4c
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/ConfigChangeEvent.java
@@ -0,0 +1,88 @@
+/*
+ * Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
+ *
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. 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.polaris.config.listener;
+
+import java.util.Map;
+import java.util.Set;
+
+import com.tencent.polaris.configuration.api.core.ConfigPropertyChangeInfo;
+
+/**
+ * A change event when config is changed .
+ *
+ * @author Palmer Xu 2022-06-07
+ */
+public final class ConfigChangeEvent {
+
+ /**
+ * all changes keys map.
+ */
+ private final Map changes;
+
+ /**
+ * all interested changed keys.
+ */
+ private final Set interestedChangedKeys;
+
+ /**
+ * Config Change Event Constructor.
+ * @param changes all changes keys map
+ * @param interestedChangedKeys all interested changed keys
+ */
+ public ConfigChangeEvent(Map changes, Set interestedChangedKeys) {
+ this.changes = changes;
+ this.interestedChangedKeys = interestedChangedKeys;
+ }
+
+ /**
+ * Get the keys changed.
+ * @return the list of the keys
+ */
+ public Set changedKeys() {
+ return changes.keySet();
+ }
+
+ /**
+ * Get a specific change instance for the key specified.
+ * @param key the changed key
+ * @return the change instance
+ */
+ public ConfigPropertyChangeInfo getChange(String key) {
+ return changes.get(key);
+ }
+
+ /**
+ * Check whether the specified key is changed .
+ * @param key the key
+ * @return true if the key is changed, false otherwise.
+ */
+ public boolean isChanged(String key) {
+ return changes.containsKey(key);
+ }
+
+ /**
+ * Maybe subclass override this method.
+ *
+ * @return interested and changed keys
+ */
+ public Set interestedChangedKeys() {
+ return interestedChangedKeys;
+ }
+
+}
diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/ConfigChangeListener.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/ConfigChangeListener.java
new file mode 100644
index 000000000..14ab64a32
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/ConfigChangeListener.java
@@ -0,0 +1,35 @@
+/*
+ * Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
+ *
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. 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.polaris.config.listener;
+
+/**
+ * Configuring the change listener interface.
+ *
+ * @author Palmer Xu 2022-05-31
+ */
+public interface ConfigChangeListener {
+
+ /**
+ * Invoked when there is any config change for the namespace.
+ *
+ * @param changeEvent the event for this change
+ */
+ void onChange(ConfigChangeEvent changeEvent);
+
+}
diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/PolarisConfigChangeEventListener.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/PolarisConfigChangeEventListener.java
new file mode 100644
index 000000000..0a55255d5
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/PolarisConfigChangeEventListener.java
@@ -0,0 +1,111 @@
+/*
+ * Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
+ *
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. 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.polaris.config.listener;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import com.google.common.collect.Maps;
+import com.tencent.polaris.configuration.api.core.ConfigPropertyChangeInfo;
+
+import org.springframework.boot.context.event.ApplicationStartedEvent;
+import org.springframework.cloud.context.environment.EnvironmentChangeEvent;
+import org.springframework.context.ApplicationEvent;
+import org.springframework.context.ApplicationListener;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.core.env.ConfigurableEnvironment;
+import org.springframework.core.env.Environment;
+import org.springframework.core.env.MutablePropertySources;
+import org.springframework.lang.NonNull;
+
+import static com.tencent.cloud.polaris.config.listener.PolarisConfigListenerContext.fireConfigChange;
+import static com.tencent.cloud.polaris.config.listener.PolarisConfigListenerContext.initialize;
+import static com.tencent.cloud.polaris.config.listener.PolarisConfigListenerContext.merge;
+
+/**
+ * Polaris Config Change Event Listener .
+ *
+ * @author Elve.Xu 2022-06-08
+ */
+public final class PolarisConfigChangeEventListener implements ApplicationListener {
+
+ private static final AtomicBoolean started = new AtomicBoolean();
+
+ /**
+ * Handle an application event.
+ *
+ * @param event the event to respond to
+ */
+ @Override
+ public void onApplicationEvent(@NonNull ApplicationEvent event) {
+
+ // Initialize application all environment properties .
+ if (event instanceof ApplicationStartedEvent && started.compareAndSet(false, true)) {
+ ApplicationStartedEvent applicationStartedEvent = (ApplicationStartedEvent) event;
+ ConfigurableEnvironment environment = applicationStartedEvent.getApplicationContext().getEnvironment();
+ Map ret = loadEnvironmentProperties(environment);
+ if (!ret.isEmpty()) {
+ initialize(ret);
+ }
+ }
+
+ // Process Environment Change Event .
+ if (event instanceof EnvironmentChangeEvent) {
+ EnvironmentChangeEvent environmentChangeEvent = (EnvironmentChangeEvent) event;
+ ConfigurableApplicationContext context = (ConfigurableApplicationContext) environmentChangeEvent.getSource();
+ ConfigurableEnvironment environment = context.getEnvironment();
+ Map ret = loadEnvironmentProperties(environment);
+ Map changes = merge(ret);
+ fireConfigChange(changes.keySet(), Maps.newHashMap(changes));
+ changes.clear();
+ }
+ }
+
+ /**
+ * Try load all application environment config properties .
+ * @param environment application environment instance of {@link Environment}
+ * @return properties
+ */
+ @SuppressWarnings("unchecked")
+ private Map loadEnvironmentProperties(ConfigurableEnvironment environment) {
+ Map ret = Maps.newHashMap();
+ MutablePropertySources sources = environment.getPropertySources();
+ sources.iterator().forEachRemaining(propertySource -> {
+ Object o = propertySource.getSource();
+ if (o instanceof Map) {
+ for (Map.Entry entry : ((Map) o).entrySet()) {
+ String key = entry.getKey();
+ String value = environment.getProperty(key);
+ ret.put(key, value);
+ }
+ }
+ else if (o instanceof Collection) {
+ int count = 0;
+ Collection
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+ org.mockito
+ mockito-inline
+ test
+
+
+
+ org.mockito
+ mockito-core
+ test
+
+
+
+ net.bytebuddy
+ byte-buddy
+ test
+
diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/ConditionalOnConnectRemoteServerEnabled.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/ConditionalOnConnectRemoteServerEnabled.java
new file mode 100644
index 000000000..89283ae18
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/ConditionalOnConnectRemoteServerEnabled.java
@@ -0,0 +1,37 @@
+/*
+ * Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
+ *
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. 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.polaris.config;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+
+/**
+ * Whether to connect to a remote server, suitable for local development mode.
+ *
+ * @author lepdou 2022-06-11
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.TYPE, ElementType.METHOD })
+@ConditionalOnProperty(value = "spring.cloud.polaris.config.connect-remote-server", matchIfMissing = true)
+public @interface ConditionalOnConnectRemoteServerEnabled {
+
+}
diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/PolarisConfigBootstrapAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/PolarisConfigBootstrapAutoConfiguration.java
index d7e0eea0e..0a87c0e65 100644
--- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/PolarisConfigBootstrapAutoConfiguration.java
+++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/PolarisConfigBootstrapAutoConfiguration.java
@@ -50,24 +50,31 @@ public class PolarisConfigBootstrapAutoConfiguration {
}
@Bean
- public ConfigFileService configFileService(SDKContext sdkContext) {
- return ConfigFileServiceFactory.createConfigFileService(sdkContext);
+ public PolarisPropertySourceManager polarisPropertySourceManager() {
+ return new PolarisPropertySourceManager();
}
@Bean
- public PolarisPropertySourceManager polarisPropertySourceManager() {
- return new PolarisPropertySourceManager();
+ @ConditionalOnConnectRemoteServerEnabled
+ public ConfigFileService configFileService(SDKContext sdkContext) {
+ return ConfigFileServiceFactory.createConfigFileService(sdkContext);
}
@Bean
- public PolarisConfigFileLocator polarisConfigFileLocator(PolarisConfigProperties polarisConfigProperties,
- PolarisContextProperties polarisContextProperties, ConfigFileService configFileService,
- PolarisPropertySourceManager polarisPropertySourceManager, Environment environment) {
- return new PolarisConfigFileLocator(polarisConfigProperties, polarisContextProperties, configFileService,
+ @ConditionalOnConnectRemoteServerEnabled
+ public PolarisConfigFileLocator polarisConfigFileLocator(
+ PolarisConfigProperties polarisConfigProperties,
+ PolarisContextProperties polarisContextProperties,
+ ConfigFileService configFileService,
+ PolarisPropertySourceManager polarisPropertySourceManager,
+ Environment environment) {
+ return new PolarisConfigFileLocator(polarisConfigProperties,
+ polarisContextProperties, configFileService,
polarisPropertySourceManager, environment);
}
@Bean
+ @ConditionalOnConnectRemoteServerEnabled
public ConfigurationModifier configurationModifier(PolarisConfigProperties polarisConfigProperties,
PolarisContextProperties polarisContextProperties) {
return new ConfigurationModifier(polarisConfigProperties, polarisContextProperties);
diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFileLocator.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFileLocator.java
index a8182ec09..b23d6a132 100644
--- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFileLocator.java
+++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFileLocator.java
@@ -80,13 +80,14 @@ public class PolarisConfigFileLocator implements PropertySourceLocator {
CompositePropertySource compositePropertySource = new CompositePropertySource(
POLARIS_CONFIG_PROPERTY_SOURCE_NAME);
+ // load spring boot default config files
+ initInternalConfigFiles(compositePropertySource);
+
+ // load custom config files
List configFileGroups = polarisConfigProperties.getGroups();
if (CollectionUtils.isEmpty(configFileGroups)) {
return compositePropertySource;
}
-
- initInternalConfigFiles(compositePropertySource);
-
initCustomPolarisConfigFiles(compositePropertySource, configFileGroups);
return compositePropertySource;
@@ -181,7 +182,8 @@ public class PolarisConfigFileLocator implements PropertySourceLocator {
private PolarisPropertySource loadPolarisPropertySource(String namespace, String group, String fileName) {
ConfigKVFile configKVFile;
// unknown extension is resolved as properties file
- if (ConfigFileFormat.isPropertyFile(fileName) || ConfigFileFormat.isUnknownFile(fileName)) {
+ if (ConfigFileFormat.isPropertyFile(fileName)
+ || ConfigFileFormat.isUnknownFile(fileName)) {
configKVFile = configFileService.getConfigPropertiesFile(namespace, group, fileName);
}
else if (ConfigFileFormat.isYamlFile(fileName)) {
diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-cloud-starter-tencent-polaris-config/src/main/resources/META-INF/additional-spring-configuration-metadata.json
index ee84cbd47..9954a62ce 100644
--- a/spring-cloud-starter-tencent-polaris-config/src/main/resources/META-INF/additional-spring-configuration-metadata.json
+++ b/spring-cloud-starter-tencent-polaris-config/src/main/resources/META-INF/additional-spring-configuration-metadata.json
@@ -34,6 +34,13 @@
"defaultValue": "",
"description": "List of imported config files.",
"sourceType": "com.tencent.cloud.polaris.config.config.PolarisConfigProperties"
+ },
+ {
+ "name": "spring.cloud.polaris.config.connect-remote-server",
+ "type": "java.lang.Boolean",
+ "defaultValue": "true",
+ "description": "Whether to connect to a remote server, suitable for local development mode.",
+ "sourceType": "com.tencent.cloud.polaris.config.config.PolarisConfigProperties"
}
]
}
diff --git a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/MockedConfigKVFile.java b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/MockedConfigKVFile.java
new file mode 100644
index 000000000..026fe4d52
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/MockedConfigKVFile.java
@@ -0,0 +1,170 @@
+/*
+ * Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
+ *
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. 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.polaris.config.adapter;
+
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import com.tencent.polaris.configuration.api.core.ConfigFileChangeListener;
+import com.tencent.polaris.configuration.api.core.ConfigKVFile;
+import com.tencent.polaris.configuration.api.core.ConfigKVFileChangeEvent;
+import com.tencent.polaris.configuration.api.core.ConfigKVFileChangeListener;
+
+/**
+ * Mock config kv file for test.
+ *@author lepdou 2022-06-11
+ */
+public class MockedConfigKVFile implements ConfigKVFile {
+
+ private final Map properties;
+ private final List listeners = new ArrayList<>();
+
+ public MockedConfigKVFile(Map properties) {
+ this.properties = properties;
+ }
+
+ @Override
+ public String getProperty(String s, String s1) {
+ return String.valueOf(properties.get(s));
+ }
+
+ @Override
+ public Integer getIntProperty(String s, Integer integer) {
+ return null;
+ }
+
+ @Override
+ public Long getLongProperty(String s, Long aLong) {
+ return null;
+ }
+
+ @Override
+ public Short getShortProperty(String s, Short aShort) {
+ return null;
+ }
+
+ @Override
+ public Float getFloatProperty(String s, Float aFloat) {
+ return null;
+ }
+
+ @Override
+ public Double getDoubleProperty(String s, Double aDouble) {
+ return null;
+ }
+
+ @Override
+ public Byte getByteProperty(String s, Byte aByte) {
+ return null;
+ }
+
+ @Override
+ public Boolean getBooleanProperty(String s, Boolean aBoolean) {
+ return null;
+ }
+
+ @Override
+ public String[] getArrayProperty(String s, String s1, String[] strings) {
+ return new String[0];
+ }
+
+ @Override
+ public > T getEnumProperty(String s, Class aClass, T t) {
+ return null;
+ }
+
+ @Override
+ public T getJsonProperty(String s, Class aClass, T t) {
+ return null;
+ }
+
+ @Override
+ public T getJsonProperty(String s, Type type, T t) {
+ return null;
+ }
+
+ @Override
+ public Set getPropertyNames() {
+ return properties.keySet();
+ }
+
+ @Override
+ public void addChangeListener(ConfigKVFileChangeListener configKVFileChangeListener) {
+ listeners.add(configKVFileChangeListener);
+ }
+
+ @Override
+ public void removeChangeListener(ConfigKVFileChangeListener configKVFileChangeListener) {
+
+ }
+
+ @Override
+ public String getContent() {
+ return null;
+ }
+
+ @Override
+ public T asJson(Class aClass, T t) {
+ return null;
+ }
+
+ @Override
+ public T asJson(Type type, T t) {
+ return null;
+ }
+
+ @Override
+ public boolean hasContent() {
+ return false;
+ }
+
+ @Override
+ public void addChangeListener(ConfigFileChangeListener configFileChangeListener) {
+
+ }
+
+ @Override
+ public void removeChangeListener(ConfigFileChangeListener configFileChangeListener) {
+
+ }
+
+ public void fireChangeListener(ConfigKVFileChangeEvent event) {
+ for (ConfigKVFileChangeListener listener : listeners) {
+ listener.onChange(event);
+ }
+ }
+
+ @Override
+ public String getNamespace() {
+ return null;
+ }
+
+ @Override
+ public String getFileGroup() {
+ return null;
+ }
+
+ @Override
+ public String getFileName() {
+ return null;
+ }
+}
diff --git a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFileLocatorTest.java b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFileLocatorTest.java
new file mode 100644
index 000000000..6fe0bfa2a
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFileLocatorTest.java
@@ -0,0 +1,188 @@
+/*
+ * Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
+ *
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. 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.polaris.config.adapter;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import com.google.common.collect.Lists;
+import com.tencent.cloud.polaris.config.config.ConfigFileGroup;
+import com.tencent.cloud.polaris.config.config.PolarisConfigProperties;
+import com.tencent.cloud.polaris.context.PolarisContextProperties;
+import com.tencent.polaris.configuration.api.core.ConfigFileService;
+import com.tencent.polaris.configuration.api.core.ConfigKVFile;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import org.springframework.core.env.Environment;
+import org.springframework.core.env.PropertySource;
+
+import static org.mockito.Mockito.when;
+
+/**
+ * test for {@link PolarisConfigFileLocator}
+ *@author lepdou 2022-06-11
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class PolarisConfigFileLocatorTest {
+
+ @Mock
+ private PolarisConfigProperties polarisConfigProperties;
+ @Mock
+ private PolarisContextProperties polarisContextProperties;
+ @Mock
+ private ConfigFileService configFileService;
+ @Mock
+ private PolarisPropertySourceManager polarisPropertySourceManager;
+ @Mock
+ private Environment environment;
+
+ private final String testNamespace = "testNamespace";
+ private final String testServiceName = "testServiceName";
+
+ @Test
+ public void testLoadApplicationPropertiesFile() {
+ PolarisConfigFileLocator locator = new PolarisConfigFileLocator(polarisConfigProperties, polarisContextProperties,
+ configFileService, polarisPropertySourceManager, environment);
+
+ when(polarisContextProperties.getNamespace()).thenReturn(testNamespace);
+ when(polarisContextProperties.getService()).thenReturn(testServiceName);
+
+ // application.properties
+ Map applicationProperties = new HashMap<>();
+ applicationProperties.put("k1", "v1");
+ applicationProperties.put("k2", "v2");
+ applicationProperties.put("k3", "v3");
+ ConfigKVFile propertiesFile = new MockedConfigKVFile(applicationProperties);
+ when(configFileService.getConfigPropertiesFile(testNamespace, testServiceName, "application.properties"))
+ .thenReturn(propertiesFile);
+
+ Map emptyMap = new HashMap<>();
+ ConfigKVFile emptyConfigFile = new MockedConfigKVFile(emptyMap);
+ when(configFileService.getConfigYamlFile(testNamespace, testServiceName, "application.yml")).thenReturn(emptyConfigFile);
+ when(configFileService.getConfigPropertiesFile(testNamespace, testServiceName, "bootstrap.properties")).thenReturn(emptyConfigFile);
+ when(configFileService.getConfigYamlFile(testNamespace, testServiceName, "bootstrap.yml")).thenReturn(emptyConfigFile);
+
+ when(polarisConfigProperties.getGroups()).thenReturn(null);
+ when(environment.getActiveProfiles()).thenReturn(new String[] {});
+
+ PropertySource> propertySource = locator.locate(environment);
+
+ Assert.assertEquals("v1", propertySource.getProperty("k1"));
+ Assert.assertEquals("v2", propertySource.getProperty("k2"));
+ Assert.assertEquals("v3", propertySource.getProperty("k3"));
+ }
+
+ @Test
+ public void testActiveProfileFilesPriorityBiggerThanDefault() {
+ PolarisConfigFileLocator locator = new PolarisConfigFileLocator(polarisConfigProperties, polarisContextProperties,
+ configFileService, polarisPropertySourceManager, environment);
+
+ when(polarisContextProperties.getNamespace()).thenReturn(testNamespace);
+ when(polarisContextProperties.getService()).thenReturn(testServiceName);
+
+ // application.properties
+ Map applicationProperties = new HashMap<>();
+ applicationProperties.put("k1", "v1");
+ applicationProperties.put("k2", "v2");
+ applicationProperties.put("k3", "v3");
+ ConfigKVFile propertiesFile = new MockedConfigKVFile(applicationProperties);
+ when(configFileService.getConfigPropertiesFile(testNamespace, testServiceName, "application.properties"))
+ .thenReturn(propertiesFile);
+
+ // application-dev.properties
+ Map devProperties = new HashMap<>();
+ devProperties.put("k1", "v11");
+ ConfigKVFile devFile = new MockedConfigKVFile(devProperties);
+ when(configFileService.getConfigPropertiesFile(testNamespace, testServiceName, "application-dev.properties"))
+ .thenReturn(devFile);
+
+ Map emptyMap = new HashMap<>();
+ ConfigKVFile emptyConfigFile = new MockedConfigKVFile(emptyMap);
+ when(configFileService.getConfigYamlFile(testNamespace, testServiceName, "application.yml")).thenReturn(emptyConfigFile);
+ when(configFileService.getConfigYamlFile(testNamespace, testServiceName, "application-dev.yml")).thenReturn(emptyConfigFile);
+ when(configFileService.getConfigPropertiesFile(testNamespace, testServiceName, "bootstrap.properties")).thenReturn(emptyConfigFile);
+ when(configFileService.getConfigPropertiesFile(testNamespace, testServiceName, "bootstrap-dev.properties")).thenReturn(emptyConfigFile);
+ when(configFileService.getConfigYamlFile(testNamespace, testServiceName, "bootstrap.yml")).thenReturn(emptyConfigFile);
+ when(configFileService.getConfigYamlFile(testNamespace, testServiceName, "bootstrap-dev.yml")).thenReturn(emptyConfigFile);
+
+ when(polarisConfigProperties.getGroups()).thenReturn(null);
+ when(environment.getActiveProfiles()).thenReturn(new String[] {"dev"});
+
+ PropertySource> propertySource = locator.locate(environment);
+
+ Assert.assertEquals("v11", propertySource.getProperty("k1"));
+ Assert.assertEquals("v2", propertySource.getProperty("k2"));
+ Assert.assertEquals("v3", propertySource.getProperty("k3"));
+ }
+
+ @Test
+ public void testGetCustomFiles() {
+ PolarisConfigFileLocator locator = new PolarisConfigFileLocator(polarisConfigProperties, polarisContextProperties,
+ configFileService, polarisPropertySourceManager, environment);
+
+ when(polarisContextProperties.getNamespace()).thenReturn(testNamespace);
+ when(polarisContextProperties.getService()).thenReturn(testServiceName);
+
+ Map emptyMap = new HashMap<>();
+ ConfigKVFile emptyConfigFile = new MockedConfigKVFile(emptyMap);
+
+ when(configFileService.getConfigPropertiesFile(testNamespace, testServiceName, "application.properties")).thenReturn(emptyConfigFile);
+ when(configFileService.getConfigYamlFile(testNamespace, testServiceName, "application.yml")).thenReturn(emptyConfigFile);
+ when(configFileService.getConfigPropertiesFile(testNamespace, testServiceName, "bootstrap.properties")).thenReturn(emptyConfigFile);
+ when(configFileService.getConfigYamlFile(testNamespace, testServiceName, "bootstrap.yml")).thenReturn(emptyConfigFile);
+
+ List customFiles = new LinkedList<>();
+ ConfigFileGroup configFileGroup = new ConfigFileGroup();
+ String customGroup = "group1";
+ configFileGroup.setName(customGroup);
+ String customFile1 = "file1.properties";
+ String customFile2 = "file2.properties";
+ configFileGroup.setFiles(Lists.newArrayList(customFile1, customFile2));
+ customFiles.add(configFileGroup);
+
+ when(polarisConfigProperties.getGroups()).thenReturn(customFiles);
+ when(environment.getActiveProfiles()).thenReturn(new String[] {});
+
+ // file1.properties
+ Map file1Map = new HashMap<>();
+ file1Map.put("k1", "v1");
+ file1Map.put("k2", "v2");
+ ConfigKVFile file1 = new MockedConfigKVFile(file1Map);
+ when(configFileService.getConfigPropertiesFile(testNamespace, customGroup, customFile1)).thenReturn(file1);
+
+ // file2.properties
+ Map file2Map = new HashMap<>();
+ file2Map.put("k1", "v11");
+ file2Map.put("k3", "v3");
+ ConfigKVFile file2 = new MockedConfigKVFile(file2Map);
+ when(configFileService.getConfigPropertiesFile(testNamespace, customGroup, customFile2)).thenReturn(file2);
+
+ PropertySource> propertySource = locator.locate(environment);
+
+ Assert.assertEquals("v1", propertySource.getProperty("k1"));
+ Assert.assertEquals("v2", propertySource.getProperty("k2"));
+ Assert.assertEquals("v3", propertySource.getProperty("k3"));
+ }
+}
diff --git a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertiesSourceAutoRefresherTest.java b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertiesSourceAutoRefresherTest.java
new file mode 100644
index 000000000..648860f35
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertiesSourceAutoRefresherTest.java
@@ -0,0 +1,122 @@
+/*
+ * Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
+ *
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. 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.polaris.config.adapter;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.google.common.collect.Lists;
+import com.tencent.cloud.polaris.config.config.PolarisConfigProperties;
+import com.tencent.polaris.configuration.api.core.ChangeType;
+import com.tencent.polaris.configuration.api.core.ConfigKVFileChangeEvent;
+import com.tencent.polaris.configuration.api.core.ConfigPropertyChangeInfo;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import org.springframework.cloud.context.refresh.ContextRefresher;
+
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+/**
+ * test for {@link PolarisPropertySourceAutoRefresher}
+ *@author lepdou 2022-06-11
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class PolarisPropertiesSourceAutoRefresherTest {
+
+ @Mock
+ private PolarisConfigProperties polarisConfigProperties;
+ @Mock
+ private PolarisPropertySourceManager polarisPropertySourceManager;
+ @Mock
+ private ContextRefresher contextRefresher;
+
+ private final String testNamespace = "testNamespace";
+ private final String testServiceName = "testServiceName";
+ private final String testFileName = "application.properties";
+
+ @Test
+ public void testConfigFileChanged() {
+ PolarisPropertySourceAutoRefresher refresher = new PolarisPropertySourceAutoRefresher(polarisConfigProperties,
+ polarisPropertySourceManager, contextRefresher);
+
+ when(polarisConfigProperties.isAutoRefresh()).thenReturn(true);
+
+ Map content = new HashMap<>();
+ content.put("k1", "v1");
+ content.put("k2", "v2");
+ content.put("k3", "v3");
+ MockedConfigKVFile file = new MockedConfigKVFile(content);
+ PolarisPropertySource polarisPropertySource = new PolarisPropertySource(testNamespace, testServiceName, testFileName,
+ file, content);
+
+ when(polarisPropertySourceManager.getAllPropertySources()).thenReturn(Lists.newArrayList(polarisPropertySource));
+
+ ConfigPropertyChangeInfo changeInfo = new ConfigPropertyChangeInfo("k1", "v1", "v11", ChangeType.MODIFIED);
+ ConfigPropertyChangeInfo changeInfo2 = new ConfigPropertyChangeInfo("k4", null, "v4", ChangeType.ADDED);
+ ConfigPropertyChangeInfo changeInfo3 = new ConfigPropertyChangeInfo("k2", "v2", null, ChangeType.DELETED);
+ Map changeInfos = new HashMap<>();
+ changeInfos.put("k1", changeInfo);
+ changeInfos.put("k2", changeInfo3);
+ changeInfos.put("k4", changeInfo2);
+
+ ConfigKVFileChangeEvent event = new ConfigKVFileChangeEvent(changeInfos);
+ refresher.onApplicationEvent(null);
+
+ file.fireChangeListener(event);
+
+ Assert.assertEquals("v11", polarisPropertySource.getProperty("k1"));
+ Assert.assertEquals("v3", polarisPropertySource.getProperty("k3"));
+ Assert.assertNull(polarisPropertySource.getProperty("k2"));
+ Assert.assertEquals("v4", polarisPropertySource.getProperty("k4"));
+ verify(contextRefresher).refresh();
+ }
+
+ @Test
+ public void testNewConfigFile() {
+ PolarisPropertySourceAutoRefresher refresher = new PolarisPropertySourceAutoRefresher(polarisConfigProperties,
+ polarisPropertySourceManager, contextRefresher);
+
+ when(polarisConfigProperties.isAutoRefresh()).thenReturn(true);
+
+ Map emptyContent = new HashMap<>();
+ MockedConfigKVFile file = new MockedConfigKVFile(emptyContent);
+ PolarisPropertySource polarisPropertySource = new PolarisPropertySource(testNamespace, testServiceName, testFileName,
+ file, emptyContent);
+
+ when(polarisPropertySourceManager.getAllPropertySources()).thenReturn(Lists.newArrayList(polarisPropertySource));
+
+ ConfigPropertyChangeInfo changeInfo = new ConfigPropertyChangeInfo("k1", null, "v1", ChangeType.ADDED);
+ Map changeInfos = new HashMap<>();
+ changeInfos.put("k1", changeInfo);
+
+ ConfigKVFileChangeEvent event = new ConfigKVFileChangeEvent(changeInfos);
+ refresher.onApplicationEvent(null);
+
+ file.fireChangeListener(event);
+
+ Assert.assertEquals("v1", polarisPropertySource.getProperty("k1"));
+ verify(contextRefresher).refresh();
+ }
+
+}
diff --git a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/listener/ConfigChangeListenerTest.java b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/listener/ConfigChangeListenerTest.java
new file mode 100644
index 000000000..f3f70b4bc
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/listener/ConfigChangeListenerTest.java
@@ -0,0 +1,124 @@
+/*
+ * Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
+ *
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. 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.polaris.config.listener;
+
+import com.google.common.collect.Sets;
+import com.tencent.cloud.polaris.config.annotation.PolarisConfigKVFileChangeListener;
+import com.tencent.polaris.configuration.api.core.ConfigPropertyChangeInfo;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.cloud.context.environment.EnvironmentChangeEvent;
+import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.stereotype.Component;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.DEFINED_PORT;
+
+/**
+ * Integration testing for change listener.
+ *@author lepdou 2022-06-11
+ */
+@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment = DEFINED_PORT,
+ classes = ConfigChangeListenerTest.TestApplication.class,
+ properties = {"server.port=8081",
+ "spring.config.location = classpath:application-test.yml"})
+public class ConfigChangeListenerTest {
+
+ @Autowired
+ private ApplicationEventPublisher applicationEventPublisher;
+ @Autowired
+ private ConfigurableApplicationContext applicationContext;
+ @Autowired
+ private TestApplication.TestConfig testConfig;
+
+ @Test
+ public void test() throws InterruptedException {
+ //before change
+ Assert.assertEquals(1000, testConfig.getTimeout());
+
+ //submit change event
+ System.setProperty("timeout", "2000");
+ EnvironmentChangeEvent event = new EnvironmentChangeEvent(applicationContext,
+ Sets.newHashSet("timeout"));
+
+ applicationEventPublisher.publishEvent(event);
+
+ //after change
+ Assert.assertEquals(2, testConfig.getChangeCnt());
+ Assert.assertEquals(2000, testConfig.getTimeout());
+ }
+
+
+ @SpringBootApplication
+ protected static class TestApplication {
+
+ @Component
+ protected static class TestConfig {
+
+ @Value("${timeout:1000}")
+ private int timeout;
+
+ private int changeCnt;
+
+ public int getTimeout() {
+ return timeout;
+ }
+
+ public void setTimeout(int timeout) {
+ this.timeout = timeout;
+ }
+
+ public int getChangeCnt() {
+ return changeCnt;
+ }
+
+ @PolarisConfigKVFileChangeListener(interestedKeys = {"timeout"})
+ public void configChangedListener(ConfigChangeEvent event) {
+ ConfigPropertyChangeInfo changeInfo = event.getChange("timeout");
+ timeout = Integer.parseInt(changeInfo.getNewValue());
+ changeCnt++;
+ }
+
+ @PolarisConfigKVFileChangeListener(interestedKeyPrefixes = {"timeout"})
+ public void configChangedListener2(ConfigChangeEvent event) {
+ ConfigPropertyChangeInfo changeInfo = event.getChange("timeout");
+ timeout = Integer.parseInt(changeInfo.getNewValue());
+ changeCnt++;
+ }
+ }
+
+ @Component
+ protected static class EventPublisher implements ApplicationEventPublisher {
+
+ @Override
+ public void publishEvent(Object o) {
+
+ }
+ }
+ }
+
+}
diff --git a/spring-cloud-starter-tencent-polaris-config/src/test/resources/application-test.yml b/spring-cloud-starter-tencent-polaris-config/src/test/resources/application-test.yml
new file mode 100644
index 000000000..c90d1340b
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-config/src/test/resources/application-test.yml
@@ -0,0 +1,9 @@
+spring:
+ application:
+ name: test
+ cloud:
+ polaris:
+ address: grpc://127.0.0.1:8091
+ namespace: default
+ config:
+ connect-remote-server: false
diff --git a/spring-cloud-tencent-coverage/pom.xml b/spring-cloud-tencent-coverage/pom.xml
index 1c8ba0ed4..37903c143 100644
--- a/spring-cloud-tencent-coverage/pom.xml
+++ b/spring-cloud-tencent-coverage/pom.xml
@@ -24,6 +24,16 @@
spring-cloud-tencent-commons
+
+ com.tencent.cloud
+ spring-cloud-tencent-polaris-context
+
+
+
+ com.tencent.cloud
+ spring-cloud-tencent-polaris-loadbalancer
+
+
com.tencent.cloudspring-cloud-starter-tencent-polaris-discovery
@@ -49,10 +59,10 @@
spring-cloud-starter-tencent-polaris-router
-
- com.tencent.cloud
- spring-cloud-tencent-polaris-context
-
+
+ com.tencent.cloud
+ spring-cloud-starter-tencent-polaris-config
+
@@ -75,4 +85,4 @@
-
\ No newline at end of file
+
From 81e8ddd541bb95a7a89d93e94da020e0296f9051 Mon Sep 17 00:00:00 2001
From: SkyeBeFreeman <928016560@qq.com>
Date: Fri, 24 Jun 2022 17:20:56 +0800
Subject: [PATCH 4/6] Update GitHub Actions workflow
---
.github/workflows/junit_test.yml | 39 +++++++++++++++----
CHANGELOG.md | 1 +
pom.xml | 2 +-
.../listener/ConfigChangeListenerTest.java | 2 +-
.../cloud/common/util/ResourceFileUtils.java | 10 ++---
.../common/util/ResourceFileUtilsTest.java | 2 +-
.../src/test/resources/test.txt | 2 +-
7 files changed, 39 insertions(+), 19 deletions(-)
diff --git a/.github/workflows/junit_test.yml b/.github/workflows/junit_test.yml
index 35fed41eb..51e9cce15 100644
--- a/.github/workflows/junit_test.yml
+++ b/.github/workflows/junit_test.yml
@@ -5,24 +5,47 @@ name: Test with Junit
on:
push:
- branches: [ 2021.0 ]
+ branches:
+ - main
+ - 2021.0
+ - 2020.0
+ - greenwich
pull_request:
- branches: [ 2021.0 ]
+ branches:
+ - main
+ - 2021.0
+ - 2020.0
+ - greenwich
jobs:
build:
+ strategy:
+ matrix:
+ java: [ 8, 11, 17 ]
+ os: [ 'windows-latest', 'macos-latest', 'ubuntu-latest' ]
- runs-on: ubuntu-latest
+ runs-on: ${{ matrix.os }}
steps:
- name: Checkout codes
- uses: actions/checkout@v2
- - name: Set up JDK 8
- uses: actions/setup-java@v2
+ uses: actions/checkout@v3
+ - name: Set up JDK ${{ matrix.java }}
+ uses: actions/setup-java@v3
with:
- java-version: '8'
- distribution: 'adopt'
+ distribution: 'temurin'
+ java-version: ${{ matrix.java }}
+ - name: Cache local Maven repository
+ uses: actions/cache@v3
+ with:
+ path: ~/.m2/repository
+ key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+ restore-keys: |
+ ${{ runner.os }}-maven-
# - name: Build with Maven
# run: mvn -B package --file pom.xml
- name: Test with Maven
run: mvn -B test --file pom.xml
+ - name: Upload coverage to Codecov
+ uses: codecov/codecov-action@v3
+ with:
+ file: '**/target/site/jacoco/jacoco.xml'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4ca47946c..49aec3daa 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,3 +7,4 @@
- [fix:solve ratelimit-callee-service UnknownHostException.](https://github.com/Tencent/spring-cloud-tencent/pull/292)
- [Feature: Add config change listener feature support](https://github.com/Tencent/spring-cloud-tencent/pull/299)
- [Feature: Add config module unit test](https://github.com/Tencent/spring-cloud-tencent/pull/301)
+- [Update GitHub Actions workflow](https://github.com/Tencent/spring-cloud-tencent/pull/305)
diff --git a/pom.xml b/pom.xml
index 1721c6596..2561f4430 100644
--- a/pom.xml
+++ b/pom.xml
@@ -95,7 +95,7 @@
5.3.21
- 0.8.3
+ 0.8.83.2.01.2.73.0.1
diff --git a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/listener/ConfigChangeListenerTest.java b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/listener/ConfigChangeListenerTest.java
index f3f70b4bc..c408f4f54 100644
--- a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/listener/ConfigChangeListenerTest.java
+++ b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/listener/ConfigChangeListenerTest.java
@@ -66,7 +66,7 @@ public class ConfigChangeListenerTest {
Sets.newHashSet("timeout"));
applicationEventPublisher.publishEvent(event);
-
+ Thread.sleep(200);
//after change
Assert.assertEquals(2, testConfig.getChangeCnt());
Assert.assertEquals(2000, testConfig.getTimeout());
diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/ResourceFileUtils.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/ResourceFileUtils.java
index d79bfce8b..b5ea45d5d 100644
--- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/ResourceFileUtils.java
+++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/ResourceFileUtils.java
@@ -23,6 +23,7 @@ import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import org.springframework.core.io.ClassPathResource;
+import org.springframework.util.StreamUtils;
/**
* Read file content from classpath resource.
@@ -35,20 +36,15 @@ public final class ResourceFileUtils {
}
public static String readFile(String path) throws IOException {
- StringBuilder sb = new StringBuilder();
ClassPathResource classPathResource = new ClassPathResource(path);
if (classPathResource.exists() && classPathResource.isReadable()) {
try (InputStream inputStream = classPathResource.getInputStream()) {
- byte[] buffer = new byte[1024 * 10];
- int len;
- while ((len = inputStream.read(buffer)) != -1) {
- sb.append(new String(buffer, 0, len, StandardCharsets.UTF_8));
- }
+ return StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
}
}
- return sb.toString();
+ return "";
}
}
diff --git a/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/ResourceFileUtilsTest.java b/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/ResourceFileUtilsTest.java
index 334cd4e20..769d99ce7 100644
--- a/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/ResourceFileUtilsTest.java
+++ b/spring-cloud-tencent-commons/src/test/java/com/tencent/cloud/common/util/ResourceFileUtilsTest.java
@@ -35,7 +35,7 @@ public class ResourceFileUtilsTest {
@Test
public void testReadExistedFile() throws IOException {
String content = ResourceFileUtils.readFile("test.txt");
- Assert.assertEquals("just for test\n", content);
+ Assert.assertEquals("just for test", content);
}
@Test
diff --git a/spring-cloud-tencent-commons/src/test/resources/test.txt b/spring-cloud-tencent-commons/src/test/resources/test.txt
index 63d3c2d75..e18c37483 100644
--- a/spring-cloud-tencent-commons/src/test/resources/test.txt
+++ b/spring-cloud-tencent-commons/src/test/resources/test.txt
@@ -1 +1 @@
-just for test
+just for test
\ No newline at end of file
From cafe2daa635b40b9b83032fcc58184e117bfe323 Mon Sep 17 00:00:00 2001
From: weihubeats
Date: Fri, 24 Jun 2022 17:26:20 +0800
Subject: [PATCH 5/6] add restTemplate Report Polaris in2021.0 (#304)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* add restTemplate Report Polaris
* add listener
* add auto config
* add listener
* add java doc
* add java doc
* Add empty judgment
* add instanceof
* add test
* 删除多余空行
* format code
* format code
* format code
* remove redundant code
* rename class name
* add restTemplate Report Polaris
* update http code judge
* Support circuitbreaker in RestTemplate
---
CHANGELOG.md | 1 +
...sCircuitBreakerBootstrapConfiguration.java | 2 +-
.../PolarisFeignClientAutoConfiguration.java | 5 +-
.../PolarisRestTemplateAutoConfiguration.java | 56 +++++++++
.../PolarisResponseErrorHandler.java | 29 +++++
.../PolarisRestTemplateModifier.java | 65 ++++++++++
...larisRestTemplateResponseErrorHandler.java | 111 ++++++++++++++++++
.../main/resources/META-INF/spring.factories | 6 +-
...cuitBreakerBootstrapConfigurationTest.java | 1 +
...larisFeignClientAutoConfigurationTest.java | 1 +
...sRestTemplateResponseErrorHandlerTest.java | 70 +++++++++++
.../SimpleClientHttpResponseTest.java | 106 +++++++++++++++++
.../example/ServiceAController.java | 5 +
13 files changed, 452 insertions(+), 6 deletions(-)
rename spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/{ => config}/PolarisCircuitBreakerBootstrapConfiguration.java (97%)
rename spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/{ => config}/PolarisFeignClientAutoConfiguration.java (95%)
create mode 100644 spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisRestTemplateAutoConfiguration.java
create mode 100644 spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisResponseErrorHandler.java
create mode 100644 spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisRestTemplateModifier.java
create mode 100644 spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisRestTemplateResponseErrorHandler.java
create mode 100644 spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisRestTemplateResponseErrorHandlerTest.java
create mode 100644 spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/SimpleClientHttpResponseTest.java
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4ca47946c..f630f0ca3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,3 +7,4 @@
- [fix:solve ratelimit-callee-service UnknownHostException.](https://github.com/Tencent/spring-cloud-tencent/pull/292)
- [Feature: Add config change listener feature support](https://github.com/Tencent/spring-cloud-tencent/pull/299)
- [Feature: Add config module unit test](https://github.com/Tencent/spring-cloud-tencent/pull/301)
+- [Feature:add restTemplate Report Polaris](https://github.com/Tencent/spring-cloud-tencent/pull/304)
diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerBootstrapConfiguration.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerBootstrapConfiguration.java
similarity index 97%
rename from spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerBootstrapConfiguration.java
rename to spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerBootstrapConfiguration.java
index 121ffcf6d..064bb081e 100644
--- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerBootstrapConfiguration.java
+++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisCircuitBreakerBootstrapConfiguration.java
@@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License.
*/
-package com.tencent.cloud.polaris.circuitbreaker;
+package com.tencent.cloud.polaris.circuitbreaker.config;
import com.tencent.cloud.common.constant.ContextConstant;
import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled;
diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/PolarisFeignClientAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisFeignClientAutoConfiguration.java
similarity index 95%
rename from spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/PolarisFeignClientAutoConfiguration.java
rename to spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisFeignClientAutoConfiguration.java
index 5b98172bb..ae699dead 100644
--- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/PolarisFeignClientAutoConfiguration.java
+++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisFeignClientAutoConfiguration.java
@@ -15,7 +15,7 @@
* specific language governing permissions and limitations under the License.
*/
-package com.tencent.cloud.polaris.circuitbreaker;
+package com.tencent.cloud.polaris.circuitbreaker.config;
import com.tencent.cloud.polaris.circuitbreaker.feign.PolarisFeignBeanPostProcessor;
import com.tencent.cloud.polaris.context.PolarisContextAutoConfiguration;
@@ -40,8 +40,7 @@ import static org.springframework.core.Ordered.HIGHEST_PRECEDENCE;
*
* @author Haotian Zhang
*/
-@ConditionalOnProperty(value = "spring.cloud.polaris.circuitbreaker.enabled", havingValue = "true",
- matchIfMissing = true)
+@ConditionalOnProperty(value = "spring.cloud.polaris.circuitbreaker.enabled", havingValue = "true", matchIfMissing = true)
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(name = "org.springframework.cloud.openfeign.FeignAutoConfiguration")
@AutoConfigureAfter(PolarisContextAutoConfiguration.class)
diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisRestTemplateAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisRestTemplateAutoConfiguration.java
new file mode 100644
index 000000000..ea99fce36
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/config/PolarisRestTemplateAutoConfiguration.java
@@ -0,0 +1,56 @@
+/*
+ * Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
+ *
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. 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.polaris.circuitbreaker.config;
+
+import com.tencent.cloud.polaris.circuitbreaker.resttemplate.PolarisResponseErrorHandler;
+import com.tencent.cloud.polaris.circuitbreaker.resttemplate.PolarisRestTemplateModifier;
+import com.tencent.cloud.polaris.circuitbreaker.resttemplate.PolarisRestTemplateResponseErrorHandler;
+import com.tencent.cloud.polaris.context.PolarisContextAutoConfiguration;
+import com.tencent.polaris.api.core.ConsumerAPI;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.AutoConfigureAfter;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * @author : wh
+ * @date : 2022/6/21 21:34
+ * @description: Auto configuration PolarisRestTemplateAutoConfiguration
+ */
+@ConditionalOnProperty(value = "spring.cloud.polaris.circuitbreaker.enabled",
+ havingValue = "true", matchIfMissing = true)
+@Configuration(proxyBeanMethods = false)
+@AutoConfigureAfter(PolarisContextAutoConfiguration.class)
+public class PolarisRestTemplateAutoConfiguration {
+
+ @Bean
+ @ConditionalOnBean(RestTemplate.class)
+ public PolarisRestTemplateResponseErrorHandler polarisRestTemplateResponseErrorHandler(ConsumerAPI consumerAPI, @Autowired(required = false) PolarisResponseErrorHandler polarisResponseErrorHandler) {
+ return new PolarisRestTemplateResponseErrorHandler(consumerAPI, polarisResponseErrorHandler);
+ }
+
+ @Bean
+ @ConditionalOnBean(RestTemplate.class)
+ public PolarisRestTemplateModifier polarisRestTemplateBeanPostProcessor(PolarisRestTemplateResponseErrorHandler restTemplateResponseErrorHandler) {
+ return new PolarisRestTemplateModifier(restTemplateResponseErrorHandler);
+ }
+}
diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisResponseErrorHandler.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisResponseErrorHandler.java
new file mode 100644
index 000000000..5ddd1e6aa
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisResponseErrorHandler.java
@@ -0,0 +1,29 @@
+/*
+ * Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
+ *
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. 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.polaris.circuitbreaker.resttemplate;
+
+import org.springframework.web.client.ResponseErrorHandler;
+
+/**
+ * @author : wh
+ * @date : 2022/6/21 19:12
+ * @description: errorHandler {@link ResponseErrorHandler}
+ */
+public interface PolarisResponseErrorHandler extends ResponseErrorHandler {
+
+}
diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisRestTemplateModifier.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisRestTemplateModifier.java
new file mode 100644
index 000000000..bd43913f4
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisRestTemplateModifier.java
@@ -0,0 +1,65 @@
+/*
+ * Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
+ *
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. 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.polaris.circuitbreaker.resttemplate;
+
+import java.util.Map;
+
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.SmartInitializingSingleton;
+import org.springframework.cloud.client.loadbalancer.LoadBalanced;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.util.ObjectUtils;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * @author : wh
+ * @date : 2022/6/21 21:20
+ * @description: auto configuration RestTemplate Find the RestTemplate bean annotated with {@link LoadBalanced} and replace {@link org.springframework.web.client.ResponseErrorHandler}
+ * with {@link PolarisRestTemplateResponseErrorHandler}
+ */
+public class PolarisRestTemplateModifier implements ApplicationContextAware, SmartInitializingSingleton {
+
+ private ApplicationContext applicationContext;
+
+ private final PolarisRestTemplateResponseErrorHandler polarisRestTemplateResponseErrorHandler;
+
+ public PolarisRestTemplateModifier(PolarisRestTemplateResponseErrorHandler polarisRestTemplateResponseErrorHandler) {
+ this.polarisRestTemplateResponseErrorHandler = polarisRestTemplateResponseErrorHandler;
+ }
+
+ @Override
+ public void afterSingletonsInstantiated() {
+ Map beans = this.applicationContext.getBeansWithAnnotation(LoadBalanced.class);
+ if (!ObjectUtils.isEmpty(beans)) {
+ beans.forEach(this::initRestTemplate);
+ }
+ }
+
+ private void initRestTemplate(String beanName, Object bean) {
+ if (bean instanceof RestTemplate) {
+ RestTemplate restTemplate = (RestTemplate) bean;
+ restTemplate.setErrorHandler(polarisRestTemplateResponseErrorHandler);
+ }
+ }
+
+ @Override
+ public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+ this.applicationContext = applicationContext;
+ }
+}
diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisRestTemplateResponseErrorHandler.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisRestTemplateResponseErrorHandler.java
new file mode 100644
index 000000000..e6e003d90
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/java/com/tencent/cloud/polaris/circuitbreaker/resttemplate/PolarisRestTemplateResponseErrorHandler.java
@@ -0,0 +1,111 @@
+/*
+ * Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
+ *
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. 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.polaris.circuitbreaker.resttemplate;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.URI;
+import java.net.URL;
+import java.util.Objects;
+
+import com.tencent.cloud.common.metadata.MetadataContext;
+import com.tencent.cloud.common.util.ReflectionUtils;
+import com.tencent.polaris.api.core.ConsumerAPI;
+import com.tencent.polaris.api.pojo.RetStatus;
+import com.tencent.polaris.api.pojo.ServiceKey;
+import com.tencent.polaris.api.rpc.ServiceCallResult;
+import com.tencent.polaris.api.utils.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.springframework.http.HttpMethod;
+import org.springframework.http.client.ClientHttpResponse;
+import org.springframework.web.client.ResponseErrorHandler;
+
+/**
+ * @author : wh
+ * @date : 2022/6/21 17:25
+ * @description: Extend ResponseErrorHandler to get request information
+ */
+public class PolarisRestTemplateResponseErrorHandler implements ResponseErrorHandler {
+
+ private static final Logger LOG = LoggerFactory.getLogger(PolarisRestTemplateResponseErrorHandler.class);
+
+ private static final String FileName = "connection";
+
+ private final ConsumerAPI consumerAPI;
+
+ private final PolarisResponseErrorHandler polarisResponseErrorHandler;
+
+
+ public PolarisRestTemplateResponseErrorHandler(ConsumerAPI consumerAPI, PolarisResponseErrorHandler polarisResponseErrorHandler) {
+ this.consumerAPI = consumerAPI;
+ this.polarisResponseErrorHandler = polarisResponseErrorHandler;
+ }
+
+ @Override
+ public boolean hasError(ClientHttpResponse response) {
+ return true;
+ }
+
+ @Override
+ public void handleError(ClientHttpResponse response) throws IOException {
+ if (Objects.nonNull(polarisResponseErrorHandler)) {
+ if (polarisResponseErrorHandler.hasError(response)) {
+ polarisResponseErrorHandler.handleError(response);
+ }
+ }
+ }
+
+ public void handleError(URI url, HttpMethod method, ClientHttpResponse response) throws IOException {
+ ServiceCallResult resultRequest = null;
+ try {
+ resultRequest = builderServiceCallResult(url, response);
+ }
+ catch (IOException e) {
+ LOG.error("Will report response of {} url {}", response, url, e);
+ throw e;
+ }
+ finally {
+ consumerAPI.updateServiceCallResult(resultRequest);
+ }
+ }
+
+ private ServiceCallResult builderServiceCallResult(URI uri, ClientHttpResponse response) throws IOException {
+ ServiceCallResult resultRequest = new ServiceCallResult();
+ String serviceName = uri.getHost();
+ resultRequest.setService(serviceName);
+ resultRequest.setNamespace(MetadataContext.LOCAL_NAMESPACE);
+ resultRequest.setMethod(uri.getPath());
+ resultRequest.setRetStatus(RetStatus.RetSuccess);
+ String sourceNamespace = MetadataContext.LOCAL_NAMESPACE;
+ String sourceService = MetadataContext.LOCAL_SERVICE;
+ if (StringUtils.isNotBlank(sourceNamespace) && StringUtils.isNotBlank(sourceService)) {
+ resultRequest.setCallerService(new ServiceKey(sourceNamespace, sourceService));
+ }
+ HttpURLConnection connection = (HttpURLConnection) ReflectionUtils.getFieldValue(response, FileName);
+ URL url = connection.getURL();
+ resultRequest.setHost(url.getHost());
+ resultRequest.setPort(url.getPort());
+ if (response.getStatusCode().value() > 500) {
+ resultRequest.setRetStatus(RetStatus.RetFail);
+ }
+ return resultRequest;
+ }
+
+}
diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/resources/META-INF/spring.factories b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/resources/META-INF/spring.factories
index 04fa47a13..229cc2af0 100644
--- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/resources/META-INF/spring.factories
+++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/main/resources/META-INF/spring.factories
@@ -1,4 +1,6 @@
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
- com.tencent.cloud.polaris.circuitbreaker.PolarisCircuitBreakerBootstrapConfiguration
+ com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerBootstrapConfiguration
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
- com.tencent.cloud.polaris.circuitbreaker.PolarisFeignClientAutoConfiguration
+ com.tencent.cloud.polaris.circuitbreaker.config.PolarisFeignClientAutoConfiguration,\
+ com.tencent.cloud.polaris.circuitbreaker.config.PolarisRestTemplateAutoConfiguration
+
diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerBootstrapConfigurationTest.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerBootstrapConfigurationTest.java
index 42777a3b6..a5bd4f2e6 100644
--- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerBootstrapConfigurationTest.java
+++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisCircuitBreakerBootstrapConfigurationTest.java
@@ -17,6 +17,7 @@
package com.tencent.cloud.polaris.circuitbreaker;
+import com.tencent.cloud.polaris.circuitbreaker.config.PolarisCircuitBreakerBootstrapConfiguration;
import org.junit.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisFeignClientAutoConfigurationTest.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisFeignClientAutoConfigurationTest.java
index c83608478..2443949c9 100644
--- a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisFeignClientAutoConfigurationTest.java
+++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisFeignClientAutoConfigurationTest.java
@@ -17,6 +17,7 @@
package com.tencent.cloud.polaris.circuitbreaker;
+import com.tencent.cloud.polaris.circuitbreaker.config.PolarisFeignClientAutoConfiguration;
import com.tencent.cloud.polaris.circuitbreaker.feign.PolarisFeignBeanPostProcessor;
import com.tencent.cloud.polaris.context.PolarisContextAutoConfiguration;
import com.tencent.polaris.api.core.ConsumerAPI;
diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisRestTemplateResponseErrorHandlerTest.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisRestTemplateResponseErrorHandlerTest.java
new file mode 100644
index 000000000..5daf30bc6
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/PolarisRestTemplateResponseErrorHandlerTest.java
@@ -0,0 +1,70 @@
+/*
+ * Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
+ *
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. 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.polaris.circuitbreaker;
+
+
+import java.net.HttpURLConnection;
+import java.net.URI;
+import java.net.URL;
+
+import com.tencent.cloud.polaris.circuitbreaker.resttemplate.PolarisRestTemplateResponseErrorHandler;
+import com.tencent.polaris.api.core.ConsumerAPI;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.http.HttpMethod;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * @author : wh
+ * @date : 2022/6/22 09:00
+ * @description: Test for {@link PolarisRestTemplateResponseErrorHandler}.
+ */
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = PolarisRestTemplateResponseErrorHandlerTest.TestApplication.class,
+ properties = {"spring.cloud.polaris.namespace=Test", "spring.cloud.polaris.service=TestApp"})
+public class PolarisRestTemplateResponseErrorHandlerTest {
+
+ @Test
+ public void handleError() throws Exception {
+ ConsumerAPI consumerAPI = mock(ConsumerAPI.class);
+ PolarisRestTemplateResponseErrorHandler polarisRestTemplateResponseErrorHandler = new PolarisRestTemplateResponseErrorHandler(consumerAPI, null);
+ URI uri = mock(URI.class);
+ when(uri.getPath()).thenReturn("/test");
+ when(uri.getHost()).thenReturn("host");
+ HttpURLConnection httpURLConnection = mock(HttpURLConnection.class);
+ URL url = mock(URL.class);
+ when(httpURLConnection.getURL()).thenReturn(url);
+ when(url.getHost()).thenReturn("127.0.0.1");
+ when(url.getPort()).thenReturn(8080);
+ when(httpURLConnection.getResponseCode()).thenReturn(200);
+ SimpleClientHttpResponseTest clientHttpResponse = new SimpleClientHttpResponseTest(httpURLConnection);
+ polarisRestTemplateResponseErrorHandler.handleError(uri, HttpMethod.GET, clientHttpResponse);
+ when(consumerAPI.unWatchService(null)).thenReturn(true);
+ }
+
+ @SpringBootApplication
+ protected static class TestApplication {
+
+ }
+}
diff --git a/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/SimpleClientHttpResponseTest.java b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/SimpleClientHttpResponseTest.java
new file mode 100644
index 000000000..ed76da17b
--- /dev/null
+++ b/spring-cloud-starter-tencent-polaris-circuitbreaker/src/test/java/com/tencent/cloud/polaris/circuitbreaker/SimpleClientHttpResponseTest.java
@@ -0,0 +1,106 @@
+/*
+ * Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
+ *
+ * Copyright (C) 2019 THL A29 Limited, a Tencent company. 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.polaris.circuitbreaker;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.client.AbstractClientHttpResponse;
+import org.springframework.lang.Nullable;
+import org.springframework.util.StreamUtils;
+import org.springframework.util.StringUtils;
+
+
+/**
+ * @author : wh
+ * @date : 2022/6/22 09:00
+ * @description: mock {@link org.springframework.http.client.SimpleClientHttpResponse}
+ */
+public class SimpleClientHttpResponseTest extends AbstractClientHttpResponse {
+
+ private final HttpURLConnection connection;
+
+ @Nullable
+ private HttpHeaders headers;
+
+ @Nullable
+ private InputStream responseStream;
+
+
+ SimpleClientHttpResponseTest(HttpURLConnection connection) {
+ this.connection = connection;
+ }
+
+
+ @Override
+ public int getRawStatusCode() throws IOException {
+ return this.connection.getResponseCode();
+ }
+
+ @Override
+ public String getStatusText() throws IOException {
+ String result = this.connection.getResponseMessage();
+ return (result != null) ? result : "";
+ }
+
+ @Override
+ public HttpHeaders getHeaders() {
+ if (this.headers == null) {
+ this.headers = new HttpHeaders();
+ // Header field 0 is the status line for most HttpURLConnections, but not on GAE
+ String name = this.connection.getHeaderFieldKey(0);
+ if (StringUtils.hasLength(name)) {
+ this.headers.add(name, this.connection.getHeaderField(0));
+ }
+ int i = 1;
+ while (true) {
+ name = this.connection.getHeaderFieldKey(i);
+ if (!StringUtils.hasLength(name)) {
+ break;
+ }
+ this.headers.add(name, this.connection.getHeaderField(i));
+ i++;
+ }
+ }
+ return this.headers;
+ }
+
+ @Override
+ public InputStream getBody() throws IOException {
+ InputStream errorStream = this.connection.getErrorStream();
+ this.responseStream = (errorStream != null ? errorStream : this.connection.getInputStream());
+ return this.responseStream;
+ }
+
+ @Override
+ public void close() {
+ try {
+ if (this.responseStream == null) {
+ getBody();
+ }
+ StreamUtils.drain(this.responseStream);
+ this.responseStream.close();
+ }
+ catch (Exception ex) {
+ // ignore
+ }
+ }
+
+}
diff --git a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-a/src/main/java/com/tencent/cloud/polaris/circuitbreaker/example/ServiceAController.java b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-a/src/main/java/com/tencent/cloud/polaris/circuitbreaker/example/ServiceAController.java
index ebfea6716..3ba9901a6 100644
--- a/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-a/src/main/java/com/tencent/cloud/polaris/circuitbreaker/example/ServiceAController.java
+++ b/spring-cloud-tencent-examples/polaris-circuitbreaker-example/polaris-circuitbreaker-example-a/src/main/java/com/tencent/cloud/polaris/circuitbreaker/example/ServiceAController.java
@@ -48,6 +48,11 @@ public class ServiceAController {
return polarisServiceB.info();
}
+ @GetMapping("/getBServiceInfoByRestTemplate")
+ public String getBServiceInfoByRestTemplate() {
+ return restTemplate.getForObject("http://polaris-circuitbreaker-example-b/example/service/b/info", String.class);
+ }
+
/**
* Get info of Service B by RestTemplate.
* @return info of Service B
From 733850d4a96ac7837a756f71821305e8990db399 Mon Sep 17 00:00:00 2001
From: kaiybaby <45356448+kaiybaby@users.noreply.github.com>
Date: Sat, 25 Jun 2022 19:32:15 +0800
Subject: [PATCH 6/6] fix the current limiting effect is that other requests
cannot be processed when queuing at a constant speed (#309)
---
CHANGELOG.md | 1 +
.../ratelimit/filter/QuotaCheckReactiveFilter.java | 5 +++--
.../filter/QuotaCheckReactiveFilterTest.java | 12 ++++++++++--
3 files changed, 14 insertions(+), 4 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b70c2be3e..40dbcc025 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,3 +9,4 @@
- [Feature: Add config module unit test](https://github.com/Tencent/spring-cloud-tencent/pull/301)
- [Feature:add restTemplate Report Polaris](https://github.com/Tencent/spring-cloud-tencent/pull/304)
- [Update GitHub Actions workflow](https://github.com/Tencent/spring-cloud-tencent/pull/305)
+- [fix: 将blocking call改为non-blocking call](https://github.com/Tencent/spring-cloud-tencent/pull/309)
\ No newline at end of file
diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckReactiveFilter.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckReactiveFilter.java
index 7340c73de..67e9f1842 100644
--- a/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckReactiveFilter.java
+++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/main/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckReactiveFilter.java
@@ -19,6 +19,7 @@
package com.tencent.cloud.polaris.ratelimit.filter;
import java.nio.charset.StandardCharsets;
+import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
@@ -55,7 +56,7 @@ import static com.tencent.cloud.polaris.ratelimit.constant.RateLimitConstant.LAB
/**
* Reactive filter to check quota.
*
- * @author Haotian Zhang, lepdou
+ * @author Haotian Zhang, lepdou, kaiy
*/
public class QuotaCheckReactiveFilter implements WebFilter, Ordered {
@@ -113,7 +114,7 @@ public class QuotaCheckReactiveFilter implements WebFilter, Ordered {
}
// Unirate
if (quotaResponse.getCode() == QuotaResultCode.QuotaResultOk && quotaResponse.getWaitMs() > 0) {
- Thread.sleep(quotaResponse.getWaitMs());
+ return Mono.delay(Duration.ofMillis(quotaResponse.getWaitMs())).flatMap(e -> chain.filter(exchange));
}
}
catch (Throwable t) {
diff --git a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckReactiveFilterTest.java b/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckReactiveFilterTest.java
index 3bae2e3bd..d76670ea7 100644
--- a/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckReactiveFilterTest.java
+++ b/spring-cloud-starter-tencent-polaris-ratelimit/src/test/java/com/tencent/cloud/polaris/ratelimit/filter/QuotaCheckReactiveFilterTest.java
@@ -22,6 +22,7 @@ import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Map;
+import java.util.concurrent.CountDownLatch;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.util.ApplicationContextAwareUtils;
@@ -65,7 +66,7 @@ import static org.mockito.Mockito.when;
/**
* Test for {@link QuotaCheckReactiveFilter}.
*
- * @author Haotian Zhang
+ * @author Haotian Zhang, kaiy
*/
@RunWith(MockitoJUnitRunner.class)
@SpringBootTest(classes = QuotaCheckReactiveFilterTest.TestApplication.class, properties = {
@@ -201,7 +202,14 @@ public class QuotaCheckReactiveFilterTest {
// Unirate waiting 1000ms
MetadataContext.LOCAL_SERVICE = "TestApp2";
long startTimestamp = System.currentTimeMillis();
- quotaCheckReactiveFilter.filter(exchange, webFilterChain);
+ CountDownLatch countDownLatch = new CountDownLatch(1);
+ quotaCheckReactiveFilter.filter(exchange, webFilterChain).subscribe(e -> { }, t -> { }, countDownLatch::countDown);
+ try {
+ countDownLatch.await();
+ }
+ catch (InterruptedException e) {
+ fail("Exception encountered.", e);
+ }
assertThat(System.currentTimeMillis() - startTimestamp).isGreaterThanOrEqualTo(1000L);
// Rate limited