From cafe2daa635b40b9b83032fcc58184e117bfe323 Mon Sep 17 00:00:00 2001 From: weihubeats Date: Fri, 24 Jun 2022 17:26:20 +0800 Subject: [PATCH] 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 4ca47946..f630f0ca 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 121ffcf6..064bb081 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 5b98172b..ae699dea 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 00000000..ea99fce3 --- /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 00000000..5ddd1e6a --- /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 00000000..bd43913f --- /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 00000000..e6e003d9 --- /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 04fa47a1..229cc2af 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 42777a3b..a5bd4f2e 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 c8360847..2443949c 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 00000000..5daf30bc --- /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 00000000..ed76da17 --- /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 ebfea671..3ba9901a 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