feat:add spring cloud 2020.0.x support

pull/78/head
skyehtzhang 3 years ago
parent 9f5bc3b0b7
commit 2781270c16

@ -5,9 +5,9 @@ name: Test with Junit
on: on:
push: push:
branches: [ main ] branches: [ 2020.0 ]
pull_request: pull_request:
branches: [ main ] branches: [ 2020.0 ]
jobs: jobs:
build: build:

@ -1,43 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent> <parent>
<groupId>org.springframework.cloud</groupId> <groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-build</artifactId> <artifactId>spring-cloud-build</artifactId>
<version>2.3.4.RELEASE</version> <version>3.0.4</version>
<relativePath/> <relativePath/>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>com.tencent.cloud</groupId> <groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-tencent</artifactId> <artifactId>spring-cloud-tencent</artifactId>
<packaging>pom</packaging> <packaging>pom</packaging>
<version>${revision}</version> <version>${revision}</version>
<name>Spring Cloud Tencent</name> <name>Spring Cloud Tencent</name>
<description>Spring Cloud Tencent</description> <description>Spring Cloud Tencent</description>
<url>https://github.com/Tencent/spring-cloud-tencent/tree/main</url> <url>https://github.com/Tencent/spring-cloud-tencent/tree/main</url>
<organization> <organization>
<name>Tencent</name> <name>Tencent</name>
<url>https://opensource.tencent.com/</url> <url>https://opensource.tencent.com/</url>
</organization> </organization>
<licenses> <licenses>
<license> <license>
<name>The BSD 3-Clause License (BSD3)</name> <name>The BSD 3-Clause License (BSD3)</name>
<url>https://raw.githubusercontent.com/Tencent/spring-cloud-tencent/main/LICENSE</url> <url>https://raw.githubusercontent.com/Tencent/spring-cloud-tencent/main/LICENSE</url>
<distribution>repo</distribution> <distribution>repo</distribution>
</license> </license>
</licenses> </licenses>
<scm> <scm>
<url>https://github.com/Tencent/spring-cloud-tencent</url> <url>https://github.com/Tencent/spring-cloud-tencent</url>
<connection>scm:git:git@github.com:Tencent/spring-cloud-tencent.git</connection> <connection>scm:git:git@github.com:Tencent/spring-cloud-tencent.git</connection>
<developerConnection>scm:git:git@github.com:Tencent/spring-cloud-tencent.git</developerConnection> <developerConnection>scm:git:git@github.com:Tencent/spring-cloud-tencent.git</developerConnection>
</scm> </scm>
<modules> <modules>
<module>spring-cloud-tencent-polaris-context</module> <module>spring-cloud-tencent-polaris-context</module>
<module>spring-cloud-tencent-commons</module> <module>spring-cloud-tencent-commons</module>
<module>spring-cloud-starter-tencent-metadata-transfer</module> <module>spring-cloud-starter-tencent-metadata-transfer</module>
@ -48,7 +48,7 @@
<module>spring-cloud-tencent-dependencies</module> <module>spring-cloud-tencent-dependencies</module>
<module>spring-cloud-tencent-examples</module> <module>spring-cloud-tencent-examples</module>
<module>spring-cloud-tencent-coverage</module> <module>spring-cloud-tencent-coverage</module>
<module>spring-cloud-starter-tencent-polaris-config</module> <module>spring-cloud-starter-tencent-polaris-config</module>
</modules> </modules>
<developers> <developers>
@ -77,10 +77,10 @@
<properties> <properties>
<!-- Project revision --> <!-- Project revision -->
<revision>1.2.0-Hoxton.SR9-SNAPSHOT</revision> <revision>1.2.0-2020.0.5-SNAPSHOT</revision>
<!-- Spring Cloud --> <!-- Spring Cloud -->
<spring.cloud.version>Hoxton.SR9</spring.cloud.version> <spring.cloud.version>2020.0.5</spring.cloud.version>
<!-- Dependencies --> <!-- Dependencies -->
<logback.version>1.2.7</logback.version> <logback.version>1.2.7</logback.version>
@ -266,31 +266,31 @@
</executions> </executions>
</plugin> </plugin>
</plugins> </plugins>
</build> </build>
<distributionManagement> <distributionManagement>
<snapshotRepository> <snapshotRepository>
<id>nexus-snapshots</id> <id>nexus-snapshots</id>
<url>https://oss.sonatype.org/content/repositories/snapshots/</url> <url>https://oss.sonatype.org/content/repositories/snapshots/</url>
</snapshotRepository> </snapshotRepository>
<repository> <repository>
<id>nexus-releases</id> <id>nexus-releases</id>
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url> <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
</repository> </repository>
</distributionManagement> </distributionManagement>
</profile> </profile>
</profiles> </profiles>
<repositories> <repositories>
<repository> <repository>
<id>nexus-snapshots</id> <id>nexus-snapshots</id>
<url>https://oss.sonatype.org/content/repositories/snapshots/</url> <url>https://oss.sonatype.org/content/repositories/snapshots/</url>
<releases> <releases>
<enabled>false</enabled> <enabled>false</enabled>
</releases> </releases>
<snapshots> <snapshots>
<enabled>true</enabled> <enabled>true</enabled>
</snapshots> </snapshots>
</repository> </repository>
</repositories> </repositories>
</project> </project>

@ -21,12 +21,6 @@
</dependency> </dependency>
<!-- Spring Cloud Tencent dependencies end --> <!-- Spring Cloud Tencent dependencies end -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
<optional>true</optional>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.cloud</groupId> <groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId> <artifactId>spring-cloud-starter-gateway</artifactId>
@ -47,7 +41,7 @@
<dependency> <dependency>
<groupId>org.springframework.cloud</groupId> <groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId> <artifactId>spring-cloud-starter-loadbalancer</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>

@ -20,9 +20,7 @@ package com.tencent.cloud.metadata.config;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import com.netflix.zuul.ZuulFilter;
import com.tencent.cloud.metadata.core.filter.gateway.Metadata2HeaderScgFilter; import com.tencent.cloud.metadata.core.filter.gateway.Metadata2HeaderScgFilter;
import com.tencent.cloud.metadata.core.filter.gateway.Metadata2HeaderZuulFilter;
import com.tencent.cloud.metadata.core.interceptor.Metadata2HeaderFeignInterceptor; import com.tencent.cloud.metadata.core.interceptor.Metadata2HeaderFeignInterceptor;
import com.tencent.cloud.metadata.core.interceptor.Metadata2HeaderRestTemplateInterceptor; import com.tencent.cloud.metadata.core.interceptor.Metadata2HeaderRestTemplateInterceptor;
@ -46,20 +44,6 @@ import org.springframework.web.client.RestTemplate;
@Configuration @Configuration
public class MetadataTransferAutoConfiguration { public class MetadataTransferAutoConfiguration {
/**
* Create when gateway application is Zuul.
*/
@Configuration
@ConditionalOnClass(name = "com.netflix.zuul.http.ZuulServlet")
static class MetadataTransferZuulFilterConfig {
@Bean
public ZuulFilter metadata2HeaderZuulFilter() {
return new Metadata2HeaderZuulFilter();
}
}
/** /**
* Create when gateway application is SCG. * Create when gateway application is SCG.
*/ */
@ -106,35 +90,29 @@ public class MetadataTransferAutoConfiguration {
BeanPostProcessor metadata2HeaderRestTemplatePostProcessor( BeanPostProcessor metadata2HeaderRestTemplatePostProcessor(
Metadata2HeaderRestTemplateInterceptor metadata2HeaderRestTemplateInterceptor) { Metadata2HeaderRestTemplateInterceptor metadata2HeaderRestTemplateInterceptor) {
// Coping with multiple bean injection scenarios // Coping with multiple bean injection scenarios
Map<String, RestTemplate> beans = this.context Map<String, RestTemplate> beans = this.context.getBeansOfType(RestTemplate.class);
.getBeansOfType(RestTemplate.class);
// If the restTemplate has been created when the // If the restTemplate has been created when the
// MetadataRestTemplatePostProcessor Bean // MetadataRestTemplatePostProcessor Bean
// is initialized, then manually set the interceptor. // is initialized, then manually set the interceptor.
if (!CollectionUtils.isEmpty(beans)) { if (!CollectionUtils.isEmpty(beans)) {
for (RestTemplate restTemplate : beans.values()) { for (RestTemplate restTemplate : beans.values()) {
List<ClientHttpRequestInterceptor> interceptors = restTemplate List<ClientHttpRequestInterceptor> interceptors = restTemplate.getInterceptors();
.getInterceptors();
// Avoid setting interceptor repeatedly. // Avoid setting interceptor repeatedly.
if (null != interceptors && !interceptors if (null != interceptors && !interceptors.contains(metadata2HeaderRestTemplateInterceptor)) {
.contains(metadata2HeaderRestTemplateInterceptor)) {
interceptors.add(metadata2HeaderRestTemplateInterceptor); interceptors.add(metadata2HeaderRestTemplateInterceptor);
restTemplate.setInterceptors(interceptors); restTemplate.setInterceptors(interceptors);
} }
} }
} }
return new Metadata2HeaderRestTemplatePostProcessor( return new Metadata2HeaderRestTemplatePostProcessor(metadata2HeaderRestTemplateInterceptor);
metadata2HeaderRestTemplateInterceptor);
} }
@Override @Override
public void setApplicationContext(ApplicationContext applicationContext) public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
throws BeansException {
this.context = applicationContext; this.context = applicationContext;
} }
public static class Metadata2HeaderRestTemplatePostProcessor public static class Metadata2HeaderRestTemplatePostProcessor implements BeanPostProcessor {
implements BeanPostProcessor {
private Metadata2HeaderRestTemplateInterceptor metadata2HeaderRestTemplateInterceptor; private Metadata2HeaderRestTemplateInterceptor metadata2HeaderRestTemplateInterceptor;
@ -152,11 +130,9 @@ public class MetadataTransferAutoConfiguration {
public Object postProcessAfterInitialization(Object bean, String beanName) { public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean instanceof RestTemplate) { if (bean instanceof RestTemplate) {
RestTemplate restTemplate = (RestTemplate) bean; RestTemplate restTemplate = (RestTemplate) bean;
List<ClientHttpRequestInterceptor> interceptors = restTemplate List<ClientHttpRequestInterceptor> interceptors = restTemplate.getInterceptors();
.getInterceptors();
// Avoid setting interceptor repeatedly. // Avoid setting interceptor repeatedly.
if (null != interceptors && !interceptors if (null != interceptors && !interceptors.contains(metadata2HeaderRestTemplateInterceptor)) {
.contains(metadata2HeaderRestTemplateInterceptor)) {
interceptors.add(this.metadata2HeaderRestTemplateInterceptor); interceptors.add(this.metadata2HeaderRestTemplateInterceptor);
restTemplate.setInterceptors(interceptors); restTemplate.setInterceptors(interceptors);
} }

@ -34,7 +34,7 @@ import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.ServerWebExchange;
import static org.springframework.cloud.gateway.filter.LoadBalancerClientFilter.LOAD_BALANCER_CLIENT_FILTER_ORDER; import static org.springframework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter.LOAD_BALANCER_CLIENT_FILTER_ORDER;
/** /**
* Scg filter used for writing metadata in HTTP request header. * Scg filter used for writing metadata in HTTP request header.
@ -43,8 +43,7 @@ import static org.springframework.cloud.gateway.filter.LoadBalancerClientFilter.
*/ */
public class Metadata2HeaderScgFilter implements GlobalFilter, Ordered { public class Metadata2HeaderScgFilter implements GlobalFilter, Ordered {
private static final int METADATA_SCG_FILTER_ORDER = LOAD_BALANCER_CLIENT_FILTER_ORDER private static final int METADATA_SCG_FILTER_ORDER = LOAD_BALANCER_CLIENT_FILTER_ORDER + 1;
+ 1;
@Override @Override
public int getOrder() { public int getOrder() {
@ -57,20 +56,17 @@ public class Metadata2HeaderScgFilter implements GlobalFilter, Ordered {
ServerHttpRequest.Builder builder = exchange.getRequest().mutate(); ServerHttpRequest.Builder builder = exchange.getRequest().mutate();
// get metadata of current thread // get metadata of current thread
MetadataContext metadataContext = exchange MetadataContext metadataContext = exchange.getAttribute(MetadataConstant.HeaderName.METADATA_CONTEXT);
.getAttribute(MetadataConstant.HeaderName.METADATA_CONTEXT);
// add new metadata and cover old // add new metadata and cover old
if (metadataContext == null) { if (metadataContext == null) {
metadataContext = MetadataContextHolder.get(); metadataContext = MetadataContextHolder.get();
} }
Map<String, String> customMetadata = metadataContext Map<String, String> customMetadata = metadataContext.getAllTransitiveCustomMetadata();
.getAllTransitiveCustomMetadata();
if (!CollectionUtils.isEmpty(customMetadata)) { if (!CollectionUtils.isEmpty(customMetadata)) {
String metadataStr = JacksonUtils.serialize2Json(customMetadata); String metadataStr = JacksonUtils.serialize2Json(customMetadata);
try { try {
builder.header(MetadataConstant.HeaderName.CUSTOM_METADATA, builder.header(MetadataConstant.HeaderName.CUSTOM_METADATA, URLEncoder.encode(metadataStr, "UTF-8"));
URLEncoder.encode(metadataStr, "UTF-8"));
} }
catch (UnsupportedEncodingException e) { catch (UnsupportedEncodingException e) {
builder.header(MetadataConstant.HeaderName.CUSTOM_METADATA, metadataStr); builder.header(MetadataConstant.HeaderName.CUSTOM_METADATA, metadataStr);

@ -1,84 +0,0 @@
/*
* 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.metadata.core.filter.gateway;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Map;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.tencent.cloud.common.constant.MetadataConstant;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.common.util.JacksonUtils;
import org.springframework.util.CollectionUtils;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.RIBBON_ROUTING_FILTER_ORDER;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.ROUTE_TYPE;
/**
* Zuul filter used for writing metadata in HTTP request header.
*
* @author Haotian Zhang
*/
public class Metadata2HeaderZuulFilter extends ZuulFilter {
@Override
public String filterType() {
return ROUTE_TYPE;
}
@Override
public int filterOrder() {
return RIBBON_ROUTING_FILTER_ORDER - 1;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() {
// get request context
RequestContext requestContext = RequestContext.getCurrentContext();
// get metadata of current thread
MetadataContext metadataContext = MetadataContextHolder.get();
// add new metadata and cover old
Map<String, String> customMetadata = metadataContext
.getAllTransitiveCustomMetadata();
if (!CollectionUtils.isEmpty(customMetadata)) {
String metadataStr = JacksonUtils.serialize2Json(customMetadata);
try {
requestContext.addZuulRequestHeader(
MetadataConstant.HeaderName.CUSTOM_METADATA,
URLEncoder.encode(metadataStr, "UTF-8"));
}
catch (UnsupportedEncodingException e) {
requestContext.addZuulRequestHeader(
MetadataConstant.HeaderName.CUSTOM_METADATA, metadataStr);
}
}
return null;
}
}

@ -43,8 +43,7 @@ import static com.tencent.cloud.common.constant.MetadataConstant.HeaderName.CUST
*/ */
public class Metadata2HeaderFeignInterceptor implements RequestInterceptor, Ordered { public class Metadata2HeaderFeignInterceptor implements RequestInterceptor, Ordered {
private static final Logger LOG = LoggerFactory private static final Logger LOG = LoggerFactory.getLogger(Metadata2HeaderFeignInterceptor.class);
.getLogger(Metadata2HeaderFeignInterceptor.class);
@Override @Override
public int getOrder() { public int getOrder() {
@ -57,27 +56,22 @@ public class Metadata2HeaderFeignInterceptor implements RequestInterceptor, Orde
MetadataContext metadataContext = MetadataContextHolder.get(); MetadataContext metadataContext = MetadataContextHolder.get();
// add new metadata and cover old // add new metadata and cover old
if (!CollectionUtils.isEmpty(requestTemplate.headers()) && !CollectionUtils if (!CollectionUtils.isEmpty(requestTemplate.headers())
.isEmpty(requestTemplate.headers().get(CUSTOM_METADATA))) { && !CollectionUtils.isEmpty(requestTemplate.headers().get(CUSTOM_METADATA))) {
for (String headerMetadataStr : requestTemplate.headers() for (String headerMetadataStr : requestTemplate.headers().get(CUSTOM_METADATA)) {
.get(CUSTOM_METADATA)) { Map<String, String> headerMetadataMap = JacksonUtils.deserialize2Map(headerMetadataStr);
Map<String, String> headerMetadataMap = JacksonUtils
.deserialize2Map(headerMetadataStr);
for (String key : headerMetadataMap.keySet()) { for (String key : headerMetadataMap.keySet()) {
metadataContext.putTransitiveCustomMetadata(key, metadataContext.putTransitiveCustomMetadata(key, headerMetadataMap.get(key));
headerMetadataMap.get(key));
} }
} }
} }
Map<String, String> customMetadata = metadataContext Map<String, String> customMetadata = metadataContext.getAllTransitiveCustomMetadata();
.getAllTransitiveCustomMetadata();
if (!CollectionUtils.isEmpty(customMetadata)) { if (!CollectionUtils.isEmpty(customMetadata)) {
String metadataStr = JacksonUtils.serialize2Json(customMetadata); String metadataStr = JacksonUtils.serialize2Json(customMetadata);
requestTemplate.removeHeader(CUSTOM_METADATA); requestTemplate.removeHeader(CUSTOM_METADATA);
try { try {
requestTemplate.header(CUSTOM_METADATA, requestTemplate.header(CUSTOM_METADATA, URLEncoder.encode(metadataStr, "UTF-8"));
URLEncoder.encode(metadataStr, "UTF-8"));
} }
catch (UnsupportedEncodingException e) { catch (UnsupportedEncodingException e) {
LOG.error("Set header failed.", e); LOG.error("Set header failed.", e);

@ -26,6 +26,7 @@ import com.tencent.cloud.common.constant.MetadataConstant;
import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.common.util.JacksonUtils; import com.tencent.cloud.common.util.JacksonUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
import org.springframework.http.HttpRequest; import org.springframework.http.HttpRequest;
@ -33,7 +34,6 @@ import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor; import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse; import org.springframework.http.client.ClientHttpResponse;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
/** /**
* Interceptor used for adding the metadata in http headers from context when web client * Interceptor used for adding the metadata in http headers from context when web client
@ -41,8 +41,7 @@ import org.springframework.util.StringUtils;
* *
* @author Haotian Zhang * @author Haotian Zhang
*/ */
public class Metadata2HeaderRestTemplateInterceptor public class Metadata2HeaderRestTemplateInterceptor implements ClientHttpRequestInterceptor, Ordered {
implements ClientHttpRequestInterceptor, Ordered {
@Override @Override
public int getOrder() { public int getOrder() {
@ -56,18 +55,14 @@ public class Metadata2HeaderRestTemplateInterceptor
MetadataContext metadataContext = MetadataContextHolder.get(); MetadataContext metadataContext = MetadataContextHolder.get();
// add new metadata and cover old // add new metadata and cover old
String metadataStr = httpRequest.getHeaders() String metadataStr = httpRequest.getHeaders().getFirst(MetadataConstant.HeaderName.CUSTOM_METADATA);
.getFirst(MetadataConstant.HeaderName.CUSTOM_METADATA); if (!StringUtils.isNotBlank(metadataStr)) {
if (!StringUtils.isEmpty(metadataStr)) { Map<String, String> headerMetadataMap = JacksonUtils.deserialize2Map(metadataStr);
Map<String, String> headerMetadataMap = JacksonUtils
.deserialize2Map(metadataStr);
for (String key : headerMetadataMap.keySet()) { for (String key : headerMetadataMap.keySet()) {
metadataContext.putTransitiveCustomMetadata(key, metadataContext.putTransitiveCustomMetadata(key, headerMetadataMap.get(key));
headerMetadataMap.get(key));
} }
} }
Map<String, String> customMetadata = metadataContext Map<String, String> customMetadata = metadataContext.getAllTransitiveCustomMetadata();
.getAllTransitiveCustomMetadata();
if (!CollectionUtils.isEmpty(customMetadata)) { if (!CollectionUtils.isEmpty(customMetadata)) {
metadataStr = JacksonUtils.serialize2Json(customMetadata); metadataStr = JacksonUtils.serialize2Json(customMetadata);
try { try {
@ -75,8 +70,7 @@ public class Metadata2HeaderRestTemplateInterceptor
URLEncoder.encode(metadataStr, "UTF-8")); URLEncoder.encode(metadataStr, "UTF-8"));
} }
catch (UnsupportedEncodingException e) { catch (UnsupportedEncodingException e) {
httpRequest.getHeaders().set(MetadataConstant.HeaderName.CUSTOM_METADATA, httpRequest.getHeaders().set(MetadataConstant.HeaderName.CUSTOM_METADATA, metadataStr);
metadataStr);
} }
} }
return clientHttpRequestExecution.execute(httpRequest, bytes); return clientHttpRequestExecution.execute(httpRequest, bytes);

@ -17,7 +17,6 @@
package com.tencent.cloud.metadata.config; package com.tencent.cloud.metadata.config;
import com.tencent.cloud.metadata.core.filter.gateway.Metadata2HeaderZuulFilter;
import com.tencent.cloud.metadata.core.interceptor.Metadata2HeaderFeignInterceptor; import com.tencent.cloud.metadata.core.interceptor.Metadata2HeaderFeignInterceptor;
import com.tencent.cloud.metadata.core.interceptor.Metadata2HeaderRestTemplateInterceptor; import com.tencent.cloud.metadata.core.interceptor.Metadata2HeaderRestTemplateInterceptor;
import org.assertj.core.api.Assertions; import org.assertj.core.api.Assertions;
@ -41,26 +40,18 @@ public class MetadataTransferAutoConfigurationTest {
*/ */
@Test @Test
public void test1() { public void test1() {
this.applicationContextRunner this.applicationContextRunner.withConfiguration(AutoConfigurations.of(MetadataTransferAutoConfiguration.class))
.withConfiguration(
AutoConfigurations.of(MetadataTransferAutoConfiguration.class))
.run(context -> { .run(context -> {
Assertions.assertThat(context).hasSingleBean( Assertions.assertThat(context).hasSingleBean(
MetadataTransferAutoConfiguration.MetadataTransferFeignInterceptorConfig.class); MetadataTransferAutoConfiguration.MetadataTransferFeignInterceptorConfig.class);
Assertions.assertThat(context).hasSingleBean(Metadata2HeaderFeignInterceptor.class);
Assertions.assertThat(context) Assertions.assertThat(context)
.hasSingleBean(Metadata2HeaderFeignInterceptor.class); .hasSingleBean(MetadataTransferAutoConfiguration.MetadataTransferRestTemplateConfig.class);
Assertions.assertThat(context).hasSingleBean( Assertions.assertThat(context).hasSingleBean(Metadata2HeaderRestTemplateInterceptor.class);
MetadataTransferAutoConfiguration.MetadataTransferRestTemplateConfig.class);
Assertions.assertThat(context)
.hasSingleBean(Metadata2HeaderRestTemplateInterceptor.class);
Assertions.assertThat(context).hasSingleBean( Assertions.assertThat(context).hasSingleBean(
MetadataTransferAutoConfiguration.MetadataTransferRestTemplateConfig.Metadata2HeaderRestTemplatePostProcessor.class); MetadataTransferAutoConfiguration.MetadataTransferRestTemplateConfig.Metadata2HeaderRestTemplatePostProcessor.class);
Assertions.assertThat(context).hasSingleBean(
MetadataTransferAutoConfiguration.MetadataTransferZuulFilterConfig.class);
Assertions.assertThat(context) Assertions.assertThat(context)
.hasSingleBean(Metadata2HeaderZuulFilter.class); .hasSingleBean(MetadataTransferAutoConfiguration.MetadataTransferScgFilterConfig.class);
Assertions.assertThat(context).hasSingleBean(
MetadataTransferAutoConfiguration.MetadataTransferScgFilterConfig.class);
Assertions.assertThat(context).hasSingleBean(GlobalFilter.class); Assertions.assertThat(context).hasSingleBean(GlobalFilter.class);
}); });
} }

@ -50,10 +50,8 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen
* @author Haotian Zhang * @author Haotian Zhang
*/ */
@RunWith(SpringRunner.class) @RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = DEFINED_PORT, @SpringBootTest(webEnvironment = DEFINED_PORT, classes = Metadata2HeaderFeignInterceptorTest.TestApplication.class,
classes = Metadata2HeaderFeignInterceptorTest.TestApplication.class, properties = { "server.port=8081", "spring.config.location = classpath:application-test.yml" })
properties = { "server.port=8081",
"spring.config.location = classpath:application-test.yml" })
public class Metadata2HeaderFeignInterceptorTest { public class Metadata2HeaderFeignInterceptorTest {
@Autowired @Autowired
@ -65,21 +63,12 @@ public class Metadata2HeaderFeignInterceptorTest {
@Test @Test
public void test1() { public void test1() {
String metadata = testFeign.test(); String metadata = testFeign.test();
Assertions.assertThat(metadata) Assertions.assertThat(metadata).isEqualTo("{\"a\":\"11\",\"b\":\"22\",\"c\":\"33\"}{}");
.isEqualTo("{\"a\":\"11\",\"b\":\"22\",\"c\":\"33\"}{}"); Assertions.assertThat(metadataLocalProperties.getContent().get("a")).isEqualTo("1");
Assertions.assertThat(metadataLocalProperties.getContent().get("a")) Assertions.assertThat(metadataLocalProperties.getContent().get("b")).isEqualTo("2");
.isEqualTo("1"); Assertions.assertThat(MetadataContextHolder.get().getTransitiveCustomMetadata("a")).isEqualTo("11");
Assertions.assertThat(metadataLocalProperties.getContent().get("b")) Assertions.assertThat(MetadataContextHolder.get().getTransitiveCustomMetadata("b")).isEqualTo("22");
.isEqualTo("2"); Assertions.assertThat(MetadataContextHolder.get().getTransitiveCustomMetadata("c")).isEqualTo("33");
Assertions
.assertThat(MetadataContextHolder.get().getTransitiveCustomMetadata("a"))
.isEqualTo("11");
Assertions
.assertThat(MetadataContextHolder.get().getTransitiveCustomMetadata("b"))
.isEqualTo("22");
Assertions
.assertThat(MetadataContextHolder.get().getTransitiveCustomMetadata("c"))
.isEqualTo("33");
} }
@SpringBootApplication @SpringBootApplication
@ -88,20 +77,17 @@ public class Metadata2HeaderFeignInterceptorTest {
protected static class TestApplication { protected static class TestApplication {
@RequestMapping("/test") @RequestMapping("/test")
public String test( public String test(@RequestHeader(MetadataConstant.HeaderName.CUSTOM_METADATA) String customMetadataStr)
@RequestHeader(MetadataConstant.HeaderName.CUSTOM_METADATA) String customMetadataStr)
throws UnsupportedEncodingException { throws UnsupportedEncodingException {
String systemMetadataStr = JacksonUtils String systemMetadataStr = JacksonUtils.serialize2Json(MetadataContextHolder.get().getAllSystemMetadata());
.serialize2Json(MetadataContextHolder.get().getAllSystemMetadata());
return URLDecoder.decode(customMetadataStr, "UTF-8") + systemMetadataStr; return URLDecoder.decode(customMetadataStr, "UTF-8") + systemMetadataStr;
} }
@FeignClient(name = "test-feign", url = "http://localhost:8081") @FeignClient(name = "test-feign", url = "http://localhost:8081")
public interface TestFeign { public interface TestFeign {
@RequestMapping(value = "/test", @RequestMapping(value = "/test", headers = {
headers = { MetadataConstant.HeaderName.CUSTOM_METADATA MetadataConstant.HeaderName.CUSTOM_METADATA + "={\"a\":\"11" + "\",\"b\":\"22\",\"c\":\"33\"}" })
+ "={\"a\":\"11" + "\",\"b\":\"22\",\"c\":\"33\"}" })
String test(); String test();
} }

@ -68,28 +68,17 @@ public class Metadata2HeaderRestTemplateInterceptorTest {
@Test @Test
public void test1() { public void test1() {
HttpHeaders httpHeaders = new HttpHeaders(); HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.set(MetadataConstant.HeaderName.CUSTOM_METADATA, httpHeaders.set(MetadataConstant.HeaderName.CUSTOM_METADATA, "{\"a\":\"11\",\"b\":\"22\",\"c\":\"33\"}");
"{\"a\":\"11\",\"b\":\"22\",\"c\":\"33\"}");
HttpEntity<String> httpEntity = new HttpEntity<>(httpHeaders); HttpEntity<String> httpEntity = new HttpEntity<>(httpHeaders);
String metadata = restTemplate String metadata = restTemplate
.exchange("http://localhost:" + localServerPort + "/test", HttpMethod.GET, .exchange("http://localhost:" + localServerPort + "/test", HttpMethod.GET, httpEntity, String.class)
httpEntity, String.class)
.getBody(); .getBody();
Assertions.assertThat(metadata) Assertions.assertThat(metadata).isEqualTo("{\"a\":\"11\",\"b\":\"22\",\"c\":\"33\"}{}");
.isEqualTo("{\"a\":\"11\",\"b\":\"22\",\"c\":\"33\"}{}"); Assertions.assertThat(metadataLocalProperties.getContent().get("a")).isEqualTo("1");
Assertions.assertThat(metadataLocalProperties.getContent().get("a")) Assertions.assertThat(metadataLocalProperties.getContent().get("b")).isEqualTo("2");
.isEqualTo("1"); Assertions.assertThat(MetadataContextHolder.get().getTransitiveCustomMetadata("a")).isEqualTo("11");
Assertions.assertThat(metadataLocalProperties.getContent().get("b")) Assertions.assertThat(MetadataContextHolder.get().getTransitiveCustomMetadata("b")).isEqualTo("22");
.isEqualTo("2"); Assertions.assertThat(MetadataContextHolder.get().getTransitiveCustomMetadata("c")).isEqualTo("33");
Assertions
.assertThat(MetadataContextHolder.get().getTransitiveCustomMetadata("a"))
.isEqualTo("11");
Assertions
.assertThat(MetadataContextHolder.get().getTransitiveCustomMetadata("b"))
.isEqualTo("22");
Assertions
.assertThat(MetadataContextHolder.get().getTransitiveCustomMetadata("c"))
.isEqualTo("33");
} }
@SpringBootApplication @SpringBootApplication
@ -102,11 +91,9 @@ public class Metadata2HeaderRestTemplateInterceptorTest {
} }
@RequestMapping("/test") @RequestMapping("/test")
public String test( public String test(@RequestHeader(MetadataConstant.HeaderName.CUSTOM_METADATA) String customMetadataStr)
@RequestHeader(MetadataConstant.HeaderName.CUSTOM_METADATA) String customMetadataStr)
throws UnsupportedEncodingException { throws UnsupportedEncodingException {
String systemMetadataStr = JacksonUtils String systemMetadataStr = JacksonUtils.serialize2Json(MetadataContextHolder.get().getAllSystemMetadata());
.serialize2Json(MetadataContextHolder.get().getAllSystemMetadata());
return URLDecoder.decode(customMetadataStr, "UTF-8") + systemMetadataStr; return URLDecoder.decode(customMetadataStr, "UTF-8") + systemMetadataStr;
} }

@ -4,7 +4,6 @@ spring:
autoconfigure: autoconfigure:
exclude: exclude:
- org.springframework.cloud.gateway.config.GatewayAutoConfiguration - org.springframework.cloud.gateway.config.GatewayAutoConfiguration
- org.springframework.cloud.netflix.zuul.ZuulServerAutoConfiguration
cloud: cloud:
tencent: tencent:
metadata: metadata:

@ -44,12 +44,6 @@
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId> <artifactId>spring-boot-starter-test</artifactId>

@ -30,8 +30,8 @@ import org.springframework.context.annotation.Configuration;
* *
* @author lepdou 2022-03-29 * @author lepdou 2022-03-29
*/ */
@ConditionalOnProperty(value = "spring.cloud.polaris.circuitbreaker.enabled", @ConditionalOnProperty(value = "spring.cloud.polaris.circuitbreaker.enabled", havingValue = "true",
havingValue = "true", matchIfMissing = true) matchIfMissing = true)
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
public class PolarisCircuitBreakerBootstrapConfiguration { public class PolarisCircuitBreakerBootstrapConfiguration {

@ -39,8 +39,8 @@ import static org.springframework.core.Ordered.HIGHEST_PRECEDENCE;
* *
* @author Haotian Zhang * @author Haotian Zhang
*/ */
@ConditionalOnProperty(value = "spring.cloud.polaris.circuitbreaker.enabled", @ConditionalOnProperty(value = "spring.cloud.polaris.circuitbreaker.enabled", havingValue = "true",
havingValue = "true", matchIfMissing = true) matchIfMissing = true)
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@AutoConfigureAfter(PolarisContextConfiguration.class) @AutoConfigureAfter(PolarisContextConfiguration.class)
@AutoConfigureBefore(FeignAutoConfiguration.class) @AutoConfigureBefore(FeignAutoConfiguration.class)
@ -53,8 +53,7 @@ public class PolarisFeignClientAutoConfiguration {
@Bean @Bean
@Order(HIGHEST_PRECEDENCE) @Order(HIGHEST_PRECEDENCE)
public PolarisFeignBeanPostProcessor polarisFeignBeanPostProcessor( public PolarisFeignBeanPostProcessor polarisFeignBeanPostProcessor(ConsumerAPI consumerAPI) {
ConsumerAPI consumerAPI) {
return new PolarisFeignBeanPostProcessor(consumerAPI); return new PolarisFeignBeanPostProcessor(consumerAPI);
} }

@ -24,19 +24,17 @@ import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.cloud.client.loadbalancer.LoadBalancerProperties;
import org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient; import org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient;
import org.springframework.cloud.netflix.ribbon.SpringClientFactory; import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalancerClient; import org.springframework.cloud.openfeign.loadbalancer.RetryableFeignBlockingLoadBalancerClient;
import org.springframework.cloud.openfeign.ribbon.CachingSpringLoadBalancerFactory;
import org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient;
/** /**
* Wrap Spring Bean and decorating proxy for Feign Client. * Wrap Spring Bean and decorating proxy for Feign Client.
* *
* @author Haotian Zhang * @author Haotian Zhang
*/ */
public class PolarisFeignBeanPostProcessor public class PolarisFeignBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {
implements BeanPostProcessor, BeanFactoryAware {
private final ConsumerAPI consumerAPI; private final ConsumerAPI consumerAPI;
@ -47,24 +45,18 @@ public class PolarisFeignBeanPostProcessor
} }
@Override @Override
public Object postProcessBeforeInitialization(Object bean, String beanName) public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
throws BeansException {
return wrapper(bean); return wrapper(bean);
} }
private Object wrapper(Object bean) { private Object wrapper(Object bean) {
if (isNeedWrap(bean)) { if (isNeedWrap(bean)) {
if (bean instanceof LoadBalancerFeignClient) { if (bean instanceof RetryableFeignBlockingLoadBalancerClient) {
LoadBalancerFeignClient client = ((LoadBalancerFeignClient) bean); RetryableFeignBlockingLoadBalancerClient client = (RetryableFeignBlockingLoadBalancerClient) bean;
return new PolarisLoadBalancerFeignClient( return new PolarisFeignBlockingLoadBalancerClient(createPolarisFeignClient(client.getDelegate()),
createPolarisFeignClient(client.getDelegate()), factory(), factory.getBean(BlockingLoadBalancerClient.class),
clientFactory()); factory.getBean(LoadBalancerProperties.class),
} factory.getBean(LoadBalancerClientFactory.class));
if (bean instanceof FeignBlockingLoadBalancerClient) {
FeignBlockingLoadBalancerClient client = (FeignBlockingLoadBalancerClient) bean;
return new PolarisFeignBlockingLoadBalancerClient(
createPolarisFeignClient(client.getDelegate()),
factory.getBean(BlockingLoadBalancerClient.class));
} }
return createPolarisFeignClient((Client) bean); return createPolarisFeignClient((Client) bean);
} }
@ -73,8 +65,7 @@ public class PolarisFeignBeanPostProcessor
private boolean isNeedWrap(Object bean) { private boolean isNeedWrap(Object bean) {
return bean instanceof Client && !(bean instanceof PolarisFeignClient) return bean instanceof Client && !(bean instanceof PolarisFeignClient)
&& !(bean instanceof PolarisFeignBlockingLoadBalancerClient) && !(bean instanceof PolarisFeignBlockingLoadBalancerClient);
&& !(bean instanceof PolarisLoadBalancerFeignClient);
} }
private PolarisFeignClient createPolarisFeignClient(Client delegate) { private PolarisFeignClient createPolarisFeignClient(Client delegate) {
@ -86,12 +77,4 @@ public class PolarisFeignBeanPostProcessor
this.factory = beanFactory; this.factory = beanFactory;
} }
CachingSpringLoadBalancerFactory factory() {
return this.factory.getBean(CachingSpringLoadBalancerFactory.class);
}
SpringClientFactory clientFactory() {
return this.factory.getBean(SpringClientFactory.class);
}
} }

@ -19,7 +19,9 @@ package com.tencent.cloud.polaris.circuitbreaker.feign;
import feign.Client; import feign.Client;
import org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient; import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.cloud.client.loadbalancer.LoadBalancerProperties;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalancerClient; import org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalancerClient;
/** /**
@ -27,12 +29,11 @@ import org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalance
* *
* @author Haotian Zhang * @author Haotian Zhang
*/ */
public class PolarisFeignBlockingLoadBalancerClient public class PolarisFeignBlockingLoadBalancerClient extends FeignBlockingLoadBalancerClient {
extends FeignBlockingLoadBalancerClient {
public PolarisFeignBlockingLoadBalancerClient(Client delegate, public PolarisFeignBlockingLoadBalancerClient(Client delegate, LoadBalancerClient loadBalancerClient,
BlockingLoadBalancerClient loadBalancerClient) { LoadBalancerProperties properties, LoadBalancerClientFactory loadBalancerClientFactory) {
super(delegate, loadBalancerClient); super(delegate, loadBalancerClient, properties, loadBalancerClientFactory);
} }
} }

@ -75,21 +75,17 @@ public class PolarisFeignClient implements Client {
ServiceCallResult resultRequest = new ServiceCallResult(); ServiceCallResult resultRequest = new ServiceCallResult();
MetadataContext metadataContext = MetadataContextHolder.get(); MetadataContext metadataContext = MetadataContextHolder.get();
String namespace = metadataContext String namespace = metadataContext.getSystemMetadata(SystemMetadataKey.PEER_NAMESPACE);
.getSystemMetadata(SystemMetadataKey.PEER_NAMESPACE);
resultRequest.setNamespace(namespace); resultRequest.setNamespace(namespace);
String serviceName = metadataContext String serviceName = metadataContext.getSystemMetadata(SystemMetadataKey.PEER_SERVICE);
.getSystemMetadata(SystemMetadataKey.PEER_SERVICE);
resultRequest.setService(serviceName); resultRequest.setService(serviceName);
String method = metadataContext.getSystemMetadata(SystemMetadataKey.PEER_PATH); String method = metadataContext.getSystemMetadata(SystemMetadataKey.PEER_PATH);
resultRequest.setMethod(method); resultRequest.setMethod(method);
resultRequest.setRetStatus(RetStatus.RetSuccess); resultRequest.setRetStatus(RetStatus.RetSuccess);
String sourceNamespace = MetadataContext.LOCAL_NAMESPACE; String sourceNamespace = MetadataContext.LOCAL_NAMESPACE;
String sourceService = MetadataContext.LOCAL_SERVICE; String sourceService = MetadataContext.LOCAL_SERVICE;
if (StringUtils.isNotBlank(sourceNamespace) if (StringUtils.isNotBlank(sourceNamespace) && StringUtils.isNotBlank(sourceService)) {
&& StringUtils.isNotBlank(sourceService)) { resultRequest.setCallerService(new ServiceKey(sourceNamespace, sourceService));
resultRequest
.setCallerService(new ServiceKey(sourceNamespace, sourceService));
} }
URI uri = URI.create(request.url()); URI uri = URI.create(request.url());
resultRequest.setHost(uri.getHost()); resultRequest.setHost(uri.getHost());

@ -1,39 +0,0 @@
/*
* 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.feign;
import feign.Client;
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
import org.springframework.cloud.openfeign.ribbon.CachingSpringLoadBalancerFactory;
import org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient;
/**
* Wrap for {@link LoadBalancerFeignClient}.
*
* @author Haotian Zhang
*/
public class PolarisLoadBalancerFeignClient extends LoadBalancerFeignClient {
public PolarisLoadBalancerFeignClient(Client delegate,
CachingSpringLoadBalancerFactory lbClientFactory,
SpringClientFactory clientFactory) {
super(delegate, lbClientFactory, clientFactory);
}
}

@ -45,8 +45,7 @@ public class PolarisFeignClientTest {
@Test @Test
public void testPolarisFeignBeanPostProcessor() { public void testPolarisFeignBeanPostProcessor() {
final PolarisFeignBeanPostProcessor postProcessor = springCtx final PolarisFeignBeanPostProcessor postProcessor = springCtx.getBean(PolarisFeignBeanPostProcessor.class);
.getBean(PolarisFeignBeanPostProcessor.class);
Assertions.assertNotNull(postProcessor, "PolarisFeignBeanPostProcessor"); Assertions.assertNotNull(postProcessor, "PolarisFeignBeanPostProcessor");
} }
@ -56,9 +55,6 @@ public class PolarisFeignClientTest {
if (client instanceof PolarisFeignClient) { if (client instanceof PolarisFeignClient) {
return; return;
} }
if (client instanceof PolarisLoadBalancerFeignClient) {
return;
}
if (client instanceof PolarisFeignBlockingLoadBalancerClient) { if (client instanceof PolarisFeignBlockingLoadBalancerClient) {
return; return;
} }

@ -37,8 +37,7 @@ public class TestPolarisFeignApp {
SpringApplication.run(TestPolarisFeignApp.class); SpringApplication.run(TestPolarisFeignApp.class);
} }
@FeignClient(name = "feign-service-polaris", @FeignClient(name = "feign-service-polaris", fallback = TestPolarisServiceFallback.class)
fallback = TestPolarisServiceFallback.class)
public interface TestPolarisService { public interface TestPolarisService {
/** /**

@ -48,8 +48,7 @@ public class ConfigurationModifier implements PolarisConfigModifier {
} }
// override polaris config server address // override polaris config server address
List<String> addresses = AddressUtils List<String> addresses = AddressUtils.parseAddressList(polarisConfigProperties.getAddress());
.parseAddressList(polarisConfigProperties.getAddress());
configuration.getConfigFile().getServerConnector().setAddresses(addresses); configuration.getConfigFile().getServerConnector().setAddresses(addresses);
} }

@ -28,22 +28,20 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
/** /**
* polaris config module auto configuration at init application context phase. * polaris config module auto configuration at init application context phase.
* *
* @author lepdou 2022-03-28 * @author lepdou 2022-03-28
*/ */
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(value = "spring.cloud.polaris.config.enabled", @ConditionalOnProperty(value = "spring.cloud.polaris.config.enabled", matchIfMissing = true)
matchIfMissing = true)
public class PolarisConfigAutoConfiguration { public class PolarisConfigAutoConfiguration {
@Bean @Bean
public PolarisPropertySourceAutoRefresher polarisPropertySourceAutoRefresher( public PolarisPropertySourceAutoRefresher polarisPropertySourceAutoRefresher(
PolarisConfigProperties polarisConfigProperties, PolarisConfigProperties polarisConfigProperties, PolarisPropertySourceManager polarisPropertySourceManager,
PolarisPropertySourceManager polarisPropertySourceManager,
ContextRefresher contextRefresher) { ContextRefresher contextRefresher) {
return new PolarisPropertySourceAutoRefresher(polarisConfigProperties, return new PolarisPropertySourceAutoRefresher(polarisConfigProperties, polarisPropertySourceManager,
polarisPropertySourceManager, contextRefresher); contextRefresher);
} }
} }

@ -37,8 +37,7 @@ import org.springframework.context.annotation.Import;
* @author lepdou 2022-03-10 * @author lepdou 2022-03-10
*/ */
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(value = "spring.cloud.polaris.config.enabled", @ConditionalOnProperty(value = "spring.cloud.polaris.config.enabled", matchIfMissing = true)
matchIfMissing = true)
@Import(PolarisContextConfiguration.class) @Import(PolarisContextConfiguration.class)
public class PolarisConfigBootstrapAutoConfiguration { public class PolarisConfigBootstrapAutoConfiguration {
@ -58,13 +57,10 @@ public class PolarisConfigBootstrapAutoConfiguration {
} }
@Bean @Bean
public PolarisConfigFileLocator polarisConfigFileLocator( public PolarisConfigFileLocator polarisConfigFileLocator(PolarisConfigProperties polarisConfigProperties,
PolarisConfigProperties polarisConfigProperties, PolarisContextProperties polarisContextProperties, ConfigFileService configFileService,
PolarisContextProperties polarisContextProperties,
ConfigFileService configFileService,
PolarisPropertySourceManager polarisPropertySourceManager) { PolarisPropertySourceManager polarisPropertySourceManager) {
return new PolarisConfigFileLocator(polarisConfigProperties, return new PolarisConfigFileLocator(polarisConfigProperties, polarisContextProperties, configFileService,
polarisContextProperties, configFileService,
polarisPropertySourceManager); polarisPropertySourceManager);
} }

@ -49,8 +49,7 @@ import org.springframework.util.StringUtils;
@Order(0) @Order(0)
public class PolarisConfigFileLocator implements PropertySourceLocator { public class PolarisConfigFileLocator implements PropertySourceLocator {
private static final Logger LOGGER = LoggerFactory private static final Logger LOGGER = LoggerFactory.getLogger(PolarisConfigFileLocator.class);
.getLogger(PolarisConfigFileLocator.class);
private static final String POLARIS_CONFIG_PROPERTY_SOURCE_NAME = "polaris-config"; private static final String POLARIS_CONFIG_PROPERTY_SOURCE_NAME = "polaris-config";
@ -63,8 +62,7 @@ public class PolarisConfigFileLocator implements PropertySourceLocator {
private final PolarisPropertySourceManager polarisPropertySourceManager; private final PolarisPropertySourceManager polarisPropertySourceManager;
public PolarisConfigFileLocator(PolarisConfigProperties polarisConfigProperties, public PolarisConfigFileLocator(PolarisConfigProperties polarisConfigProperties,
PolarisContextProperties polarisContextProperties, PolarisContextProperties polarisContextProperties, ConfigFileService configFileService,
ConfigFileService configFileService,
PolarisPropertySourceManager polarisPropertySourceManager) { PolarisPropertySourceManager polarisPropertySourceManager) {
this.polarisConfigProperties = polarisConfigProperties; this.polarisConfigProperties = polarisConfigProperties;
this.polarisContextProperties = polarisContextProperties; this.polarisContextProperties = polarisContextProperties;
@ -95,8 +93,7 @@ public class PolarisConfigFileLocator implements PropertySourceLocator {
String group = configFileGroup.getName(); String group = configFileGroup.getName();
if (StringUtils.isEmpty(group)) { if (StringUtils.isEmpty(group)) {
throw new IllegalArgumentException( throw new IllegalArgumentException("polaris config group name cannot be empty.");
"polaris config group name cannot be empty.");
} }
List<String> files = configFileGroup.getFiles(); List<String> files = configFileGroup.getFiles();
@ -105,8 +102,7 @@ public class PolarisConfigFileLocator implements PropertySourceLocator {
} }
for (String fileName : files) { for (String fileName : files) {
PolarisPropertySource polarisPropertySource = loadPolarisPropertySource( PolarisPropertySource polarisPropertySource = loadPolarisPropertySource(namespace, group, fileName);
namespace, group, fileName);
compositePropertySource.addPropertySource(polarisPropertySource); compositePropertySource.addPropertySource(polarisPropertySource);
@ -119,27 +115,21 @@ public class PolarisConfigFileLocator implements PropertySourceLocator {
} }
} }
private PolarisPropertySource loadPolarisPropertySource(String namespace, private PolarisPropertySource loadPolarisPropertySource(String namespace, String group, String fileName) {
String group, String fileName) {
ConfigKVFile configKVFile; ConfigKVFile configKVFile;
// unknown extension is resolved as properties file // unknown extension is resolved as properties file
if (ConfigFileFormat.isPropertyFile(fileName) if (ConfigFileFormat.isPropertyFile(fileName) || ConfigFileFormat.isUnknownFile(fileName)) {
|| ConfigFileFormat.isUnknownFile(fileName)) { configKVFile = configFileService.getConfigPropertiesFile(namespace, group, fileName);
configKVFile = configFileService.getConfigPropertiesFile(namespace, group,
fileName);
} }
else if (ConfigFileFormat.isYamlFile(fileName)) { else if (ConfigFileFormat.isYamlFile(fileName)) {
configKVFile = configFileService.getConfigYamlFile(namespace, group, configKVFile = configFileService.getConfigYamlFile(namespace, group, fileName);
fileName);
} }
else { else {
LOGGER.warn( LOGGER.warn("[SCT Config] Unsupported config file. namespace = {}, group = {}, fileName = {}", namespace,
"[SCT Config] Unsupported config file. namespace = {}, group = {}, fileName = {}", group, fileName);
namespace, group, fileName);
throw new IllegalStateException( throw new IllegalStateException("Only configuration files in the format of properties / yaml / yaml"
"Only configuration files in the format of properties / yaml / yaml" + " can be injected into the spring context");
+ " can be injected into the spring context");
} }
Map<String, Object> map = new ConcurrentHashMap<>(); Map<String, Object> map = new ConcurrentHashMap<>();

@ -39,8 +39,8 @@ public class PolarisPropertySource extends MapPropertySource {
private final ConfigKVFile configKVFile; private final ConfigKVFile configKVFile;
public PolarisPropertySource(String namespace, String group, String fileName, public PolarisPropertySource(String namespace, String group, String fileName, ConfigKVFile configKVFile,
ConfigKVFile configKVFile, Map<String, Object> source) { Map<String, Object> source) {
super(namespace + "-" + group + "-" + fileName, source); super(namespace + "-" + group + "-" + fileName, source);
this.namespace = namespace; this.namespace = namespace;
@ -71,8 +71,8 @@ public class PolarisPropertySource extends MapPropertySource {
@Override @Override
public String toString() { public String toString() {
return "PolarisPropertySource{" + "namespace='" + namespace + '\'' + ", group='" return "PolarisPropertySource{" + "namespace='" + namespace + '\'' + ", group='" + group + '\'' + ", fileName='"
+ group + '\'' + ", fileName='" + fileName + '\'' + '}'; + fileName + '\'' + '}';
} }
} }

@ -46,8 +46,7 @@ import org.springframework.util.CollectionUtils;
public class PolarisPropertySourceAutoRefresher public class PolarisPropertySourceAutoRefresher
implements ApplicationListener<ApplicationReadyEvent>, ApplicationContextAware { implements ApplicationListener<ApplicationReadyEvent>, ApplicationContextAware {
private static final Logger LOGGER = LoggerFactory private static final Logger LOGGER = LoggerFactory.getLogger(PolarisPropertySourceAutoRefresher.class);
.getLogger(PolarisPropertySourceAutoRefresher.class);
private final PolarisConfigProperties polarisConfigProperties; private final PolarisConfigProperties polarisConfigProperties;
@ -59,18 +58,15 @@ public class PolarisPropertySourceAutoRefresher
private final AtomicBoolean registered = new AtomicBoolean(false); private final AtomicBoolean registered = new AtomicBoolean(false);
public PolarisPropertySourceAutoRefresher( public PolarisPropertySourceAutoRefresher(PolarisConfigProperties polarisConfigProperties,
PolarisConfigProperties polarisConfigProperties, PolarisPropertySourceManager polarisPropertySourceManager, ContextRefresher contextRefresher) {
PolarisPropertySourceManager polarisPropertySourceManager,
ContextRefresher contextRefresher) {
this.polarisConfigProperties = polarisConfigProperties; this.polarisConfigProperties = polarisConfigProperties;
this.polarisPropertySourceManager = polarisPropertySourceManager; this.polarisPropertySourceManager = polarisPropertySourceManager;
this.contextRefresher = contextRefresher; this.contextRefresher = contextRefresher;
} }
@Override @Override
public void setApplicationContext(ApplicationContext applicationContext) public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
throws BeansException {
this.applicationContext = applicationContext; this.applicationContext = applicationContext;
} }
@ -84,8 +80,7 @@ public class PolarisPropertySourceAutoRefresher
return; return;
} }
List<PolarisPropertySource> polarisPropertySources = polarisPropertySourceManager List<PolarisPropertySource> polarisPropertySources = polarisPropertySourceManager.getAllPropertySources();
.getAllPropertySources();
if (CollectionUtils.isEmpty(polarisPropertySources)) { if (CollectionUtils.isEmpty(polarisPropertySources)) {
return; return;
} }
@ -96,45 +91,38 @@ public class PolarisPropertySourceAutoRefresher
// register polaris config publish event // register polaris config publish event
for (PolarisPropertySource polarisPropertySource : polarisPropertySources) { for (PolarisPropertySource polarisPropertySource : polarisPropertySources) {
polarisPropertySource.getConfigKVFile() polarisPropertySource.getConfigKVFile().addChangeListener(new ConfigKVFileChangeListener() {
.addChangeListener(new ConfigKVFileChangeListener() { @Override
@Override public void onChange(ConfigKVFileChangeEvent configKVFileChangeEvent) {
public void onChange( LOGGER.info(
ConfigKVFileChangeEvent configKVFileChangeEvent) { "[SCT Config] received polaris config change event and will refresh spring context."
LOGGER.info( + "namespace = {}, group = {}, fileName = {}",
"[SCT Config] received polaris config change event and will refresh spring context." polarisPropertySource.getNamespace(), polarisPropertySource.getGroup(),
+ "namespace = {}, group = {}, fileName = {}", polarisPropertySource.getFileName());
polarisPropertySource.getNamespace(),
polarisPropertySource.getGroup(), Map<String, Object> source = polarisPropertySource.getSource();
polarisPropertySource.getFileName());
for (String changedKey : configKVFileChangeEvent.changedKeys()) {
Map<String, Object> source = polarisPropertySource ConfigPropertyChangeInfo configPropertyChangeInfo = configKVFileChangeEvent
.getSource(); .getChangeInfo(changedKey);
for (String changedKey : configKVFileChangeEvent LOGGER.info("[SCT Config] changed property = {}", configPropertyChangeInfo);
.changedKeys()) {
ConfigPropertyChangeInfo configPropertyChangeInfo = configKVFileChangeEvent switch (configPropertyChangeInfo.getChangeType()) {
.getChangeInfo(changedKey); case MODIFIED:
case ADDED:
LOGGER.info("[SCT Config] changed property = {}", source.put(changedKey, configPropertyChangeInfo.getNewValue());
configPropertyChangeInfo); break;
case DELETED:
switch (configPropertyChangeInfo.getChangeType()) { source.remove(changedKey);
case MODIFIED: break;
case ADDED:
source.put(changedKey,
configPropertyChangeInfo.getNewValue());
break;
case DELETED:
source.remove(changedKey);
break;
}
}
// rebuild beans with @RefreshScope annotation
contextRefresher.refresh();
} }
}); }
// rebuild beans with @RefreshScope annotation
contextRefresher.refresh();
}
});
} }
} }

@ -33,8 +33,7 @@ public class PolarisPropertySourceManager {
private final Map<String, PolarisPropertySource> polarisPropertySources = new ConcurrentHashMap<>(); private final Map<String, PolarisPropertySource> polarisPropertySources = new ConcurrentHashMap<>();
public void addPropertySource(PolarisPropertySource polarisPropertySource) { public void addPropertySource(PolarisPropertySource polarisPropertySource) {
polarisPropertySources.putIfAbsent(polarisPropertySource.getPropertySourceName(), polarisPropertySources.putIfAbsent(polarisPropertySource.getPropertySourceName(), polarisPropertySource);
polarisPropertySource);
} }
public List<PolarisPropertySource> getAllPropertySources() { public List<PolarisPropertySource> getAllPropertySources() {

@ -15,70 +15,71 @@
<dependencies> <dependencies>
<!-- Spring Cloud Tencent dependencies start --> <!-- Spring Cloud Tencent dependencies start -->
<dependency> <dependency>
<groupId>com.tencent.cloud</groupId> <groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-tencent-polaris-context</artifactId> <artifactId>spring-cloud-tencent-polaris-context</artifactId>
</dependency> </dependency>
<!-- Spring Cloud Tencent dependencies end --> <!-- Spring Cloud Tencent dependencies end -->
<!-- Polaris dependencies start --> <!-- Polaris dependencies start -->
<dependency> <dependency>
<groupId>com.tencent.polaris</groupId> <groupId>com.tencent.polaris</groupId>
<artifactId>polaris-discovery-factory</artifactId> <artifactId>polaris-discovery-factory</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.tencent.polaris</groupId> <groupId>com.tencent.polaris</groupId>
<artifactId>polaris-test-common</artifactId> <artifactId>polaris-test-common</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.tencent.polaris</groupId> <groupId>com.tencent.polaris</groupId>
<artifactId>polaris-test-mock-discovery</artifactId> <artifactId>polaris-test-mock-discovery</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<!-- Polaris dependencies end --> <!-- Polaris dependencies end -->
<dependency> <dependency>
<groupId>org.springframework.cloud</groupId> <groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId> <artifactId>spring-cloud-loadbalancer</artifactId>
</dependency> <optional>true</optional>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId> <artifactId>spring-boot-starter-web</artifactId>
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId> <artifactId>spring-boot-starter-webflux</artifactId>
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId> <artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>io.projectreactor</groupId> <groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId> <artifactId>reactor-test</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.powermock</groupId> <groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId> <artifactId>powermock-module-junit4</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.powermock</groupId> <groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito2</artifactId> <artifactId>powermock-api-mockito2</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
</dependencies> </dependencies>
</project> </project>

@ -102,16 +102,13 @@ public class PolarisDiscoveryProperties {
@PostConstruct @PostConstruct
public void init() { public void init() {
if (StringUtils.isEmpty(this.getNamespace())) { if (StringUtils.isEmpty(this.getNamespace())) {
this.setNamespace(environment this.setNamespace(environment.resolvePlaceholders("${spring.cloud.polaris.discovery.namespace:}"));
.resolvePlaceholders("${spring.cloud.polaris.discovery.namespace:}"));
} }
if (StringUtils.isEmpty(this.getService())) { if (StringUtils.isEmpty(this.getService())) {
this.setService(environment this.setService(environment.resolvePlaceholders("${spring.cloud.polaris.discovery.service:}"));
.resolvePlaceholders("${spring.cloud.polaris.discovery.service:}"));
} }
if (StringUtils.isEmpty(this.getToken())) { if (StringUtils.isEmpty(this.getToken())) {
this.setToken(environment this.setToken(environment.resolvePlaceholders("${spring.cloud.polaris.discovery.token:}"));
.resolvePlaceholders("${spring.cloud.polaris.discovery.token:}"));
} }
} }
@ -200,12 +197,10 @@ public class PolarisDiscoveryProperties {
@Override @Override
public String toString() { public String toString() {
return "PolarisProperties{" + "token='" + token + '\'' + ", namespace='" return "PolarisProperties{" + "token='" + token + '\'' + ", namespace='" + namespace + '\'' + ", service='"
+ namespace + '\'' + ", service='" + service + '\'' + ", weight=" + weight + service + '\'' + ", weight=" + weight + ", version='" + version + '\'' + ", protocol='" + protocol
+ ", version='" + version + '\'' + ", protocol='" + protocol + '\'' + '\'' + ", port=" + port + '\'' + ", registerEnabled=" + registerEnabled + ", heartbeatEnabled="
+ ", port=" + port + '\'' + ", registerEnabled=" + registerEnabled + heartbeatEnabled + ", healthCheckUrl=" + healthCheckUrl + ", environment=" + environment + '}';
+ ", heartbeatEnabled=" + heartbeatEnabled + ", healthCheckUrl="
+ healthCheckUrl + ", environment=" + environment + '}';
} }
} }

@ -31,8 +31,7 @@ import org.springframework.cloud.client.ConditionalOnDiscoveryEnabled;
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD }) @Target({ ElementType.TYPE, ElementType.METHOD })
@ConditionalOnDiscoveryEnabled @ConditionalOnDiscoveryEnabled
@ConditionalOnProperty(value = "spring.cloud.polaris.discovery.enabled", @ConditionalOnProperty(value = "spring.cloud.polaris.discovery.enabled", matchIfMissing = true)
matchIfMissing = true)
public @interface ConditionalOnPolarisDiscoveryEnabled { public @interface ConditionalOnPolarisDiscoveryEnabled {
} }

@ -39,8 +39,7 @@ import org.springframework.context.annotation.Import;
*/ */
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnPolarisDiscoveryEnabled @ConditionalOnPolarisDiscoveryEnabled
@Import({ PolarisDiscoveryClientConfiguration.class, @Import({ PolarisDiscoveryClientConfiguration.class, PolarisReactiveDiscoveryClientConfiguration.class,
PolarisReactiveDiscoveryClientConfiguration.class,
ConsulContextProperties.class }) ConsulContextProperties.class })
public class PolarisDiscoveryAutoConfiguration { public class PolarisDiscoveryAutoConfiguration {
@ -52,15 +51,13 @@ public class PolarisDiscoveryAutoConfiguration {
@Bean(name = "polarisProvider") @Bean(name = "polarisProvider")
@ConditionalOnMissingBean @ConditionalOnMissingBean
public ProviderAPI polarisProvider(SDKContext polarisContext) public ProviderAPI polarisProvider(SDKContext polarisContext) throws PolarisException {
throws PolarisException {
return DiscoveryAPIFactory.createProviderAPIByContext(polarisContext); return DiscoveryAPIFactory.createProviderAPIByContext(polarisContext);
} }
@Bean(name = "polarisConsumer") @Bean(name = "polarisConsumer")
@ConditionalOnMissingBean @ConditionalOnMissingBean
public ConsumerAPI polarisConsumer(SDKContext polarisContext) public ConsumerAPI polarisConsumer(SDKContext polarisContext) throws PolarisException {
throws PolarisException {
return DiscoveryAPIFactory.createConsumerAPIByContext(polarisContext); return DiscoveryAPIFactory.createConsumerAPIByContext(polarisContext);
} }
@ -72,8 +69,7 @@ public class PolarisDiscoveryAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public PolarisServiceDiscovery polarisServiceDiscovery( public PolarisServiceDiscovery polarisServiceDiscovery(PolarisDiscoveryHandler polarisDiscoveryHandler) {
PolarisDiscoveryHandler polarisDiscoveryHandler) {
return new PolarisServiceDiscovery(polarisDiscoveryHandler); return new PolarisServiceDiscovery(polarisDiscoveryHandler);
} }

@ -33,14 +33,12 @@ import org.springframework.context.annotation.Configuration;
*/ */
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnBlockingDiscoveryEnabled @ConditionalOnBlockingDiscoveryEnabled
@AutoConfigureBefore({ SimpleDiscoveryClientAutoConfiguration.class, @AutoConfigureBefore({ SimpleDiscoveryClientAutoConfiguration.class, CommonsClientAutoConfiguration.class })
CommonsClientAutoConfiguration.class })
@AutoConfigureAfter(PolarisDiscoveryAutoConfiguration.class) @AutoConfigureAfter(PolarisDiscoveryAutoConfiguration.class)
public class PolarisDiscoveryClientConfiguration { public class PolarisDiscoveryClientConfiguration {
@Bean @Bean
public DiscoveryClient polarisDiscoveryClient( public DiscoveryClient polarisDiscoveryClient(PolarisServiceDiscovery polarisServiceDiscovery) {
PolarisServiceDiscovery polarisServiceDiscovery) {
return new PolarisDiscoveryClient(polarisServiceDiscovery); return new PolarisDiscoveryClient(polarisServiceDiscovery);
} }

@ -64,13 +64,11 @@ public class PolarisDiscoveryHandler {
GetInstancesRequest getInstancesRequest = new GetInstancesRequest(); GetInstancesRequest getInstancesRequest = new GetInstancesRequest();
getInstancesRequest.setNamespace(namespace); getInstancesRequest.setNamespace(namespace);
getInstancesRequest.setService(service); getInstancesRequest.setService(service);
String method = MetadataContextHolder.get() String method = MetadataContextHolder.get().getSystemMetadata(SystemMetadataKey.PEER_PATH);
.getSystemMetadata(SystemMetadataKey.PEER_PATH);
getInstancesRequest.setMethod(method); getInstancesRequest.setMethod(method);
String localNamespace = MetadataContext.LOCAL_NAMESPACE; String localNamespace = MetadataContext.LOCAL_NAMESPACE;
String localService = MetadataContext.LOCAL_SERVICE; String localService = MetadataContext.LOCAL_SERVICE;
Map<String, String> allTransitiveCustomMetadata = MetadataContextHolder.get() Map<String, String> allTransitiveCustomMetadata = MetadataContextHolder.get().getAllTransitiveCustomMetadata();
.getAllTransitiveCustomMetadata();
if (StringUtils.isNotBlank(localNamespace) || StringUtils.isNotBlank(localService) if (StringUtils.isNotBlank(localNamespace) || StringUtils.isNotBlank(localService)
|| null != allTransitiveCustomMetadata) { || null != allTransitiveCustomMetadata) {
ServiceInfo sourceService = new ServiceInfo(); ServiceInfo sourceService = new ServiceInfo();

@ -49,8 +49,7 @@ public class PolarisServiceDiscovery {
*/ */
public List<ServiceInstance> getInstances(String serviceId) throws PolarisException { public List<ServiceInstance> getInstances(String serviceId) throws PolarisException {
List<ServiceInstance> instances = new ArrayList<>(); List<ServiceInstance> instances = new ArrayList<>();
InstancesResponse filteredInstances = polarisDiscoveryHandler InstancesResponse filteredInstances = polarisDiscoveryHandler.getFilteredInstances(serviceId);
.getFilteredInstances(serviceId);
ServiceInstances serviceInstances = filteredInstances.toServiceInstances(); ServiceInstances serviceInstances = filteredInstances.toServiceInstances();
for (Instance instance : serviceInstances.getInstances()) { for (Instance instance : serviceInstances.getInstances()) {
instances.add(new PolarisServiceInstance(instance)); instances.add(new PolarisServiceInstance(instance));
@ -64,8 +63,8 @@ public class PolarisServiceDiscovery {
* @throws PolarisException polarisException * @throws PolarisException polarisException
*/ */
public List<String> getServices() throws PolarisException { public List<String> getServices() throws PolarisException {
return polarisDiscoveryHandler.GetServices().getServices().stream() return polarisDiscoveryHandler.GetServices().getServices().stream().map(ServiceInfo::getService)
.map(ServiceInfo::getService).collect(Collectors.toList()); .collect(Collectors.toList());
} }
} }

@ -38,13 +38,11 @@ import org.springframework.cloud.client.discovery.ReactiveDiscoveryClient;
*/ */
public class PolarisReactiveDiscoveryClient implements ReactiveDiscoveryClient { public class PolarisReactiveDiscoveryClient implements ReactiveDiscoveryClient {
private static final Logger log = LoggerFactory private static final Logger log = LoggerFactory.getLogger(PolarisReactiveDiscoveryClient.class);
.getLogger(PolarisReactiveDiscoveryClient.class);
private PolarisServiceDiscovery polarisServiceDiscovery; private PolarisServiceDiscovery polarisServiceDiscovery;
public PolarisReactiveDiscoveryClient( public PolarisReactiveDiscoveryClient(PolarisServiceDiscovery polarisServiceDiscovery) {
PolarisServiceDiscovery polarisServiceDiscovery) {
this.polarisServiceDiscovery = polarisServiceDiscovery; this.polarisServiceDiscovery = polarisServiceDiscovery;
} }

@ -100,37 +100,29 @@ public class ConsulContextProperties {
@Override @Override
public void modify(ConfigurationImpl configuration) { public void modify(ConfigurationImpl configuration) {
if (consulContextProperties != null && consulContextProperties.enabled if (consulContextProperties != null && consulContextProperties.enabled
&& consulContextProperties.discoveryEnabled && consulContextProperties.discoveryEnabled && consulContextProperties.register) {
&& consulContextProperties.register) { if (CollectionUtils.isEmpty(configuration.getGlobal().getServerConnectors())) {
if (CollectionUtils
.isEmpty(configuration.getGlobal().getServerConnectors())) {
configuration.getGlobal().setServerConnectors(new ArrayList<>()); configuration.getGlobal().setServerConnectors(new ArrayList<>());
} }
configuration.getGlobal().getServerConnectors() configuration.getGlobal().getServerConnectors().add(configuration.getGlobal().getServerConnector());
.add(configuration.getGlobal().getServerConnector());
ServerConnectorConfigImpl serverConnectorConfig = new ServerConnectorConfigImpl(); ServerConnectorConfigImpl serverConnectorConfig = new ServerConnectorConfigImpl();
serverConnectorConfig.setAddresses( serverConnectorConfig.setAddresses(
Collections.singletonList(consulContextProperties.host + ":" Collections.singletonList(consulContextProperties.host + ":" + consulContextProperties.port));
+ consulContextProperties.port));
serverConnectorConfig.setProtocol(DefaultPlugins.SERVER_CONNECTOR_CONSUL); serverConnectorConfig.setProtocol(DefaultPlugins.SERVER_CONNECTOR_CONSUL);
Map<String, String> metadata = serverConnectorConfig.getMetadata(); Map<String, String> metadata = serverConnectorConfig.getMetadata();
if (StringUtils.isNotBlank(consulContextProperties.serviceName)) { if (StringUtils.isNotBlank(consulContextProperties.serviceName)) {
metadata.put(MetadataMapKey.SERVICE_NAME_KEY, metadata.put(MetadataMapKey.SERVICE_NAME_KEY, consulContextProperties.serviceName);
consulContextProperties.serviceName);
} }
if (StringUtils.isNotBlank(consulContextProperties.instanceId)) { if (StringUtils.isNotBlank(consulContextProperties.instanceId)) {
metadata.put(MetadataMapKey.INSTANCE_ID_KEY, metadata.put(MetadataMapKey.INSTANCE_ID_KEY, consulContextProperties.instanceId);
consulContextProperties.instanceId);
} }
if (consulContextProperties.preferIpAddress if (consulContextProperties.preferIpAddress
&& StringUtils.isNotBlank(consulContextProperties.ipAddress)) { && StringUtils.isNotBlank(consulContextProperties.ipAddress)) {
metadata.put(MetadataMapKey.PREFER_IP_ADDRESS_KEY, metadata.put(MetadataMapKey.PREFER_IP_ADDRESS_KEY,
String.valueOf(consulContextProperties.preferIpAddress)); String.valueOf(consulContextProperties.preferIpAddress));
metadata.put(MetadataMapKey.IP_ADDRESS_KEY, metadata.put(MetadataMapKey.IP_ADDRESS_KEY, consulContextProperties.ipAddress);
consulContextProperties.ipAddress);
} }
configuration.getGlobal().getServerConnectors() configuration.getGlobal().getServerConnectors().add(serverConnectorConfig);
.add(serverConnectorConfig);
} }
} }

@ -31,17 +31,14 @@ import org.springframework.util.StringUtils;
* *
* @author Haotian Zhang, Andrew Shan, Jie Cheng * @author Haotian Zhang, Andrew Shan, Jie Cheng
*/ */
public class PolarisAutoServiceRegistration public class PolarisAutoServiceRegistration extends AbstractAutoServiceRegistration<Registration> {
extends AbstractAutoServiceRegistration<Registration> {
private static final Logger log = LoggerFactory private static final Logger log = LoggerFactory.getLogger(PolarisAutoServiceRegistration.class);
.getLogger(PolarisAutoServiceRegistration.class);
private final PolarisRegistration registration; private final PolarisRegistration registration;
public PolarisAutoServiceRegistration(ServiceRegistry<Registration> serviceRegistry, public PolarisAutoServiceRegistration(ServiceRegistry<Registration> serviceRegistry,
AutoServiceRegistrationProperties autoServiceRegistrationProperties, AutoServiceRegistrationProperties autoServiceRegistrationProperties, PolarisRegistration registration) {
PolarisRegistration registration) {
super(serviceRegistry, autoServiceRegistrationProperties); super(serviceRegistry, autoServiceRegistrationProperties);
this.registration = registration; this.registration = registration;
} }

@ -41,8 +41,7 @@ public class PolarisRegistration implements Registration, ServiceInstance {
private final SDKContext polarisContext; private final SDKContext polarisContext;
public PolarisRegistration(PolarisDiscoveryProperties polarisDiscoveryProperties, public PolarisRegistration(PolarisDiscoveryProperties polarisDiscoveryProperties, SDKContext context) {
SDKContext context) {
this.polarisDiscoveryProperties = polarisDiscoveryProperties; this.polarisDiscoveryProperties = polarisDiscoveryProperties;
this.polarisContext = context; this.polarisContext = context;
} }
@ -68,8 +67,7 @@ public class PolarisRegistration implements Registration, ServiceInstance {
@Override @Override
public boolean isSecure() { public boolean isSecure() {
return StringUtils.equalsIgnoreCase(polarisDiscoveryProperties.getProtocol(), return StringUtils.equalsIgnoreCase(polarisDiscoveryProperties.getProtocol(), "https");
"https");
} }
@Override @Override
@ -88,8 +86,8 @@ public class PolarisRegistration implements Registration, ServiceInstance {
@Override @Override
public String toString() { public String toString() {
return "PolarisRegistration{" + "polarisDiscoveryProperties=" return "PolarisRegistration{" + "polarisDiscoveryProperties=" + polarisDiscoveryProperties + ", polarisContext="
+ polarisDiscoveryProperties + ", polarisContext=" + polarisContext + '}'; + polarisContext + '}';
} }
} }

@ -34,14 +34,13 @@ import com.tencent.polaris.api.rpc.InstanceHeartbeatRequest;
import com.tencent.polaris.api.rpc.InstanceRegisterRequest; import com.tencent.polaris.api.rpc.InstanceRegisterRequest;
import com.tencent.polaris.api.rpc.InstancesResponse; import com.tencent.polaris.api.rpc.InstancesResponse;
import com.tencent.polaris.client.util.NamedThreadFactory; import com.tencent.polaris.client.util.NamedThreadFactory;
import org.apache.logging.log4j.util.Strings; import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.cloud.client.serviceregistry.Registration; import org.springframework.cloud.client.serviceregistry.Registration;
import org.springframework.cloud.client.serviceregistry.ServiceRegistry; import org.springframework.cloud.client.serviceregistry.ServiceRegistry;
import org.springframework.util.StringUtils;
import static org.springframework.util.ReflectionUtils.rethrowRuntimeException; import static org.springframework.util.ReflectionUtils.rethrowRuntimeException;
@ -52,8 +51,7 @@ import static org.springframework.util.ReflectionUtils.rethrowRuntimeException;
*/ */
public class PolarisServiceRegistry implements ServiceRegistry<Registration> { public class PolarisServiceRegistry implements ServiceRegistry<Registration> {
private static final Logger log = LoggerFactory private static final Logger log = LoggerFactory.getLogger(PolarisServiceRegistry.class);
.getLogger(PolarisServiceRegistry.class);
private static final int ttl = 5; private static final int ttl = 5;
@ -66,14 +64,13 @@ public class PolarisServiceRegistry implements ServiceRegistry<Registration> {
private final ScheduledExecutorService heartbeatExecutor; private final ScheduledExecutorService heartbeatExecutor;
public PolarisServiceRegistry(PolarisDiscoveryProperties polarisDiscoveryProperties, public PolarisServiceRegistry(PolarisDiscoveryProperties polarisDiscoveryProperties,
PolarisDiscoveryHandler polarisDiscoveryHandler, PolarisDiscoveryHandler polarisDiscoveryHandler, MetadataLocalProperties metadataLocalProperties) {
MetadataLocalProperties metadataLocalProperties) {
this.polarisDiscoveryProperties = polarisDiscoveryProperties; this.polarisDiscoveryProperties = polarisDiscoveryProperties;
this.polarisDiscoveryHandler = polarisDiscoveryHandler; this.polarisDiscoveryHandler = polarisDiscoveryHandler;
this.metadataLocalProperties = metadataLocalProperties; this.metadataLocalProperties = metadataLocalProperties;
if (polarisDiscoveryProperties.isHeartbeatEnabled()) { if (polarisDiscoveryProperties.isHeartbeatEnabled()) {
ScheduledThreadPoolExecutor heartbeatExecutor = new ScheduledThreadPoolExecutor( ScheduledThreadPoolExecutor heartbeatExecutor = new ScheduledThreadPoolExecutor(0,
0, new NamedThreadFactory("spring-cloud-heartbeat")); new NamedThreadFactory("spring-cloud-heartbeat"));
heartbeatExecutor.setMaximumPoolSize(1); heartbeatExecutor.setMaximumPoolSize(1);
this.heartbeatExecutor = heartbeatExecutor; this.heartbeatExecutor = heartbeatExecutor;
} }
@ -85,7 +82,7 @@ public class PolarisServiceRegistry implements ServiceRegistry<Registration> {
@Override @Override
public void register(Registration registration) { public void register(Registration registration) {
if (StringUtils.isEmpty(registration.getServiceId())) { if (StringUtils.isBlank(registration.getServiceId())) {
log.warn("No service to register for polaris client..."); log.warn("No service to register for polaris client...");
return; return;
} }
@ -105,10 +102,9 @@ public class PolarisServiceRegistry implements ServiceRegistry<Registration> {
try { try {
ProviderAPI providerClient = polarisDiscoveryHandler.getProviderAPI(); ProviderAPI providerClient = polarisDiscoveryHandler.getProviderAPI();
providerClient.register(instanceRegisterRequest); providerClient.register(instanceRegisterRequest);
log.info("polaris registry, {} {} {}:{} {} register finished", log.info("polaris registry, {} {} {}:{} {} register finished", polarisDiscoveryProperties.getNamespace(),
polarisDiscoveryProperties.getNamespace(), registration.getServiceId(), registration.getHost(), registration.getPort(),
registration.getServiceId(), registration.getHost(), metadataLocalProperties.getContent());
registration.getPort(), metadataLocalProperties.getContent());
if (null != heartbeatExecutor) { if (null != heartbeatExecutor) {
InstanceHeartbeatRequest heartbeatRequest = new InstanceHeartbeatRequest(); InstanceHeartbeatRequest heartbeatRequest = new InstanceHeartbeatRequest();
@ -118,8 +114,7 @@ public class PolarisServiceRegistry implements ServiceRegistry<Registration> {
} }
} }
catch (Exception e) { catch (Exception e) {
log.error("polaris registry, {} register failed...{},", log.error("polaris registry, {} register failed...{},", registration.getServiceId(), registration, e);
registration.getServiceId(), registration, e);
rethrowRuntimeException(e); rethrowRuntimeException(e);
} }
} }
@ -146,8 +141,7 @@ public class PolarisServiceRegistry implements ServiceRegistry<Registration> {
providerClient.deRegister(deRegisterRequest); providerClient.deRegister(deRegisterRequest);
} }
catch (Exception e) { catch (Exception e) {
log.error("ERR_POLARIS_DEREGISTER, de-register failed...{},", registration, log.error("ERR_POLARIS_DEREGISTER, de-register failed...{},", registration, e);
e);
} }
finally { finally {
if (null != heartbeatExecutor) { if (null != heartbeatExecutor) {
@ -170,8 +164,7 @@ public class PolarisServiceRegistry implements ServiceRegistry<Registration> {
@Override @Override
public Object getStatus(Registration registration) { public Object getStatus(Registration registration) {
String serviceName = registration.getServiceId(); String serviceName = registration.getServiceId();
InstancesResponse instancesResponse = polarisDiscoveryHandler InstancesResponse instancesResponse = polarisDiscoveryHandler.getInstances(serviceName);
.getInstances(serviceName);
Instance[] instances = instancesResponse.getInstances(); Instance[] instances = instancesResponse.getInstances();
if (null == instances || instances.length == 0) { if (null == instances || instances.length == 0) {
return null; return null;
@ -192,25 +185,22 @@ public class PolarisServiceRegistry implements ServiceRegistry<Registration> {
public void heartbeat(InstanceHeartbeatRequest heartbeatRequest) { public void heartbeat(InstanceHeartbeatRequest heartbeatRequest) {
heartbeatExecutor.scheduleWithFixedDelay(() -> { heartbeatExecutor.scheduleWithFixedDelay(() -> {
try { try {
String healthCheckEndpoint = polarisDiscoveryProperties String healthCheckEndpoint = polarisDiscoveryProperties.getHealthCheckUrl();
.getHealthCheckUrl();
// First determine whether health-check-url is configured. // First determine whether health-check-url is configured.
// If configured, the service instance health check needs to be executed // If configured, the service instance health check needs to be executed
// first. // first.
// If the health check passes, the heartbeat will be reported. // If the health check passes, the heartbeat will be reported.
// If it does not pass, the heartbeat will not be reported. // If it does not pass, the heartbeat will not be reported.
if (Strings.isNotEmpty(healthCheckEndpoint)) { if (StringUtils.isNotBlank(healthCheckEndpoint)) {
if (!healthCheckEndpoint.startsWith("/")) { if (!healthCheckEndpoint.startsWith("/")) {
healthCheckEndpoint = "/" + healthCheckEndpoint; healthCheckEndpoint = "/" + healthCheckEndpoint;
} }
String healthCheckUrl = String.format("http://%s:%s%s", String healthCheckUrl = String.format("http://%s:%s%s", heartbeatRequest.getHost(),
heartbeatRequest.getHost(), heartbeatRequest.getPort(), heartbeatRequest.getPort(), healthCheckEndpoint);
healthCheckEndpoint);
if (!OkHttpUtil.get(healthCheckUrl, null)) { if (!OkHttpUtil.get(healthCheckUrl, null)) {
log.error( log.error("backend service health check failed. health check endpoint = {}",
"backend service health check failed. health check endpoint = {}",
healthCheckEndpoint); healthCheckEndpoint);
return; return;
} }

@ -43,37 +43,29 @@ import org.springframework.context.annotation.Configuration;
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties @EnableConfigurationProperties
@ConditionalOnPolarisDiscoveryEnabled @ConditionalOnPolarisDiscoveryEnabled
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", @ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
matchIfMissing = true) @AutoConfigureAfter({ AutoServiceRegistrationConfiguration.class, AutoServiceRegistrationAutoConfiguration.class,
@AutoConfigureAfter({ AutoServiceRegistrationConfiguration.class,
AutoServiceRegistrationAutoConfiguration.class,
PolarisDiscoveryAutoConfiguration.class }) PolarisDiscoveryAutoConfiguration.class })
public class PolarisServiceRegistryAutoConfiguration { public class PolarisServiceRegistryAutoConfiguration {
@Bean @Bean
public PolarisServiceRegistry polarisServiceRegistry( public PolarisServiceRegistry polarisServiceRegistry(PolarisDiscoveryProperties polarisDiscoveryProperties,
PolarisDiscoveryProperties polarisDiscoveryProperties, PolarisDiscoveryHandler polarisDiscoveryHandler, MetadataLocalProperties metadataLocalProperties) {
PolarisDiscoveryHandler polarisDiscoveryHandler, return new PolarisServiceRegistry(polarisDiscoveryProperties, polarisDiscoveryHandler, metadataLocalProperties);
MetadataLocalProperties metadataLocalProperties) {
return new PolarisServiceRegistry(polarisDiscoveryProperties,
polarisDiscoveryHandler, metadataLocalProperties);
} }
@Bean @Bean
@ConditionalOnBean(AutoServiceRegistrationProperties.class) @ConditionalOnBean(AutoServiceRegistrationProperties.class)
public PolarisRegistration polarisRegistration( public PolarisRegistration polarisRegistration(PolarisDiscoveryProperties polarisDiscoveryProperties,
PolarisDiscoveryProperties polarisDiscoveryProperties, SDKContext context) { SDKContext context) {
return new PolarisRegistration(polarisDiscoveryProperties, context); return new PolarisRegistration(polarisDiscoveryProperties, context);
} }
@Bean @Bean
@ConditionalOnBean(AutoServiceRegistrationProperties.class) @ConditionalOnBean(AutoServiceRegistrationProperties.class)
public PolarisAutoServiceRegistration polarisAutoServiceRegistration( public PolarisAutoServiceRegistration polarisAutoServiceRegistration(PolarisServiceRegistry registry,
PolarisServiceRegistry registry, AutoServiceRegistrationProperties autoServiceRegistrationProperties, PolarisRegistration registration) {
AutoServiceRegistrationProperties autoServiceRegistrationProperties, return new PolarisAutoServiceRegistration(registry, autoServiceRegistrationProperties, registration);
PolarisRegistration registration) {
return new PolarisAutoServiceRegistration(registry,
autoServiceRegistrationProperties, registration);
} }
} }

@ -1,40 +0,0 @@
/*
* 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.ribbon;
import com.tencent.cloud.polaris.discovery.ConditionalOnPolarisDiscoveryEnabled;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration;
import org.springframework.cloud.netflix.ribbon.RibbonClients;
import org.springframework.context.annotation.Configuration;
/**
* Autoconfiguration of ribbon of Polaris.
*
* @author Haotian Zhang, Andrew Shan, Jie Cheng
*/
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties
@ConditionalOnPolarisDiscoveryEnabled
@AutoConfigureAfter(RibbonAutoConfiguration.class)
@RibbonClients(defaultConfiguration = PolarisRibbonServerListConfiguration.class)
public class PolarisDiscoveryRibbonAutoConfiguration {
}

@ -1,47 +0,0 @@
/*
* 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.ribbon;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.Server;
import com.netflix.loadbalancer.ServerList;
import com.tencent.cloud.polaris.discovery.PolarisDiscoveryHandler;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Configuration of server list.
*
* @author Haotian Zhang, Andrew Shan, Jie Cheng
*/
@Configuration
public class PolarisRibbonServerListConfiguration {
@Bean
@ConditionalOnMissingBean
public ServerList<Server> ribbonServerList(
PolarisDiscoveryHandler polarisDiscoveryHandler,
IClientConfig iClientConfig) {
PolarisServerList serverList = new PolarisServerList(polarisDiscoveryHandler);
serverList.initWithNiwsConfig(iClientConfig);
return serverList;
}
}

@ -1,77 +0,0 @@
/*
* 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.ribbon;
import java.util.ArrayList;
import java.util.List;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractServerList;
import com.netflix.loadbalancer.Server;
import com.tencent.cloud.common.pojo.PolarisServer;
import com.tencent.cloud.polaris.discovery.PolarisDiscoveryHandler;
import com.tencent.polaris.api.pojo.Instance;
import com.tencent.polaris.api.pojo.ServiceInstances;
import com.tencent.polaris.api.rpc.InstancesResponse;
/**
* Server list of Polaris.
*
* @author Haotian Zhang, Andrew Shan, Jie Cheng
*/
public class PolarisServerList extends AbstractServerList<Server> {
private String serviceId;
private PolarisDiscoveryHandler polarisDiscoveryHandler;
public PolarisServerList(PolarisDiscoveryHandler polarisDiscoveryHandler) {
this.polarisDiscoveryHandler = polarisDiscoveryHandler;
}
@Override
public List<Server> getInitialListOfServers() {
return getServers();
}
@Override
public List<Server> getUpdatedListOfServers() {
return getServers();
}
private List<Server> getServers() {
InstancesResponse filteredInstances = polarisDiscoveryHandler
.getFilteredInstances(serviceId);
ServiceInstances serviceInstances = filteredInstances.toServiceInstances();
List<Server> polarisServers = new ArrayList<>();
for (Instance instance : serviceInstances.getInstances()) {
polarisServers.add(new PolarisServer(serviceInstances, instance));
}
return polarisServers;
}
public String getServiceId() {
return serviceId;
}
@Override
public void initWithNiwsConfig(IClientConfig iClientConfig) {
this.serviceId = iClientConfig.getClientName();
}
}

@ -20,7 +20,6 @@ package com.tencent.cloud.polaris.util;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import com.squareup.okhttp.MediaType;
import com.squareup.okhttp.OkHttpClient; import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request; import com.squareup.okhttp.Request;
import com.squareup.okhttp.Response; import com.squareup.okhttp.Response;
@ -39,12 +38,6 @@ public final class OkHttpUtil {
*/ */
public final static Logger logger = LoggerFactory.getLogger(OkHttpUtil.class); public final static Logger logger = LoggerFactory.getLogger(OkHttpUtil.class);
/**
* JSON format.
*/
public static final MediaType MEDIA_TYPE_JSON = MediaType
.parse("application/json; charset=utf-8");
/** /**
* client. * client.
*/ */
@ -69,8 +62,7 @@ public final class OkHttpUtil {
if (response.isSuccessful() && Objects.nonNull(response.body())) { if (response.isSuccessful() && Objects.nonNull(response.body())) {
String result = response.body().string(); String result = response.body().string();
logger.debug("exec get request, url: {} successresponse data: {}", url, logger.debug("exec get request, url: {} successresponse data: {}", url, result);
result);
return true; return true;
} }
} }
@ -85,8 +77,7 @@ public final class OkHttpUtil {
* @param builder builder * @param builder builder
* @param headers headers * @param headers headers
*/ */
private static void buildHeader(Request.Builder builder, private static void buildHeader(Request.Builder builder, Map<String, String> headers) {
Map<String, String> headers) {
if (Objects.nonNull(headers) && headers.size() > 0) { if (Objects.nonNull(headers) && headers.size() > 0) {
headers.forEach((k, v) -> { headers.forEach((k, v) -> {
if (Objects.nonNull(k) && Objects.nonNull(v)) { if (Objects.nonNull(k) && Objects.nonNull(v)) {

@ -1,4 +1,3 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.tencent.cloud.polaris.discovery.PolarisDiscoveryAutoConfiguration,\ com.tencent.cloud.polaris.discovery.PolarisDiscoveryAutoConfiguration,\
com.tencent.cloud.polaris.ribbon.PolarisDiscoveryRibbonAutoConfiguration,\
com.tencent.cloud.polaris.registry.PolarisServiceRegistryAutoConfiguration com.tencent.cloud.polaris.registry.PolarisServiceRegistryAutoConfiguration

@ -47,12 +47,10 @@ public class PolarisDiscoveryAutoConfigurationTest {
private static NamingServer namingServer; private static NamingServer namingServer;
private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(PolarisContextConfiguration.class, .withConfiguration(
PolarisDiscoveryAutoConfiguration.class, AutoConfigurations.of(PolarisContextConfiguration.class, PolarisDiscoveryAutoConfiguration.class,
PolarisDiscoveryClientConfiguration.class, PolarisDiscoveryClientConfiguration.class, PolarisContextConfiguration.class))
PolarisContextConfiguration.class)) .withPropertyValues("spring.application.name=" + SERVICE_PROVIDER).withPropertyValues("server.port=" + PORT)
.withPropertyValues("spring.application.name=" + SERVICE_PROVIDER)
.withPropertyValues("server.port=" + PORT)
.withPropertyValues("spring.cloud.polaris.address=grpc://127.0.0.1:10081"); .withPropertyValues("spring.cloud.polaris.address=grpc://127.0.0.1:10081");
@BeforeClass @BeforeClass

@ -44,10 +44,8 @@ public class PolarisDiscoveryClientConfigurationTest {
private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(PolarisContextConfiguration.class, .withConfiguration(AutoConfigurations.of(PolarisContextConfiguration.class,
PolarisDiscoveryClientConfiguration.class, PolarisDiscoveryClientConfiguration.class, PolarisContextConfiguration.class))
PolarisContextConfiguration.class)) .withPropertyValues("spring.application.name=" + SERVICE_PROVIDER).withPropertyValues("server.port=" + PORT)
.withPropertyValues("spring.application.name=" + SERVICE_PROVIDER)
.withPropertyValues("server.port=" + PORT)
.withPropertyValues("spring.cloud.polaris.address=grpc://127.0.0.1:10081"); .withPropertyValues("spring.cloud.polaris.address=grpc://127.0.0.1:10081");
@BeforeClass @BeforeClass
@ -64,16 +62,13 @@ public class PolarisDiscoveryClientConfigurationTest {
@Test @Test
public void testDefaultInitialization() { public void testDefaultInitialization() {
this.contextRunner.run(context -> assertThat(context) this.contextRunner.run(context -> assertThat(context).hasSingleBean(PolarisDiscoveryClient.class));
.hasSingleBean(PolarisDiscoveryClient.class));
} }
@Test @Test
public void testDiscoveryBlockingDisabled() { public void testDiscoveryBlockingDisabled() {
this.contextRunner this.contextRunner.withPropertyValues("spring.cloud.discovery.blocking.enabled=false")
.withPropertyValues("spring.cloud.discovery.blocking.enabled=false") .run(context -> assertThat(context).doesNotHaveBean(PolarisDiscoveryClient.class));
.run(context -> assertThat(context)
.doesNotHaveBean(PolarisDiscoveryClient.class));
} }
@Configuration @Configuration

@ -65,8 +65,7 @@ public class PolarisDiscoveryClientTest {
@Test @Test
public void testGetServices() { public void testGetServices() {
when(polarisServiceDiscovery.getServices()) when(polarisServiceDiscovery.getServices()).thenReturn(singletonList(SERVICE_PROVIDER));
.thenReturn(singletonList(SERVICE_PROVIDER));
List<String> services = client.getServices(); List<String> services = client.getServices();

@ -52,14 +52,11 @@ public class PolarisServiceDiscoveryTest {
private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(PolarisContextConfiguration.class, .withConfiguration(AutoConfigurations.of(PolarisContextConfiguration.class,
PolarisServiceDiscoveryTest.PolarisPropertiesConfiguration.class, PolarisServiceDiscoveryTest.PolarisPropertiesConfiguration.class,
PolarisDiscoveryClientConfiguration.class, PolarisDiscoveryClientConfiguration.class, PolarisDiscoveryAutoConfiguration.class,
PolarisDiscoveryAutoConfiguration.class,
PolarisContextConfiguration.class)) PolarisContextConfiguration.class))
.withPropertyValues("spring.application.name=" + SERVICE_PROVIDER) .withPropertyValues("spring.application.name=" + SERVICE_PROVIDER).withPropertyValues("server.port=" + PORT)
.withPropertyValues("server.port=" + PORT)
.withPropertyValues("spring.cloud.polaris.address=grpc://127.0.0.1:10081") .withPropertyValues("spring.cloud.polaris.address=grpc://127.0.0.1:10081")
.withPropertyValues( .withPropertyValues("spring.cloud.polaris.discovery.namespace=" + NAMESPACE_TEST)
"spring.cloud.polaris.discovery.namespace=" + NAMESPACE_TEST)
.withPropertyValues("spring.cloud.polaris.discovery.token=xxxxxx"); .withPropertyValues("spring.cloud.polaris.discovery.token=xxxxxx");
@BeforeClass @BeforeClass
@ -72,8 +69,7 @@ public class PolarisServiceDiscoveryTest {
instanceParameter.setIsolated(false); instanceParameter.setIsolated(false);
instanceParameter.setWeight(100); instanceParameter.setWeight(100);
ServiceKey serviceKey = new ServiceKey(NAMESPACE_TEST, SERVICE_PROVIDER); ServiceKey serviceKey = new ServiceKey(NAMESPACE_TEST, SERVICE_PROVIDER);
namingServer.getNamingService().batchAddInstances(serviceKey, PORT, 3, namingServer.getNamingService().batchAddInstances(serviceKey, PORT, 3, instanceParameter);
instanceParameter);
} }
@AfterClass @AfterClass
@ -86,10 +82,8 @@ public class PolarisServiceDiscoveryTest {
@Test @Test
public void testGetInstances() { public void testGetInstances() {
this.contextRunner.run(context -> { this.contextRunner.run(context -> {
PolarisServiceDiscovery polarisServiceDiscovery = context PolarisServiceDiscovery polarisServiceDiscovery = context.getBean(PolarisServiceDiscovery.class);
.getBean(PolarisServiceDiscovery.class); List<ServiceInstance> serviceInstances = polarisServiceDiscovery.getInstances(SERVICE_PROVIDER);
List<ServiceInstance> serviceInstances = polarisServiceDiscovery
.getInstances(SERVICE_PROVIDER);
assertThat(serviceInstances.isEmpty()).isFalse(); assertThat(serviceInstances.isEmpty()).isFalse();
assertThat(serviceInstances).hasSize(3); assertThat(serviceInstances).hasSize(3);
assertThat(serviceInstances.get(0).getPort()).isEqualTo(PORT); assertThat(serviceInstances.get(0).getPort()).isEqualTo(PORT);
@ -101,8 +95,7 @@ public class PolarisServiceDiscoveryTest {
@Test @Test
public void testGetServices() throws PolarisException { public void testGetServices() throws PolarisException {
this.contextRunner.run(context -> { this.contextRunner.run(context -> {
PolarisServiceDiscovery polarisServiceDiscovery = context PolarisServiceDiscovery polarisServiceDiscovery = context.getBean(PolarisServiceDiscovery.class);
.getBean(PolarisServiceDiscovery.class);
List<String> services = polarisServiceDiscovery.getServices(); List<String> services = polarisServiceDiscovery.getServices();
assertThat(services.size()).isEqualTo(1); assertThat(services.size()).isEqualTo(1);
}); });

@ -45,11 +45,9 @@ public class PolarisReactiveDiscoveryClientConfigurationTest {
private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(PolarisContextConfiguration.class, .withConfiguration(AutoConfigurations.of(PolarisContextConfiguration.class,
PolarisReactiveDiscoveryClientConfiguration.class, PolarisReactiveDiscoveryClientConfiguration.class, PolarisDiscoveryClientConfiguration.class,
PolarisDiscoveryClientConfiguration.class,
PolarisContextConfiguration.class)) PolarisContextConfiguration.class))
.withPropertyValues("spring.application.name=" + SERVICE_PROVIDER) .withPropertyValues("spring.application.name=" + SERVICE_PROVIDER).withPropertyValues("server.port=" + PORT)
.withPropertyValues("server.port=" + PORT)
.withPropertyValues("spring.cloud.polaris.address=grpc://127.0.0.1:10081"); .withPropertyValues("spring.cloud.polaris.address=grpc://127.0.0.1:10081");
@BeforeClass @BeforeClass
@ -66,8 +64,7 @@ public class PolarisReactiveDiscoveryClientConfigurationTest {
@Test @Test
public void testDefaultInitialization() { public void testDefaultInitialization() {
this.contextRunner.run(context -> assertThat(context) this.contextRunner.run(context -> assertThat(context).hasSingleBean(PolarisReactiveDiscoveryClient.class));
.hasSingleBean(PolarisReactiveDiscoveryClient.class));
} }
@Configuration @Configuration

@ -57,8 +57,7 @@ public class PolarisReactiveDiscoveryClientTest {
@Test @Test
public void testGetInstances() throws PolarisException { public void testGetInstances() throws PolarisException {
when(serviceDiscovery.getInstances(SERVICE_PROVIDER)) when(serviceDiscovery.getInstances(SERVICE_PROVIDER)).thenReturn(singletonList(serviceInstance));
.thenReturn(singletonList(serviceInstance));
Flux<ServiceInstance> instances = this.client.getInstances(SERVICE_PROVIDER); Flux<ServiceInstance> instances = this.client.getInstances(SERVICE_PROVIDER);
@ -68,14 +67,11 @@ public class PolarisReactiveDiscoveryClientTest {
@Test @Test
public void testGetServices() throws PolarisException { public void testGetServices() throws PolarisException {
when(serviceDiscovery.getServices()) when(serviceDiscovery.getServices()).thenReturn(Arrays.asList(SERVICE_PROVIDER + 1, SERVICE_PROVIDER + 2));
.thenReturn(Arrays.asList(SERVICE_PROVIDER + 1, SERVICE_PROVIDER + 2));
Flux<String> services = this.client.getServices(); Flux<String> services = this.client.getServices();
StepVerifier.create(services) StepVerifier.create(services).expectNext(SERVICE_PROVIDER + 1, SERVICE_PROVIDER + 2).expectComplete().verify();
.expectNext(SERVICE_PROVIDER + 1, SERVICE_PROVIDER + 2).expectComplete()
.verify();
} }
} }

@ -47,10 +47,8 @@ public class PolarisServiceRegistryAutoConfigurationTest {
private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(PolarisContextConfiguration.class, .withConfiguration(AutoConfigurations.of(PolarisContextConfiguration.class,
PolarisServiceRegistryAutoConfiguration.class, PolarisServiceRegistryAutoConfiguration.class, PolarisDiscoveryClientConfiguration.class))
PolarisDiscoveryClientConfiguration.class)) .withPropertyValues("spring.application.name=" + SERVICE_PROVIDER).withPropertyValues("server.port=" + PORT)
.withPropertyValues("spring.application.name=" + SERVICE_PROVIDER)
.withPropertyValues("server.port=" + PORT)
.withPropertyValues("spring.cloud.polaris.address=grpc://127.0.0.1:10081"); .withPropertyValues("spring.cloud.polaris.address=grpc://127.0.0.1:10081");
@BeforeClass @BeforeClass
@ -69,8 +67,7 @@ public class PolarisServiceRegistryAutoConfigurationTest {
public void testDefaultInitialization() { public void testDefaultInitialization() {
this.contextRunner.run(context -> { this.contextRunner.run(context -> {
assertThat(context).hasSingleBean(PolarisDiscoveryAutoConfiguration.class); assertThat(context).hasSingleBean(PolarisDiscoveryAutoConfiguration.class);
assertThat(context) assertThat(context).hasSingleBean(AutoServiceRegistrationAutoConfiguration.class);
.hasSingleBean(AutoServiceRegistrationAutoConfiguration.class);
}); });
} }

@ -50,15 +50,12 @@ public class PolarisServiceRegistryTest {
private static NamingServer namingServer; private static NamingServer namingServer;
private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(PolarisContextConfiguration.class, .withConfiguration(
PolarisPropertiesConfiguration.class, AutoConfigurations.of(PolarisContextConfiguration.class, PolarisPropertiesConfiguration.class,
PolarisDiscoveryClientConfiguration.class, PolarisDiscoveryClientConfiguration.class, PolarisDiscoveryAutoConfiguration.class))
PolarisDiscoveryAutoConfiguration.class)) .withPropertyValues("spring.application.name=" + SERVICE_PROVIDER).withPropertyValues("server.port=" + PORT)
.withPropertyValues("spring.application.name=" + SERVICE_PROVIDER)
.withPropertyValues("server.port=" + PORT)
.withPropertyValues("spring.cloud.polaris.address=grpc://127.0.0.1:10081") .withPropertyValues("spring.cloud.polaris.address=grpc://127.0.0.1:10081")
.withPropertyValues( .withPropertyValues("spring.cloud.polaris.discovery.namespace=" + NAMESPACE_TEST)
"spring.cloud.polaris.discovery.namespace=" + NAMESPACE_TEST)
.withPropertyValues("spring.cloud.polaris.discovery.token=xxxxxx"); .withPropertyValues("spring.cloud.polaris.discovery.token=xxxxxx");
@BeforeClass @BeforeClass
@ -66,8 +63,7 @@ public class PolarisServiceRegistryTest {
namingServer = NamingServer.startNamingServer(10081); namingServer = NamingServer.startNamingServer(10081);
// add service // add service
namingServer.getNamingService() namingServer.getNamingService().addService(new ServiceKey(NAMESPACE_TEST, SERVICE_PROVIDER));
.addService(new ServiceKey(NAMESPACE_TEST, SERVICE_PROVIDER));
} }
@AfterClass @AfterClass
@ -80,8 +76,7 @@ public class PolarisServiceRegistryTest {
@Test @Test
public void testRegister() { public void testRegister() {
this.contextRunner.run(context -> { this.contextRunner.run(context -> {
PolarisServiceRegistry registry = context PolarisServiceRegistry registry = context.getBean(PolarisServiceRegistry.class);
.getBean(PolarisServiceRegistry.class);
PolarisRegistration registration = Mockito.mock(PolarisRegistration.class); PolarisRegistration registration = Mockito.mock(PolarisRegistration.class);
when(registration.getHost()).thenReturn("127.0.0.1"); when(registration.getHost()).thenReturn("127.0.0.1");
when(registration.getPort()).thenReturn(PORT); when(registration.getPort()).thenReturn(PORT);

@ -1,92 +0,0 @@
/*
* 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.ribbon;
import com.netflix.client.config.DefaultClientConfigImpl;
import com.netflix.client.config.IClientConfig;
import com.tencent.cloud.polaris.context.PolarisContextConfiguration;
import com.tencent.cloud.polaris.discovery.PolarisDiscoveryClientConfiguration;
import com.tencent.cloud.polaris.discovery.PolarisDiscoveryHandler;
import org.junit.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
import static com.tencent.polaris.test.common.Consts.NAMESPACE_TEST;
import static com.tencent.polaris.test.common.Consts.PORT;
import static com.tencent.polaris.test.common.Consts.SERVICE_PROVIDER;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Test for {@link PolarisRibbonServerListConfiguration}
*
* @author Haotian Zhang
*/
public class PolarisRibbonServerListConfigurationTest {
private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(PolarisRibbonClientTest.class,
PolarisDiscoveryClientConfiguration.class,
PolarisContextConfiguration.class))
.withPropertyValues("spring.application.name=" + SERVICE_PROVIDER)
.withPropertyValues("server.port=" + PORT)
.withPropertyValues("spring.cloud.polaris.address=grpc://127.0.0.1:10081")
.withPropertyValues(
"spring.cloud.polaris.discovery.namespace=" + NAMESPACE_TEST)
.withPropertyValues("spring.cloud.polaris.discovery.token=xxxxxx");
@Test
public void testProperties() {
this.contextRunner.run(context -> {
PolarisDiscoveryHandler discoveryHandler = context
.getBean(PolarisDiscoveryHandler.class);
PolarisServerList serverList = new PolarisServerList(discoveryHandler);
IClientConfig iClientConfig = context.getBean(IClientConfig.class);
serverList.initWithNiwsConfig(iClientConfig);
assertThat(serverList.getServiceId()).isEqualTo(SERVICE_PROVIDER);
});
}
@Configuration
@EnableAutoConfiguration
@EnableDiscoveryClient
static class PolarisRibbonClientTest {
@Bean
IClientConfig iClientConfig() {
DefaultClientConfigImpl config = new DefaultClientConfigImpl();
config.setClientName(SERVICE_PROVIDER);
return config;
}
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
}
}

@ -1,146 +0,0 @@
/*
* 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.ribbon;
import java.util.List;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.Server;
import com.tencent.cloud.polaris.context.PolarisContextConfiguration;
import com.tencent.cloud.polaris.discovery.PolarisDiscoveryAutoConfiguration;
import com.tencent.cloud.polaris.discovery.PolarisDiscoveryClientConfiguration;
import com.tencent.cloud.polaris.discovery.PolarisDiscoveryHandler;
import com.tencent.polaris.api.pojo.ServiceKey;
import com.tencent.polaris.test.mock.discovery.NamingServer;
import com.tencent.polaris.test.mock.discovery.NamingService;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.annotation.Configuration;
import static com.tencent.polaris.test.common.Consts.NAMESPACE_TEST;
import static com.tencent.polaris.test.common.Consts.PORT;
import static com.tencent.polaris.test.common.Consts.SERVICE_PROVIDER;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
* Test for {@link PolarisServerList}
*
* @author Haotian Zhang
*/
public class PolarisServerListTest {
private static NamingServer namingServer;
private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(PolarisContextConfiguration.class,
PolarisServerListTest.PolarisPropertiesConfiguration.class,
PolarisDiscoveryClientConfiguration.class,
PolarisDiscoveryAutoConfiguration.class,
PolarisContextConfiguration.class))
.withPropertyValues("spring.application.name=" + SERVICE_PROVIDER)
.withPropertyValues("server.port=" + PORT)
.withPropertyValues("spring.cloud.polaris.address=grpc://127.0.0.1:10081")
.withPropertyValues(
"spring.cloud.polaris.discovery.namespace=" + NAMESPACE_TEST)
.withPropertyValues("spring.cloud.polaris.discovery.token=xxxxxx");
@BeforeClass
public static void beforeClass() throws Exception {
namingServer = NamingServer.startNamingServer(10081);
// add service
namingServer.getNamingService()
.addService(new ServiceKey(NAMESPACE_TEST, SERVICE_PROVIDER));
}
@AfterClass
public static void afterClass() throws Exception {
if (null != namingServer) {
namingServer.terminate();
}
}
/**
* Test {@link PolarisServerList#getInitialListOfServers()} with empty server list.
*/
@Test
@SuppressWarnings("unchecked")
public void test1() {
this.contextRunner.run(context -> {
// mock
IClientConfig iClientConfig = mock(IClientConfig.class);
when(iClientConfig.getClientName()).thenReturn(SERVICE_PROVIDER);
PolarisDiscoveryHandler polarisDiscoveryHandler = context
.getBean(PolarisDiscoveryHandler.class);
PolarisServerList serverList = new PolarisServerList(polarisDiscoveryHandler);
serverList.initWithNiwsConfig(iClientConfig);
List<Server> servers = serverList.getInitialListOfServers();
assertThat(servers).isEmpty();
});
}
/**
* Test {@link PolarisServerList#getUpdatedListOfServers()} with server list of size
* 3.
*/
@Test
@SuppressWarnings("unchecked")
public void test2() {
this.contextRunner.run(context -> {
// mock
IClientConfig iClientConfig = mock(IClientConfig.class);
when(iClientConfig.getClientName()).thenReturn(SERVICE_PROVIDER);
PolarisDiscoveryHandler polarisDiscoveryHandler = context
.getBean(PolarisDiscoveryHandler.class);
PolarisServerList serverList = new PolarisServerList(polarisDiscoveryHandler);
serverList.initWithNiwsConfig(iClientConfig);
// add service with 3 instances
NamingService.InstanceParameter instanceParameter = new NamingService.InstanceParameter();
instanceParameter.setHealthy(true);
instanceParameter.setIsolated(false);
instanceParameter.setWeight(100);
ServiceKey serviceKey = new ServiceKey(NAMESPACE_TEST, SERVICE_PROVIDER);
namingServer.getNamingService().batchAddInstances(serviceKey, PORT, 3,
instanceParameter);
List<Server> servers = serverList.getUpdatedListOfServers();
assertThat(servers).hasSize(3);
assertThat(servers.get(0).getPort()).isEqualTo(PORT);
assertThat(servers.get(1).getPort()).isEqualTo(PORT + 1);
assertThat(servers.get(2).getPort()).isEqualTo(PORT + 2);
});
}
@Configuration
@EnableAutoConfiguration
@EnableDiscoveryClient
static class PolarisPropertiesConfiguration {
}
}

@ -58,12 +58,6 @@
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>org.powermock</groupId> <groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId> <artifactId>powermock-module-junit4</artifactId>

@ -41,8 +41,7 @@ import static javax.servlet.DispatcherType.REQUEST;
* @author Haotian Zhang * @author Haotian Zhang
*/ */
@Configuration @Configuration
@ConditionalOnProperty(name = "spring.cloud.polaris.ratelimit.enabled", @ConditionalOnProperty(name = "spring.cloud.polaris.ratelimit.enabled", matchIfMissing = true)
matchIfMissing = true)
public class RateLimitConfiguration { public class RateLimitConfiguration {
@Bean @Bean

@ -48,8 +48,7 @@ import org.springframework.web.server.WebFilterChain;
*/ */
public class QuotaCheckReactiveFilter implements WebFilter, Ordered { public class QuotaCheckReactiveFilter implements WebFilter, Ordered {
private static final Logger LOG = LoggerFactory private static final Logger LOG = LoggerFactory.getLogger(QuotaCheckReactiveFilter.class);
.getLogger(QuotaCheckReactiveFilter.class);
private final LimitAPI limitAPI; private final LimitAPI limitAPI;
@ -74,14 +73,14 @@ public class QuotaCheckReactiveFilter implements WebFilter, Ordered {
} }
try { try {
QuotaResponse quotaResponse = QuotaCheckUtils.getQuota(limitAPI, QuotaResponse quotaResponse = QuotaCheckUtils.getQuota(limitAPI, localNamespace, localService, 1, labels,
localNamespace, localService, 1, labels, null); null);
if (quotaResponse.getCode() == QuotaResultCode.QuotaResultLimited) { if (quotaResponse.getCode() == QuotaResultCode.QuotaResultLimited) {
ServerHttpResponse response = exchange.getResponse(); ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(HttpStatus.TOO_MANY_REQUESTS); response.setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
response.getHeaders().setContentType(MediaType.APPLICATION_JSON); response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
DataBuffer dataBuffer = response.bufferFactory().allocateBuffer().write( DataBuffer dataBuffer = response.bufferFactory().allocateBuffer()
(RateLimitConstant.QUOTA_LIMITED_INFO + quotaResponse.getInfo()) .write((RateLimitConstant.QUOTA_LIMITED_INFO + quotaResponse.getInfo())
.getBytes(StandardCharsets.UTF_8)); .getBytes(StandardCharsets.UTF_8));
return response.writeWith(Mono.just(dataBuffer)); return response.writeWith(Mono.just(dataBuffer));
} }

@ -50,8 +50,7 @@ import static org.springframework.http.HttpStatus.TOO_MANY_REQUESTS;
@Order(RateLimitConstant.FILTER_ORDER) @Order(RateLimitConstant.FILTER_ORDER)
public class QuotaCheckServletFilter extends OncePerRequestFilter { public class QuotaCheckServletFilter extends OncePerRequestFilter {
private static final Logger LOG = LoggerFactory private static final Logger LOG = LoggerFactory.getLogger(QuotaCheckServletFilter.class);
.getLogger(QuotaCheckServletFilter.class);
private final LimitAPI limitAPI; private final LimitAPI limitAPI;
@ -60,8 +59,7 @@ public class QuotaCheckServletFilter extends OncePerRequestFilter {
} }
@Override @Override
protected void doFilterInternal(HttpServletRequest request, protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException { throws ServletException, IOException {
String localNamespace = MetadataContext.LOCAL_NAMESPACE; String localNamespace = MetadataContext.LOCAL_NAMESPACE;
String localService = MetadataContext.LOCAL_SERVICE; String localService = MetadataContext.LOCAL_SERVICE;
@ -73,8 +71,8 @@ public class QuotaCheckServletFilter extends OncePerRequestFilter {
} }
try { try {
QuotaResponse quotaResponse = QuotaCheckUtils.getQuota(limitAPI, QuotaResponse quotaResponse = QuotaCheckUtils.getQuota(limitAPI, localNamespace, localService, 1, labels,
localNamespace, localService, 1, labels, null); null);
if (quotaResponse.getCode() == QuotaResultCode.QuotaResultLimited) { if (quotaResponse.getCode() == QuotaResultCode.QuotaResultLimited) {
response.setStatus(TOO_MANY_REQUESTS.value()); response.setStatus(TOO_MANY_REQUESTS.value());
response.getWriter().write(RateLimitConstant.QUOTA_LIMITED_INFO); response.getWriter().write(RateLimitConstant.QUOTA_LIMITED_INFO);

@ -37,8 +37,8 @@ public final class QuotaCheckUtils {
private QuotaCheckUtils() { private QuotaCheckUtils() {
} }
public static QuotaResponse getQuota(LimitAPI limitAPI, String namespace, public static QuotaResponse getQuota(LimitAPI limitAPI, String namespace, String service, int count,
String service, int count, Map<String, String> labels, String method) { Map<String, String> labels, String method) {
// build quota request // build quota request
QuotaRequest quotaRequest = new QuotaRequest(); QuotaRequest quotaRequest = new QuotaRequest();
quotaRequest.setNamespace(namespace); quotaRequest.setNamespace(namespace);
@ -51,10 +51,8 @@ public final class QuotaCheckUtils {
return limitAPI.getQuota(quotaRequest); return limitAPI.getQuota(quotaRequest);
} }
catch (Throwable throwable) { catch (Throwable throwable) {
LOG.error("fail to invoke getQuota of LimitAPI with QuotaRequest[{}].", LOG.error("fail to invoke getQuota of LimitAPI with QuotaRequest[{}].", quotaRequest, throwable);
quotaRequest, throwable); return new QuotaResponse(new QuotaResult(QuotaResult.Code.QuotaResultOk, 0, "get quota failed"));
return new QuotaResponse(new QuotaResult(QuotaResult.Code.QuotaResultOk, 0,
"get quota failed"));
} }
} }

@ -57,8 +57,7 @@ import static org.mockito.Mockito.when;
@RunWith(SpringRunner.class) @RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = { CalleeControllerTests.Config.class, TestController.class }, classes = { CalleeControllerTests.Config.class, TestController.class },
properties = { "spring.application.name=java_provider_test", properties = { "spring.application.name=java_provider_test", "spring.cloud.polaris.discovery.namespace=Test",
"spring.cloud.polaris.discovery.namespace=Test",
"spring.cloud.polaris.address=grpc://127.0.0.1:10081" }) "spring.cloud.polaris.address=grpc://127.0.0.1:10081" })
public class CalleeControllerTests { public class CalleeControllerTests {
@ -83,8 +82,7 @@ public class CalleeControllerTests {
instanceParameter.setIsolated(false); instanceParameter.setIsolated(false);
instanceParameter.setWeight(100); instanceParameter.setWeight(100);
ServiceKey serviceKey = new ServiceKey(NAMESPACE_TEST, SERVICE_PROVIDER); ServiceKey serviceKey = new ServiceKey(NAMESPACE_TEST, SERVICE_PROVIDER);
namingServer.getNamingService().batchAddInstances(serviceKey, PORT, 3, namingServer.getNamingService().batchAddInstances(serviceKey, PORT, 3, instanceParameter);
instanceParameter);
} }
@AfterClass @AfterClass
@ -111,10 +109,8 @@ public class CalleeControllerTests {
try { try {
if (i > 9) { if (i > 9) {
QuotaResponse quotaResponse = mock(QuotaResponse.class); QuotaResponse quotaResponse = mock(QuotaResponse.class);
when(quotaResponse.getCode()) when(quotaResponse.getCode()).thenReturn(QuotaResultCode.QuotaResultLimited);
.thenReturn(QuotaResultCode.QuotaResultLimited); when(quotaResponse.getInfo()).thenReturn("Testing rate limit after 10 times success.");
when(quotaResponse.getInfo())
.thenReturn("Testing rate limit after 10 times success.");
when(limitAPI.getQuota(any())).thenReturn(quotaResponse); when(limitAPI.getQuota(any())).thenReturn(quotaResponse);
} }
String result = restTemplate.getForObject(url, String.class); String result = restTemplate.getForObject(url, String.class);

@ -21,29 +21,29 @@
</dependency> </dependency>
<!-- Spring Cloud Tencent dependencies end --> <!-- Spring Cloud Tencent dependencies end -->
<!-- Polaris dependencies start -->
<dependency> <dependency>
<groupId>com.tencent.polaris</groupId> <groupId>org.springframework.cloud</groupId>
<artifactId>polaris-router-factory</artifactId> <artifactId>spring-cloud-loadbalancer</artifactId>
</dependency> </dependency>
<!-- Polaris dependencies start -->
<dependency> <dependency>
<groupId>org.springframework.cloud</groupId> <groupId>com.tencent.polaris</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId> <artifactId>polaris-router-factory</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.tencent.polaris</groupId> <groupId>com.tencent.polaris</groupId>
<artifactId>polaris-test-common</artifactId> <artifactId>polaris-test-common</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<!-- Polaris dependencies end --> <!-- Polaris dependencies end -->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId> <artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
</dependencies> </dependencies>
</project> </project>

@ -21,17 +21,10 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import com.netflix.client.config.IClientConfig; import com.tencent.cloud.common.constant.MetadataConstant;
import com.netflix.loadbalancer.DynamicServerListLoadBalancer;
import com.netflix.loadbalancer.IPing;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.PollingServerListUpdater;
import com.netflix.loadbalancer.Server;
import com.netflix.loadbalancer.ServerList;
import com.tencent.cloud.common.constant.MetadataConstant.SystemMetadataKey;
import com.tencent.cloud.common.metadata.MetadataContext; import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.common.metadata.MetadataContextHolder;
import com.tencent.cloud.common.pojo.PolarisServer; import com.tencent.cloud.common.pojo.PolarisServiceInstance;
import com.tencent.polaris.api.pojo.DefaultInstance; import com.tencent.polaris.api.pojo.DefaultInstance;
import com.tencent.polaris.api.pojo.DefaultServiceInstances; import com.tencent.polaris.api.pojo.DefaultServiceInstances;
import com.tencent.polaris.api.pojo.Instance; import com.tencent.polaris.api.pojo.Instance;
@ -42,70 +35,68 @@ import com.tencent.polaris.router.api.core.RouterAPI;
import com.tencent.polaris.router.api.rpc.ProcessRoutersRequest; import com.tencent.polaris.router.api.rpc.ProcessRoutersRequest;
import com.tencent.polaris.router.api.rpc.ProcessRoutersResponse; import com.tencent.polaris.router.api.rpc.ProcessRoutersResponse;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import reactor.core.publisher.Flux;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.Request;
import org.springframework.cloud.loadbalancer.core.DelegatingServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
/** /**
* Routing load balancer of polaris. * Service instance list supplier of Polaris.
* *
* @author Haotian Zhang * @author Haotian Zhang
*/ */
public class PolarisRoutingLoadBalancer extends DynamicServerListLoadBalancer<Server> { public class PolarisRouterServiceInstanceListSupplier extends DelegatingServiceInstanceListSupplier {
private final RouterAPI routerAPI; private final RouterAPI routerAPI;
public PolarisRoutingLoadBalancer(IClientConfig config, IRule rule, IPing ping, public PolarisRouterServiceInstanceListSupplier(ServiceInstanceListSupplier delegate, RouterAPI routerAPI) {
ServerList<Server> serverList, RouterAPI routerAPI) { super(delegate);
super(config, rule, ping, serverList, null, new PollingServerListUpdater());
this.routerAPI = routerAPI; this.routerAPI = routerAPI;
} }
@Override @Override
public List<Server> getReachableServers() { public Flux<List<ServiceInstance>> get() {
List<Server> allServers = super.getAllServers(); return getDelegate().get().map(this::chooseInstances);
}
@Override
public Flux<List<ServiceInstance>> get(Request request) {
return super.get(request);
}
public List<ServiceInstance> chooseInstances(List<ServiceInstance> allServers) {
if (CollectionUtils.isEmpty(allServers)) { if (CollectionUtils.isEmpty(allServers)) {
return allServers; return allServers;
} }
ServiceInstances serviceInstances = null; ServiceInstances serviceInstances = null;
if (allServers.get(0) instanceof PolarisServer) { String serviceName = allServers.get(0).getServiceId();
serviceInstances = ((PolarisServer) allServers.get(0)).getServiceInstances(); if (StringUtils.isBlank(serviceName)) {
throw new IllegalStateException(
"PolarisRoutingLoadBalancer only Server with AppName or ServiceIdForDiscovery attribute");
} }
else { ServiceKey serviceKey = new ServiceKey(MetadataContext.LOCAL_NAMESPACE, serviceName);
String serviceName; List<Instance> instances = new ArrayList<>(8);
// notice the difference between different service registries for (ServiceInstance server : allServers) {
if (StringUtils.isNotBlank(allServers.get(0).getMetaInfo().getServiceIdForDiscovery())) { DefaultInstance instance = new DefaultInstance();
serviceName = allServers.get(0).getMetaInfo().getServiceIdForDiscovery(); instance.setNamespace(MetadataContext.LOCAL_NAMESPACE);
} instance.setService(serviceName);
else { instance.setProtocol(server.getScheme());
serviceName = allServers.get(0).getMetaInfo().getAppName(); instance.setId(server.getInstanceId());
} instance.setHost(server.getHost());
if (StringUtils.isBlank(serviceName)) { instance.setPort(server.getPort());
throw new IllegalStateException( instance.setWeight(100);
"PolarisRoutingLoadBalancer only Server with AppName or ServiceIdForDiscovery attribute"); instances.add(instance);
}
ServiceKey serviceKey = new ServiceKey(MetadataContext.LOCAL_NAMESPACE, serviceName);
List<Instance> instances = new ArrayList<>(8);
for (Server server : allServers) {
DefaultInstance instance = new DefaultInstance();
instance.setNamespace(MetadataContext.LOCAL_NAMESPACE);
instance.setService(serviceName);
instance.setHealthy(server.isAlive());
instance.setProtocol(server.getScheme());
instance.setId(server.getId());
instance.setHost(server.getHost());
instance.setPort(server.getPort());
instance.setZone(server.getZone());
instance.setWeight(100);
instances.add(instance);
}
serviceInstances = new DefaultServiceInstances(serviceKey, instances);
} }
serviceInstances = new DefaultServiceInstances(serviceKey, instances);
ProcessRoutersRequest processRoutersRequest = new ProcessRoutersRequest(); ProcessRoutersRequest processRoutersRequest = new ProcessRoutersRequest();
processRoutersRequest.setDstInstances(serviceInstances); processRoutersRequest.setDstInstances(serviceInstances);
String srcNamespace = MetadataContext.LOCAL_NAMESPACE; String srcNamespace = MetadataContext.LOCAL_NAMESPACE;
String srcService = MetadataContext.LOCAL_SERVICE; String srcService = MetadataContext.LOCAL_SERVICE;
Map<String, String> transitiveCustomMetadata = MetadataContextHolder.get().getAllTransitiveCustomMetadata(); Map<String, String> transitiveCustomMetadata = MetadataContextHolder.get().getAllTransitiveCustomMetadata();
String method = MetadataContextHolder.get().getSystemMetadata(SystemMetadataKey.PEER_PATH); String method = MetadataContextHolder.get().getSystemMetadata(MetadataConstant.SystemMetadataKey.PEER_PATH);
processRoutersRequest.setMethod(method); processRoutersRequest.setMethod(method);
if (StringUtils.isNotBlank(srcNamespace) && StringUtils.isNotBlank(srcService)) { if (StringUtils.isNotBlank(srcNamespace) && StringUtils.isNotBlank(srcService)) {
ServiceInfo serviceInfo = new ServiceInfo(); ServiceInfo serviceInfo = new ServiceInfo();
@ -114,20 +105,13 @@ public class PolarisRoutingLoadBalancer extends DynamicServerListLoadBalancer<Se
serviceInfo.setMetadata(transitiveCustomMetadata); serviceInfo.setMetadata(transitiveCustomMetadata);
processRoutersRequest.setSourceService(serviceInfo); processRoutersRequest.setSourceService(serviceInfo);
} }
ProcessRoutersResponse processRoutersResponse = routerAPI ProcessRoutersResponse processRoutersResponse = routerAPI.processRouters(processRoutersRequest);
.processRouters(processRoutersRequest); ServiceInstances filteredServiceInstances = processRoutersResponse.getServiceInstances();
ServiceInstances filteredServiceInstances = processRoutersResponse List<ServiceInstance> filteredInstances = new ArrayList<>();
.getServiceInstances();
List<Server> filteredInstances = new ArrayList<>();
for (Instance instance : filteredServiceInstances.getInstances()) { for (Instance instance : filteredServiceInstances.getInstances()) {
filteredInstances.add(new PolarisServer(serviceInstances, instance)); filteredInstances.add(new PolarisServiceInstance(instance));
} }
return filteredInstances; return filteredInstances;
} }
@Override
public List<Server> getAllServers() {
return getReachableServers();
}
} }

@ -0,0 +1,115 @@
/*
* 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.router;
import java.util.List;
import java.util.stream.Collectors;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.pojo.PolarisServiceInstance;
import com.tencent.cloud.polaris.router.config.PolarisLoadBalancerProperties;
import com.tencent.polaris.api.pojo.DefaultServiceInstances;
import com.tencent.polaris.api.pojo.Instance;
import com.tencent.polaris.api.pojo.ServiceInstances;
import com.tencent.polaris.api.pojo.ServiceKey;
import com.tencent.polaris.api.rpc.Criteria;
import com.tencent.polaris.router.api.core.RouterAPI;
import com.tencent.polaris.router.api.rpc.ProcessLoadBalanceRequest;
import com.tencent.polaris.router.api.rpc.ProcessLoadBalanceResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.publisher.Mono;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.DefaultResponse;
import org.springframework.cloud.client.loadbalancer.EmptyResponse;
import org.springframework.cloud.client.loadbalancer.Request;
import org.springframework.cloud.client.loadbalancer.Response;
import org.springframework.cloud.loadbalancer.core.NoopServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.core.ReactorServiceInstanceLoadBalancer;
import org.springframework.cloud.loadbalancer.core.RoundRobinLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
/**
* Loadbalancer of Polaris.
*
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
*/
public class PolarisRoutingLoadbalancer extends RoundRobinLoadBalancer implements ReactorServiceInstanceLoadBalancer {
private static final Logger log = LoggerFactory.getLogger(PolarisRoutingLoadbalancer.class);
private final String serviceId;
private final PolarisLoadBalancerProperties loadBalancerProperties;
private final RouterAPI routerAPI;
private ObjectProvider<ServiceInstanceListSupplier> supplierObjectProvider;
public PolarisRoutingLoadbalancer(String serviceId,
ObjectProvider<ServiceInstanceListSupplier> supplierObjectProvider,
PolarisLoadBalancerProperties loadBalancerProperties, RouterAPI routerAPI) {
super(supplierObjectProvider, serviceId);
this.serviceId = serviceId;
this.supplierObjectProvider = supplierObjectProvider;
this.loadBalancerProperties = loadBalancerProperties;
this.routerAPI = routerAPI;
}
private static ServiceInstances convertToPolarisServiceInstances(List<ServiceInstance> serviceInstances) {
ServiceKey serviceKey = new ServiceKey(MetadataContext.LOCAL_NAMESPACE, serviceInstances.get(0).getServiceId());
List<Instance> polarisInstances = serviceInstances.stream()
.map(serviceInstance -> ((PolarisServiceInstance) serviceInstance).getPolarisInstance())
.collect(Collectors.toList());
return new DefaultServiceInstances(serviceKey, polarisInstances);
}
@Override
public Mono<Response<ServiceInstance>> choose(Request request) {
if (!loadBalancerProperties.getLoadbalancerEnabled()) {
return super.choose(request);
}
ServiceInstanceListSupplier supplier = supplierObjectProvider
.getIfAvailable(NoopServiceInstanceListSupplier::new);
return supplier.get().next().map(this::getInstanceResponse);
}
private Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> serviceInstances) {
if (serviceInstances.isEmpty()) {
log.warn("No servers available for service: " + this.serviceId);
return new EmptyResponse();
}
ProcessLoadBalanceRequest request = new ProcessLoadBalanceRequest();
request.setDstInstances(convertToPolarisServiceInstances(serviceInstances));
request.setLbPolicy(loadBalancerProperties.getStrategy());
request.setCriteria(new Criteria());
try {
ProcessLoadBalanceResponse response = routerAPI.processLoadBalance(request);
return new DefaultResponse(new PolarisServiceInstance(response.getTargetInstance()));
}
catch (Exception e) {
log.warn("PolarisRoutingLoadbalancer error", e);
return new EmptyResponse();
}
}
}

@ -26,28 +26,27 @@ import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration; import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClients;
import org.springframework.cloud.netflix.ribbon.RibbonClients; import org.springframework.cloud.loadbalancer.config.LoadBalancerAutoConfiguration;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
/** /**
* Auto-configuration Ribbon for Polaris. * Autoconfiguration of loadbalancer of Polaris.
* *
* @author Haotian Zhang * @author Haotian Zhang, Andrew Shan, Jie Cheng
*/ */
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties @EnableConfigurationProperties
@ConditionalOnProperty(value = "spring.cloud.polaris.loadbalancer.enabled", @ConditionalOnProperty(value = "spring.cloud.polaris.loadbalancer.enabled", matchIfMissing = true)
matchIfMissing = true) @AutoConfigureAfter(LoadBalancerAutoConfiguration.class)
@AutoConfigureAfter(RibbonAutoConfiguration.class) @LoadBalancerClients(defaultConfiguration = PolarisLoadBalancerClientConfiguration.class)
@RibbonClients(defaultConfiguration = PolarisRibbonClientConfiguration.class) public class PolarisLoadBalancerAutoConfiguration {
public class PolarisRibbonAutoConfiguration {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public PolarisRibbonProperties polarisRibbonProperties() { public PolarisLoadBalancerProperties polarisLoadBalancerProperties() {
return new PolarisRibbonProperties(); return new PolarisLoadBalancerProperties();
} }
@Bean(name = "polarisRoute") @Bean(name = "polarisRoute")

@ -0,0 +1,102 @@
/*
* 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.router.config;
import com.tencent.cloud.polaris.router.PolarisRouterServiceInstanceListSupplier;
import com.tencent.cloud.polaris.router.PolarisRoutingLoadbalancer;
import com.tencent.polaris.router.api.core.RouterAPI;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.client.ConditionalOnBlockingDiscoveryEnabled;
import org.springframework.cloud.client.ConditionalOnDiscoveryEnabled;
import org.springframework.cloud.client.ConditionalOnReactiveDiscoveryEnabled;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.discovery.ReactiveDiscoveryClient;
import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.Environment;
/**
* Configuration of loadbalancer client.
*
* @author <a href="mailto:liaochuntao@live.com">liaochuntao</a>
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnDiscoveryEnabled
public class PolarisLoadBalancerClientConfiguration {
/**
* Order of reactive discovery service instance supplier.
*/
private static final int REACTIVE_SERVICE_INSTANCE_SUPPLIER_ORDER = 193827465;
@Bean
@ConditionalOnMissingBean
public ReactorLoadBalancer<ServiceInstance> polarisLoadBalancer(Environment environment,
LoadBalancerClientFactory loadBalancerClientFactory, PolarisLoadBalancerProperties loadBalancerProperties,
RouterAPI routerAPI) {
String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
return new PolarisRoutingLoadbalancer(name,
loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class),
loadBalancerProperties, routerAPI);
}
@Configuration
@ConditionalOnReactiveDiscoveryEnabled
@Order(REACTIVE_SERVICE_INSTANCE_SUPPLIER_ORDER)
static class PolarisReactiveSupportConfiguration {
@Bean
@ConditionalOnBean(ReactiveDiscoveryClient.class)
@ConditionalOnMissingBean
@ConditionalOnProperty(value = "spring.cloud.loadbalancer.configurations", havingValue = "polaris")
public ServiceInstanceListSupplier polarisRouterDiscoveryClientServiceInstanceListSupplier(RouterAPI routerAPI,
ConfigurableApplicationContext context) {
return new PolarisRouterServiceInstanceListSupplier(
ServiceInstanceListSupplier.builder().withDiscoveryClient().build(context), routerAPI);
}
}
@Configuration
@ConditionalOnBlockingDiscoveryEnabled
@Order(REACTIVE_SERVICE_INSTANCE_SUPPLIER_ORDER + 1)
static class PolarisBlockingSupportConfiguration {
@Bean
@ConditionalOnBean(DiscoveryClient.class)
@ConditionalOnMissingBean
@ConditionalOnProperty(value = "spring.cloud.loadbalancer.configurations", havingValue = "polaris")
public ServiceInstanceListSupplier polarisRouterDiscoveryClientServiceInstanceListSupplier(RouterAPI routerAPI,
ConfigurableApplicationContext context) {
return new PolarisRouterServiceInstanceListSupplier(
ServiceInstanceListSupplier.builder().withBlockingDiscoveryClient().build(context), routerAPI);
}
}
}

@ -21,12 +21,12 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
/** /**
* Properties of Ribbon. * Properties of loadbalancer.
* *
* @author Haotian Zhang * @author Haotian Zhang
*/ */
@ConfigurationProperties("spring.cloud.polaris.ribbon") @ConfigurationProperties("spring.cloud.polaris.ribbon")
public class PolarisRibbonProperties { public class PolarisLoadBalancerProperties {
/** /**
* If load-balance enabled. * If load-balance enabled.
@ -58,8 +58,8 @@ public class PolarisRibbonProperties {
@Override @Override
public String toString() { public String toString() {
return "PolarisRibbonProperties{" + "loadbalancerEnabled=" + loadbalancerEnabled return "PolarisRibbonProperties{" + "loadbalancerEnabled=" + loadbalancerEnabled + ", strategy='" + strategy
+ ", strategy='" + strategy + '\'' + '}'; + '\'' + '}';
} }
} }

@ -1,63 +0,0 @@
/*
* 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.router.config;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.IPing;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.Server;
import com.netflix.loadbalancer.ServerList;
import com.tencent.cloud.polaris.router.PolarisRoutingLoadBalancer;
import com.tencent.cloud.polaris.router.rule.PolarisLoadBalanceRule;
import com.tencent.cloud.polaris.router.rule.PolarisWeightedRandomRule;
import com.tencent.polaris.router.api.core.RouterAPI;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Configuration of ribbon client of Polaris.
*
* @author Haotian Zhang
*/
@Configuration
public class PolarisRibbonClientConfiguration {
@Bean
@ConditionalOnMissingBean
public IRule polarisRibbonRule(PolarisRibbonProperties polarisRibbonProperties) {
switch (PolarisLoadBalanceRule
.fromStrategy(polarisRibbonProperties.getStrategy())) {
case WEIGHTED_RANDOM_RULE:
default:
return new PolarisWeightedRandomRule();
}
}
@Bean
@ConditionalOnMissingBean
public ILoadBalancer polarisRoutingLoadBalancer(IClientConfig iClientConfig,
IRule iRule, IPing iPing, ServerList<Server> serverList,
RouterAPI polarisRouter) {
return new PolarisRoutingLoadBalancer(iClientConfig, iRule, iPing, serverList,
polarisRouter);
}
}

@ -1,52 +0,0 @@
/*
* 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.router.rule;
import java.util.Arrays;
/**
* Load balance rule.
*
* @author Haotian Zhang
*/
public enum PolarisLoadBalanceRule {
/**
* Weighted random load balance rule.
*/
WEIGHTED_RANDOM_RULE("weighted_random");
/**
* Load balance strategy.
*/
final String policy;
PolarisLoadBalanceRule(String strategy) {
this.policy = strategy;
}
public static PolarisLoadBalanceRule fromStrategy(String strategy) {
return Arrays.stream(values()).filter(t -> t.getPolicy().equals(strategy))
.findAny().orElse(WEIGHTED_RANDOM_RULE);
}
public String getPolicy() {
return policy;
}
}

@ -1,73 +0,0 @@
/*
* 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.router.rule;
import java.util.List;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.Server;
import com.tencent.cloud.common.pojo.PolarisServer;
import com.tencent.polaris.api.config.consumer.LoadBalanceConfig;
import com.tencent.polaris.api.pojo.Instance;
import com.tencent.polaris.router.api.core.RouterAPI;
import com.tencent.polaris.router.api.rpc.ProcessLoadBalanceRequest;
import com.tencent.polaris.router.api.rpc.ProcessLoadBalanceResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
/**
* Weighted random load balance strategy.
*
* @author Haotian Zhang
*/
public class PolarisWeightedRandomRule extends AbstractLoadBalancerRule {
private static final String POLICY = LoadBalanceConfig.LOAD_BALANCE_WEIGHTED_RANDOM;
@Autowired
private RouterAPI polarisRouter;
@Override
public void initWithNiwsConfig(IClientConfig clientConfig) {
}
@Override
public Server choose(Object key) {
List<Server> allServers = getLoadBalancer().getReachableServers();
if (CollectionUtils.isEmpty(allServers)) {
return null;
}
Server server = allServers.get(0);
if (!(server instanceof PolarisServer)) {
throw new IllegalStateException(
"PolarisDiscoveryRule only support PolarisServer instances");
}
PolarisServer polarisServer = (PolarisServer) server;
ProcessLoadBalanceRequest request = new ProcessLoadBalanceRequest();
request.setDstInstances(polarisServer.getServiceInstances());
request.setLbPolicy(POLICY);
ProcessLoadBalanceResponse processLoadBalanceResponse = polarisRouter
.processLoadBalance(request);
Instance targetInstance = processLoadBalanceResponse.getTargetInstance();
return new PolarisServer(polarisServer.getServiceInstances(), targetInstance);
}
}

@ -1,2 +1,2 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.tencent.cloud.polaris.router.config.PolarisRibbonAutoConfiguration com.tencent.cloud.polaris.router.config.PolarisLoadBalancerAutoConfiguration

@ -1,62 +0,0 @@
/*
* 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.router.config;
import com.tencent.cloud.polaris.context.PolarisContextConfiguration;
import com.tencent.polaris.router.api.core.RouterAPI;
import org.junit.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Configuration;
import static com.tencent.polaris.test.common.Consts.PORT;
import static com.tencent.polaris.test.common.Consts.SERVICE_PROVIDER;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Test for {@link PolarisRibbonAutoConfiguration}
*
* @author Haotian Zhang
*/
public class PolarisRibbonAutoConfigurationTest {
private ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(PolarisRibbonTest.class,
PolarisRibbonAutoConfiguration.class,
PolarisContextConfiguration.class))
.withPropertyValues("spring.application.name=" + SERVICE_PROVIDER)
.withPropertyValues("server.port=" + PORT)
.withPropertyValues("spring.cloud.polaris.address=grpc://127.0.0.1:10081");
@Test
public void testDefaultInitialization() {
this.contextRunner.run(context -> {
assertThat(context).hasSingleBean(RouterAPI.class);
assertThat(context).hasSingleBean(PolarisRibbonProperties.class);
});
}
@Configuration
@EnableAutoConfiguration
static class PolarisRibbonTest {
}
}

@ -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.router.config;
import com.tencent.cloud.polaris.context.PolarisContextConfiguration;
import com.tencent.cloud.polaris.router.PolarisRouterServiceInstanceListSupplier;
import com.tencent.polaris.router.api.core.RouterAPI;
import org.junit.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Configuration;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Test for {@link PolarisLoadBalancerAutoConfiguration}
*
* @author Haotian Zhang
*/
public class PolarisRouterAutoConfigurationTest {
private final ApplicationContextRunner blockingContextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(PolarisLoadBalancerTest.class, PolarisContextConfiguration.class,
PolarisLoadBalancerAutoConfiguration.class,
PolarisLoadBalancerClientConfiguration.PolarisBlockingSupportConfiguration.class))
.withPropertyValues("spring.cloud.loadbalancer.configurations=polaris");
private final ApplicationContextRunner noPolarisContextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(PolarisLoadBalancerTest.class, PolarisContextConfiguration.class,
PolarisLoadBalancerAutoConfiguration.class,
PolarisLoadBalancerClientConfiguration.PolarisBlockingSupportConfiguration.class));
/**
* Test for BlockingDiscovery.
*/
@Test
public void test1() {
this.blockingContextRunner.run(context -> {
assertThat(context).hasSingleBean(RouterAPI.class);
assertThat(context).hasSingleBean(PolarisLoadBalancerProperties.class);
assertThat(context)
.doesNotHaveBean(PolarisLoadBalancerClientConfiguration.PolarisReactiveSupportConfiguration.class);
assertThat(context)
.hasSingleBean(PolarisLoadBalancerClientConfiguration.PolarisBlockingSupportConfiguration.class);
assertThat(context).doesNotHaveBean(PolarisRouterServiceInstanceListSupplier.class);
});
}
/**
* Test for no Polaris.
*/
@Test
public void test2() {
this.noPolarisContextRunner.run(context -> {
assertThat(context).hasSingleBean(RouterAPI.class);
assertThat(context).hasSingleBean(PolarisLoadBalancerProperties.class);
assertThat(context)
.doesNotHaveBean(PolarisLoadBalancerClientConfiguration.PolarisReactiveSupportConfiguration.class);
assertThat(context)
.hasSingleBean(PolarisLoadBalancerClientConfiguration.PolarisBlockingSupportConfiguration.class);
assertThat(context).doesNotHaveBean(PolarisRouterServiceInstanceListSupplier.class);
});
}
@Configuration
@EnableAutoConfiguration
static class PolarisLoadBalancerTest {
}
}

@ -66,8 +66,8 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.springframework.cloud</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId> <artifactId>spring-boot-starter-web</artifactId>
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>

@ -61,8 +61,7 @@ public final class MetadataConstant {
/** /**
* Order of MetadataFirstFeignInterceptor. * Order of MetadataFirstFeignInterceptor.
*/ */
public static int METADATA_FIRST_FEIGN_INTERCEPTOR_ORDER = Ordered.HIGHEST_PRECEDENCE public static int METADATA_FIRST_FEIGN_INTERCEPTOR_ORDER = Ordered.HIGHEST_PRECEDENCE + 1;
+ 1;
/** /**
* Order of Metadata2HeaderInterceptor. * Order of Metadata2HeaderInterceptor.

@ -93,8 +93,7 @@ public class MetadataContext {
@Override @Override
public String toString() { public String toString() {
return "MetadataContext{" + "transitiveCustomMetadata=" return "MetadataContext{" + "transitiveCustomMetadata=" + JacksonUtils.serialize2Json(transitiveCustomMetadata)
+ JacksonUtils.serialize2Json(transitiveCustomMetadata)
+ ", systemMetadata=" + JacksonUtils.serialize2Json(systemMetadata) + '}'; + ", systemMetadata=" + JacksonUtils.serialize2Json(systemMetadata) + '}';
} }

@ -49,13 +49,12 @@ public final class MetadataContextHolder {
if (null == METADATA_CONTEXT.get()) { if (null == METADATA_CONTEXT.get()) {
MetadataContext metadataContext = new MetadataContext(); MetadataContext metadataContext = new MetadataContext();
if (metadataLocalProperties == null) { if (metadataLocalProperties == null) {
metadataLocalProperties = (MetadataLocalProperties) ApplicationContextAwareUtils metadataLocalProperties = (MetadataLocalProperties) ApplicationContextAwareUtils.getApplicationContext()
.getApplicationContext().getBean("metadataLocalProperties"); .getBean("metadataLocalProperties");
} }
// init custom metadata and load local metadata // init custom metadata and load local metadata
Map<String, String> transitiveMetadataMap = getTransitiveMetadataMap( Map<String, String> transitiveMetadataMap = getTransitiveMetadataMap(metadataLocalProperties.getContent(),
metadataLocalProperties.getContent(),
metadataLocalProperties.getTransitive()); metadataLocalProperties.getTransitive());
metadataContext.putAllTransitiveCustomMetadata(transitiveMetadataMap); metadataContext.putAllTransitiveCustomMetadata(transitiveMetadataMap);
@ -70,8 +69,8 @@ public final class MetadataContextHolder {
* @param transitiveMetadataKeyList transitive metadata name list * @param transitiveMetadataKeyList transitive metadata name list
* @return result * @return result
*/ */
private static Map<String, String> getTransitiveMetadataMap( private static Map<String, String> getTransitiveMetadataMap(Map<String, String> source,
Map<String, String> source, List<String> transitiveMetadataKeyList) { List<String> transitiveMetadataKeyList) {
Map<String, String> result = new HashMap<>(); Map<String, String> result = new HashMap<>();
for (String key : transitiveMetadataKeyList) { for (String key : transitiveMetadataKeyList) {
if (source.containsKey(key)) { if (source.containsKey(key)) {
@ -94,8 +93,7 @@ public final class MetadataContextHolder {
* @param customMetadataMap custom metadata collection * @param customMetadataMap custom metadata collection
* @param systemMetadataMap system metadata collection * @param systemMetadataMap system metadata collection
*/ */
public static void init(Map<String, String> customMetadataMap, public static void init(Map<String, String> customMetadataMap, Map<String, String> systemMetadataMap) {
Map<String, String> systemMetadataMap) {
// Init ThreadLocal. // Init ThreadLocal.
MetadataContextHolder.remove(); MetadataContextHolder.remove();
MetadataContext metadataContext = MetadataContextHolder.get(); MetadataContext metadataContext = MetadataContextHolder.get();

@ -17,10 +17,8 @@
package com.tencent.cloud.common.metadata.config; package com.tencent.cloud.common.metadata.config;
import com.netflix.zuul.ZuulFilter;
import com.tencent.cloud.common.constant.MetadataConstant; import com.tencent.cloud.common.constant.MetadataConstant;
import com.tencent.cloud.common.metadata.filter.gateway.MetadataFirstScgFilter; import com.tencent.cloud.common.metadata.filter.gateway.MetadataFirstScgFilter;
import com.tencent.cloud.common.metadata.filter.gateway.MetadataFirstZuulFilter;
import com.tencent.cloud.common.metadata.filter.web.MetadataReactiveFilter; import com.tencent.cloud.common.metadata.filter.web.MetadataReactiveFilter;
import com.tencent.cloud.common.metadata.filter.web.MetadataServletFilter; import com.tencent.cloud.common.metadata.filter.web.MetadataServletFilter;
import com.tencent.cloud.common.metadata.interceptor.feign.MetadataFirstFeignInterceptor; import com.tencent.cloud.common.metadata.interceptor.feign.MetadataFirstFeignInterceptor;
@ -67,10 +65,8 @@ public class MetadataAutoConfiguration {
MetadataServletFilter metadataServletFilter) { MetadataServletFilter metadataServletFilter) {
FilterRegistrationBean<MetadataServletFilter> filterRegistrationBean = new FilterRegistrationBean<>( FilterRegistrationBean<MetadataServletFilter> filterRegistrationBean = new FilterRegistrationBean<>(
metadataServletFilter); metadataServletFilter);
filterRegistrationBean.setDispatcherTypes(ASYNC, ERROR, FORWARD, INCLUDE, filterRegistrationBean.setDispatcherTypes(ASYNC, ERROR, FORWARD, INCLUDE, REQUEST);
REQUEST); filterRegistrationBean.setOrder(MetadataConstant.OrderConstant.WEB_FILTER_ORDER);
filterRegistrationBean
.setOrder(MetadataConstant.OrderConstant.WEB_FILTER_ORDER);
return filterRegistrationBean; return filterRegistrationBean;
} }
@ -109,20 +105,6 @@ public class MetadataAutoConfiguration {
} }
/**
* Create when gateway application is Zuul.
*/
@Configuration
@ConditionalOnClass(name = "com.netflix.zuul.http.ZuulServlet")
static class MetadataZuulFilterConfig {
@Bean
public ZuulFilter metadataFirstZuulFilter() {
return new MetadataFirstZuulFilter();
}
}
/** /**
* Create when gateway application is SCG. * Create when gateway application is SCG.
*/ */

@ -55,23 +55,19 @@ public class MetadataFirstScgFilter implements GlobalFilter, Ordered {
Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR); Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);
// get metadata of current thread // get metadata of current thread
MetadataContext metadataContext = exchange MetadataContext metadataContext = exchange.getAttribute(MetadataConstant.HeaderName.METADATA_CONTEXT);
.getAttribute(MetadataConstant.HeaderName.METADATA_CONTEXT);
if (metadataContext == null) { if (metadataContext == null) {
metadataContext = MetadataContextHolder.get(); metadataContext = MetadataContextHolder.get();
} }
// TODO The peer namespace is temporarily the same as the local namespace // TODO The peer namespace is temporarily the same as the local namespace
metadataContext.putSystemMetadata( metadataContext.putSystemMetadata(MetadataConstant.SystemMetadataKey.PEER_NAMESPACE,
MetadataConstant.SystemMetadataKey.PEER_NAMESPACE,
MetadataContext.LOCAL_NAMESPACE); MetadataContext.LOCAL_NAMESPACE);
metadataContext.putSystemMetadata(MetadataConstant.SystemMetadataKey.PEER_SERVICE, metadataContext.putSystemMetadata(MetadataConstant.SystemMetadataKey.PEER_SERVICE, route.getId());
route.getId());
metadataContext.putSystemMetadata(MetadataConstant.SystemMetadataKey.PEER_PATH, metadataContext.putSystemMetadata(MetadataConstant.SystemMetadataKey.PEER_PATH,
exchange.getRequest().getURI().getPath()); exchange.getRequest().getURI().getPath());
exchange.getAttributes().put(MetadataConstant.HeaderName.METADATA_CONTEXT, exchange.getAttributes().put(MetadataConstant.HeaderName.METADATA_CONTEXT, metadataContext);
metadataContext);
return chain.filter(exchange); return chain.filter(exchange);
} }

@ -1,70 +0,0 @@
/*
* 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.common.metadata.filter.gateway;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.tencent.cloud.common.constant.MetadataConstant;
import com.tencent.cloud.common.metadata.MetadataContext;
import com.tencent.cloud.common.metadata.MetadataContextHolder;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_DECORATION_FILTER_ORDER;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.REQUEST_URI_KEY;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.SERVICE_ID_KEY;
/**
* Zuul output first filter used for setting peer info in context.
*
* @author Haotian Zhang
*/
public class MetadataFirstZuulFilter extends ZuulFilter {
@Override
public String filterType() {
return PRE_TYPE;
}
@Override
public int filterOrder() {
return PRE_DECORATION_FILTER_ORDER + 1;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() {
// get request context
RequestContext requestContext = RequestContext.getCurrentContext();
// TODO The peer namespace is temporarily the same as the local namespace
MetadataContextHolder.get().putSystemMetadata(
MetadataConstant.SystemMetadataKey.PEER_NAMESPACE,
MetadataContext.LOCAL_NAMESPACE);
MetadataContextHolder.get().putSystemMetadata(
MetadataConstant.SystemMetadataKey.PEER_SERVICE,
(String) requestContext.get(SERVICE_ID_KEY));
MetadataContextHolder.get().putSystemMetadata(
MetadataConstant.SystemMetadataKey.PEER_PATH,
(String) requestContext.get(REQUEST_URI_KEY));
return null;
}
}

@ -44,8 +44,7 @@ import org.springframework.web.server.WebFilterChain;
*/ */
public class MetadataReactiveFilter implements WebFilter, Ordered { public class MetadataReactiveFilter implements WebFilter, Ordered {
private static final Logger LOG = LoggerFactory private static final Logger LOG = LoggerFactory.getLogger(MetadataReactiveFilter.class);
.getLogger(MetadataReactiveFilter.class);
@Override @Override
public int getOrder() { public int getOrder() {
@ -53,13 +52,11 @@ public class MetadataReactiveFilter implements WebFilter, Ordered {
} }
@Override @Override
public Mono<Void> filter(ServerWebExchange serverWebExchange, public Mono<Void> filter(ServerWebExchange serverWebExchange, WebFilterChain webFilterChain) {
WebFilterChain webFilterChain) {
// Get metadata string from http header. // Get metadata string from http header.
ServerHttpRequest serverHttpRequest = serverWebExchange.getRequest(); ServerHttpRequest serverHttpRequest = serverWebExchange.getRequest();
HttpHeaders httpHeaders = serverHttpRequest.getHeaders(); HttpHeaders httpHeaders = serverHttpRequest.getHeaders();
String customMetadataStr = httpHeaders String customMetadataStr = httpHeaders.getFirst(MetadataConstant.HeaderName.CUSTOM_METADATA);
.getFirst(MetadataConstant.HeaderName.CUSTOM_METADATA);
try { try {
if (StringUtils.hasText(customMetadataStr)) { if (StringUtils.hasText(customMetadataStr)) {
customMetadataStr = URLDecoder.decode(customMetadataStr, "UTF-8"); customMetadataStr = URLDecoder.decode(customMetadataStr, "UTF-8");
@ -71,18 +68,15 @@ public class MetadataReactiveFilter implements WebFilter, Ordered {
LOG.debug("Get upstream metadata string: {}", customMetadataStr); LOG.debug("Get upstream metadata string: {}", customMetadataStr);
// create custom metadata. // create custom metadata.
Map<String, String> upstreamCustomMetadataMap = JacksonUtils Map<String, String> upstreamCustomMetadataMap = JacksonUtils.deserialize2Map(customMetadataStr);
.deserialize2Map(customMetadataStr);
MetadataContextHolder.init(upstreamCustomMetadataMap, null); MetadataContextHolder.init(upstreamCustomMetadataMap, null);
// Save to ServerWebExchange. // Save to ServerWebExchange.
serverWebExchange.getAttributes().put( serverWebExchange.getAttributes().put(MetadataConstant.HeaderName.METADATA_CONTEXT,
MetadataConstant.HeaderName.METADATA_CONTEXT,
MetadataContextHolder.get()); MetadataContextHolder.get());
return webFilterChain.filter(serverWebExchange) return webFilterChain.filter(serverWebExchange)
.doOnError(throwable -> LOG.error("handle metadata[{}] error.", .doOnError(throwable -> LOG.error("handle metadata[{}] error.", MetadataContextHolder.get(), throwable))
MetadataContextHolder.get(), throwable))
.doFinally((type) -> MetadataContextHolder.remove()); .doFinally((type) -> MetadataContextHolder.remove());
} }

@ -46,16 +46,13 @@ import org.springframework.web.filter.OncePerRequestFilter;
@Order(MetadataConstant.OrderConstant.WEB_FILTER_ORDER) @Order(MetadataConstant.OrderConstant.WEB_FILTER_ORDER)
public class MetadataServletFilter extends OncePerRequestFilter { public class MetadataServletFilter extends OncePerRequestFilter {
private static final Logger LOG = LoggerFactory private static final Logger LOG = LoggerFactory.getLogger(MetadataServletFilter.class);
.getLogger(MetadataServletFilter.class);
@Override @Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
HttpServletResponse httpServletResponse, FilterChain filterChain) FilterChain filterChain) throws ServletException, IOException {
throws ServletException, IOException {
// Get custom metadata string from http header. // Get custom metadata string from http header.
String customMetadataStr = httpServletRequest String customMetadataStr = httpServletRequest.getHeader(MetadataConstant.HeaderName.CUSTOM_METADATA);
.getHeader(MetadataConstant.HeaderName.CUSTOM_METADATA);
try { try {
if (StringUtils.hasText(customMetadataStr)) { if (StringUtils.hasText(customMetadataStr)) {
customMetadataStr = URLDecoder.decode(customMetadataStr, "UTF-8"); customMetadataStr = URLDecoder.decode(customMetadataStr, "UTF-8");
@ -67,8 +64,7 @@ public class MetadataServletFilter extends OncePerRequestFilter {
LOG.debug("Get upstream metadata string: {}", customMetadataStr); LOG.debug("Get upstream metadata string: {}", customMetadataStr);
// create custom metadata. // create custom metadata.
Map<String, String> upstreamCustomMetadataMap = JacksonUtils Map<String, String> upstreamCustomMetadataMap = JacksonUtils.deserialize2Map(customMetadataStr);
.deserialize2Map(customMetadataStr);
try { try {
MetadataContextHolder.init(upstreamCustomMetadataMap, null); MetadataContextHolder.init(upstreamCustomMetadataMap, null);

@ -43,13 +43,11 @@ public class MetadataFirstFeignInterceptor implements RequestInterceptor, Ordere
MetadataContext metadataContext = MetadataContextHolder.get(); MetadataContext metadataContext = MetadataContextHolder.get();
// TODO The peer namespace is temporarily the same as the local namespace // TODO The peer namespace is temporarily the same as the local namespace
metadataContext.putSystemMetadata( metadataContext.putSystemMetadata(MetadataConstant.SystemMetadataKey.PEER_NAMESPACE,
MetadataConstant.SystemMetadataKey.PEER_NAMESPACE,
MetadataContext.LOCAL_NAMESPACE); MetadataContext.LOCAL_NAMESPACE);
metadataContext.putSystemMetadata(MetadataConstant.SystemMetadataKey.PEER_SERVICE, metadataContext.putSystemMetadata(MetadataConstant.SystemMetadataKey.PEER_SERVICE,
requestTemplate.feignTarget().name()); requestTemplate.feignTarget().name());
metadataContext.putSystemMetadata(MetadataConstant.SystemMetadataKey.PEER_PATH, metadataContext.putSystemMetadata(MetadataConstant.SystemMetadataKey.PEER_PATH, requestTemplate.path());
requestTemplate.path());
} }
} }

@ -1,111 +0,0 @@
/*
* 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.common.pojo;
import java.util.Map;
import java.util.Objects;
import com.netflix.loadbalancer.Server;
import com.tencent.polaris.api.pojo.Instance;
import com.tencent.polaris.api.pojo.ServiceInstances;
import org.apache.commons.lang.StringUtils;
/**
* Polaris' implementation of {@link Server}.
*
* @author Haotian Zhang
*/
public class PolarisServer extends Server {
private final ServiceInstances serviceInstances;
private final Instance instance;
private final MetaInfo metaInfo;
public PolarisServer(ServiceInstances serviceInstances, Instance instance) {
super(instance.getHost(), instance.getPort());
if (StringUtils.equalsIgnoreCase(instance.getProtocol(), "https")) {
setSchemea("https");
}
else {
setSchemea("http");
}
this.serviceInstances = serviceInstances;
this.instance = instance;
this.metaInfo = new MetaInfo() {
@Override
public String getAppName() {
return instance.getService();
}
@Override
public String getServerGroup() {
return null;
}
@Override
public String getServiceIdForDiscovery() {
return instance.getService();
}
@Override
public String getInstanceId() {
return instance.getId();
}
};
}
public Instance getInstance() {
return instance;
}
@Override
public MetaInfo getMetaInfo() {
return metaInfo;
}
public Map<String, String> getMetadata() {
return instance.getMetadata();
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
if (!super.equals(o)) {
return false;
}
PolarisServer that = (PolarisServer) o;
return Objects.equals(instance, that.instance);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), instance);
}
public ServiceInstances getServiceInstances() {
return serviceInstances;
}
}

@ -50,6 +50,10 @@ public class PolarisServiceInstance implements ServiceInstance {
} }
} }
public Instance getPolarisInstance() {
return instance;
}
@Override @Override
public String getInstanceId() { public String getInstanceId() {
return ServiceInstance.super.getInstanceId(); return ServiceInstance.super.getInstanceId();

@ -40,8 +40,7 @@ public class ApplicationContextAwareUtils implements ApplicationContextAware {
return applicationContext; return applicationContext;
} }
public void setApplicationContext(ApplicationContext applicationContext) public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
throws BeansException {
ApplicationContextAwareUtils.applicationContext = applicationContext; ApplicationContextAwareUtils.applicationContext = applicationContext;
} }

@ -74,9 +74,7 @@ public final class JacksonUtils {
return new HashMap<>(); return new HashMap<>();
} }
catch (JsonProcessingException e) { catch (JsonProcessingException e) {
LOG.error( LOG.error("Json to map failed. check if the format of the json string[{}] is correct.", jsonStr, e);
"Json to map failed. check if the format of the json string[{}] is correct.",
jsonStr, e);
throw new RuntimeException("Json to map failed.", e); throw new RuntimeException("Json to map failed.", e);
} }
} }

@ -31,8 +31,7 @@ public final class ReflectionUtils {
} }
public static Object getFieldValue(Object instance, String fieldName) { public static Object getFieldValue(Object instance, String fieldName) {
Field field = org.springframework.util.ReflectionUtils Field field = org.springframework.util.ReflectionUtils.findField(instance.getClass(), fieldName);
.findField(instance.getClass(), fieldName);
field.setAccessible(true); field.setAccessible(true);
try { try {

@ -18,7 +18,6 @@
package com.tencent.cloud.common.metadata.config; package com.tencent.cloud.common.metadata.config;
import com.tencent.cloud.common.metadata.filter.gateway.MetadataFirstScgFilter; import com.tencent.cloud.common.metadata.filter.gateway.MetadataFirstScgFilter;
import com.tencent.cloud.common.metadata.filter.gateway.MetadataFirstZuulFilter;
import com.tencent.cloud.common.metadata.filter.web.MetadataReactiveFilter; import com.tencent.cloud.common.metadata.filter.web.MetadataReactiveFilter;
import com.tencent.cloud.common.metadata.filter.web.MetadataServletFilter; import com.tencent.cloud.common.metadata.filter.web.MetadataServletFilter;
import com.tencent.cloud.common.metadata.interceptor.feign.MetadataFirstFeignInterceptor; import com.tencent.cloud.common.metadata.interceptor.feign.MetadataFirstFeignInterceptor;
@ -48,31 +47,21 @@ public class MetadataAutoConfigurationTest {
*/ */
@Test @Test
public void test1() { public void test1() {
this.applicationContextRunner this.applicationContextRunner.withConfiguration(AutoConfigurations.of(MetadataAutoConfiguration.class))
.withConfiguration(AutoConfigurations.of(MetadataAutoConfiguration.class))
.run(context -> { .run(context -> {
Assertions.assertThat(context).hasSingleBean(MetadataLocalProperties.class);
Assertions.assertThat(context) Assertions.assertThat(context)
.hasSingleBean(MetadataLocalProperties.class); .doesNotHaveBean(MetadataAutoConfiguration.MetadataServletFilterConfig.class);
Assertions.assertThat(context).doesNotHaveBean( Assertions.assertThat(context).doesNotHaveBean(MetadataServletFilter.class);
MetadataAutoConfiguration.MetadataServletFilterConfig.class);
Assertions.assertThat(context) Assertions.assertThat(context)
.doesNotHaveBean(MetadataServletFilter.class); .doesNotHaveBean(MetadataAutoConfiguration.MetadataReactiveFilterConfig.class);
Assertions.assertThat(context).doesNotHaveBean( Assertions.assertThat(context).doesNotHaveBean(MetadataReactiveFilter.class);
MetadataAutoConfiguration.MetadataReactiveFilterConfig.class);
Assertions.assertThat(context) Assertions.assertThat(context)
.doesNotHaveBean(MetadataReactiveFilter.class); .hasSingleBean(MetadataAutoConfiguration.MetadataFeignInterceptorConfig.class);
Assertions.assertThat(context).hasSingleBean( Assertions.assertThat(context).hasSingleBean(MetadataFirstFeignInterceptor.class);
MetadataAutoConfiguration.MetadataFeignInterceptorConfig.class);
Assertions.assertThat(context) Assertions.assertThat(context)
.hasSingleBean(MetadataFirstFeignInterceptor.class); .hasSingleBean(MetadataAutoConfiguration.MetadataScgFilterConfig.class);
Assertions.assertThat(context).hasSingleBean( Assertions.assertThat(context).hasSingleBean(MetadataFirstScgFilter.class);
MetadataAutoConfiguration.MetadataZuulFilterConfig.class);
Assertions.assertThat(context)
.hasSingleBean(MetadataFirstZuulFilter.class);
Assertions.assertThat(context).hasSingleBean(
MetadataAutoConfiguration.MetadataScgFilterConfig.class);
Assertions.assertThat(context)
.hasSingleBean(MetadataFirstScgFilter.class);
}); });
} }
@ -81,31 +70,21 @@ public class MetadataAutoConfigurationTest {
*/ */
@Test @Test
public void test2() { public void test2() {
this.webApplicationContextRunner this.webApplicationContextRunner.withConfiguration(AutoConfigurations.of(MetadataAutoConfiguration.class))
.withConfiguration(AutoConfigurations.of(MetadataAutoConfiguration.class))
.run(context -> { .run(context -> {
Assertions.assertThat(context).hasSingleBean(MetadataLocalProperties.class);
Assertions.assertThat(context) Assertions.assertThat(context)
.hasSingleBean(MetadataLocalProperties.class); .hasSingleBean(MetadataAutoConfiguration.MetadataServletFilterConfig.class);
Assertions.assertThat(context).hasSingleBean( Assertions.assertThat(context).hasSingleBean(MetadataServletFilter.class);
MetadataAutoConfiguration.MetadataServletFilterConfig.class);
Assertions.assertThat(context)
.hasSingleBean(MetadataServletFilter.class);
Assertions.assertThat(context).doesNotHaveBean(
MetadataAutoConfiguration.MetadataReactiveFilterConfig.class);
Assertions.assertThat(context)
.doesNotHaveBean(MetadataReactiveFilter.class);
Assertions.assertThat(context).hasSingleBean(
MetadataAutoConfiguration.MetadataFeignInterceptorConfig.class);
Assertions.assertThat(context) Assertions.assertThat(context)
.hasSingleBean(MetadataFirstFeignInterceptor.class); .doesNotHaveBean(MetadataAutoConfiguration.MetadataReactiveFilterConfig.class);
Assertions.assertThat(context).hasSingleBean( Assertions.assertThat(context).doesNotHaveBean(MetadataReactiveFilter.class);
MetadataAutoConfiguration.MetadataZuulFilterConfig.class);
Assertions.assertThat(context) Assertions.assertThat(context)
.hasSingleBean(MetadataFirstZuulFilter.class); .hasSingleBean(MetadataAutoConfiguration.MetadataFeignInterceptorConfig.class);
Assertions.assertThat(context).hasSingleBean( Assertions.assertThat(context).hasSingleBean(MetadataFirstFeignInterceptor.class);
MetadataAutoConfiguration.MetadataScgFilterConfig.class);
Assertions.assertThat(context) Assertions.assertThat(context)
.hasSingleBean(MetadataFirstScgFilter.class); .hasSingleBean(MetadataAutoConfiguration.MetadataScgFilterConfig.class);
Assertions.assertThat(context).hasSingleBean(MetadataFirstScgFilter.class);
}); });
} }
@ -115,30 +94,20 @@ public class MetadataAutoConfigurationTest {
@Test @Test
public void test3() { public void test3() {
this.reactiveWebApplicationContextRunner this.reactiveWebApplicationContextRunner
.withConfiguration(AutoConfigurations.of(MetadataAutoConfiguration.class)) .withConfiguration(AutoConfigurations.of(MetadataAutoConfiguration.class)).run(context -> {
.run(context -> { Assertions.assertThat(context).hasSingleBean(MetadataLocalProperties.class);
Assertions.assertThat(context)
.hasSingleBean(MetadataLocalProperties.class);
Assertions.assertThat(context).doesNotHaveBean(
MetadataAutoConfiguration.MetadataServletFilterConfig.class);
Assertions.assertThat(context)
.doesNotHaveBean(MetadataServletFilter.class);
Assertions.assertThat(context).hasSingleBean(
MetadataAutoConfiguration.MetadataReactiveFilterConfig.class);
Assertions.assertThat(context) Assertions.assertThat(context)
.hasSingleBean(MetadataReactiveFilter.class); .doesNotHaveBean(MetadataAutoConfiguration.MetadataServletFilterConfig.class);
Assertions.assertThat(context).hasSingleBean( Assertions.assertThat(context).doesNotHaveBean(MetadataServletFilter.class);
MetadataAutoConfiguration.MetadataFeignInterceptorConfig.class);
Assertions.assertThat(context) Assertions.assertThat(context)
.hasSingleBean(MetadataFirstFeignInterceptor.class); .hasSingleBean(MetadataAutoConfiguration.MetadataReactiveFilterConfig.class);
Assertions.assertThat(context).hasSingleBean( Assertions.assertThat(context).hasSingleBean(MetadataReactiveFilter.class);
MetadataAutoConfiguration.MetadataZuulFilterConfig.class);
Assertions.assertThat(context) Assertions.assertThat(context)
.hasSingleBean(MetadataFirstZuulFilter.class); .hasSingleBean(MetadataAutoConfiguration.MetadataFeignInterceptorConfig.class);
Assertions.assertThat(context).hasSingleBean( Assertions.assertThat(context).hasSingleBean(MetadataFirstFeignInterceptor.class);
MetadataAutoConfiguration.MetadataScgFilterConfig.class);
Assertions.assertThat(context) Assertions.assertThat(context)
.hasSingleBean(MetadataFirstScgFilter.class); .hasSingleBean(MetadataAutoConfiguration.MetadataScgFilterConfig.class);
Assertions.assertThat(context).hasSingleBean(MetadataFirstScgFilter.class);
}); });
} }

@ -42,17 +42,14 @@ public class MetadataLocalPropertiesTest {
@Test @Test
public void test1() { public void test1() {
Assertions.assertThat(metadataLocalProperties.getContent().get("a")) Assertions.assertThat(metadataLocalProperties.getContent().get("a")).isEqualTo("1");
.isEqualTo("1"); Assertions.assertThat(metadataLocalProperties.getContent().get("b")).isEqualTo("2");
Assertions.assertThat(metadataLocalProperties.getContent().get("b"))
.isEqualTo("2");
Assertions.assertThat(metadataLocalProperties.getContent().get("c")).isNull(); Assertions.assertThat(metadataLocalProperties.getContent().get("c")).isNull();
} }
@Test @Test
public void test2() { public void test2() {
Assertions.assertThat(metadataLocalProperties.getTransitive().contains("b")) Assertions.assertThat(metadataLocalProperties.getTransitive().contains("b")).isTrue();
.isTrue();
} }
@SpringBootApplication @SpringBootApplication

@ -41,8 +41,7 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen
* @author Haotian Zhang * @author Haotian Zhang
*/ */
@RunWith(SpringRunner.class) @RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = MOCK, @SpringBootTest(webEnvironment = MOCK, classes = MetadataServletFilterTest.TestApplication.class,
classes = MetadataServletFilterTest.TestApplication.class,
properties = { "spring.config.location = classpath:application-test.yml" }) properties = { "spring.config.location = classpath:application-test.yml" })
public class MetadataReactiveFilterTest { public class MetadataReactiveFilterTest {
@ -69,15 +68,12 @@ public class MetadataReactiveFilterTest {
// Mock request // Mock request
MockServerHttpRequest request = MockServerHttpRequest.get("test") MockServerHttpRequest request = MockServerHttpRequest.get("test")
.header(MetadataConstant.HeaderName.CUSTOM_METADATA, "{\"c\": \"3\"}") .header(MetadataConstant.HeaderName.CUSTOM_METADATA, "{\"c\": \"3\"}").build();
.build();
ServerWebExchange exchange = MockServerWebExchange.from(request); ServerWebExchange exchange = MockServerWebExchange.from(request);
metadataReactiveFilter.filter(exchange, webFilterChain); metadataReactiveFilter.filter(exchange, webFilterChain);
Assertions.assertThat(metadataLocalProperties.getContent().get("a")) Assertions.assertThat(metadataLocalProperties.getContent().get("a")).isEqualTo("1");
.isEqualTo("1"); Assertions.assertThat(metadataLocalProperties.getContent().get("b")).isEqualTo("2");
Assertions.assertThat(metadataLocalProperties.getContent().get("b"))
.isEqualTo("2");
Assertions.assertThat(metadataLocalProperties.getContent().get("c")).isNull(); Assertions.assertThat(metadataLocalProperties.getContent().get("c")).isNull();
} }

@ -43,8 +43,7 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen
* @author Haotian Zhang * @author Haotian Zhang
*/ */
@RunWith(SpringRunner.class) @RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = RANDOM_PORT, @SpringBootTest(webEnvironment = RANDOM_PORT, classes = MetadataServletFilterTest.TestApplication.class,
classes = MetadataServletFilterTest.TestApplication.class,
properties = { "spring.config.location = classpath:application-test.yml" }) properties = { "spring.config.location = classpath:application-test.yml" })
public class MetadataServletFilterTest { public class MetadataServletFilterTest {
@ -66,10 +65,8 @@ public class MetadataServletFilterTest {
request.addHeader(MetadataConstant.HeaderName.CUSTOM_METADATA, "{\"c\": \"3\"}"); request.addHeader(MetadataConstant.HeaderName.CUSTOM_METADATA, "{\"c\": \"3\"}");
MockHttpServletResponse response = new MockHttpServletResponse(); MockHttpServletResponse response = new MockHttpServletResponse();
metadataServletFilter.doFilter(request, response, filterChain); metadataServletFilter.doFilter(request, response, filterChain);
Assertions.assertThat(metadataLocalProperties.getContent().get("a")) Assertions.assertThat(metadataLocalProperties.getContent().get("a")).isEqualTo("1");
.isEqualTo("1"); Assertions.assertThat(metadataLocalProperties.getContent().get("b")).isEqualTo("2");
Assertions.assertThat(metadataLocalProperties.getContent().get("b"))
.isEqualTo("2");
Assertions.assertThat(metadataLocalProperties.getContent().get("c")).isNull(); Assertions.assertThat(metadataLocalProperties.getContent().get("c")).isNull();
} }

@ -4,7 +4,6 @@ spring:
autoconfigure: autoconfigure:
exclude: exclude:
- org.springframework.cloud.gateway.config.GatewayAutoConfiguration - org.springframework.cloud.gateway.config.GatewayAutoConfiguration
- org.springframework.cloud.netflix.zuul.ZuulServerAutoConfiguration
cloud: cloud:
tencent: tencent:
metadata: metadata:

@ -1,93 +1,93 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent> <parent>
<groupId>org.springframework.cloud</groupId> <groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies-parent</artifactId> <artifactId>spring-cloud-dependencies-parent</artifactId>
<version>2.3.1.RELEASE</version> <version>3.0.4</version>
<relativePath/> <relativePath/>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>com.tencent.cloud</groupId> <groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-tencent-dependencies</artifactId> <artifactId>spring-cloud-tencent-dependencies</artifactId>
<version>${revision}</version> <version>${revision}</version>
<packaging>pom</packaging> <packaging>pom</packaging>
<name>Spring Cloud Tencent Dependencies</name> <name>Spring Cloud Tencent Dependencies</name>
<description>Spring Cloud Tencent Dependencies</description> <description>Spring Cloud Tencent Dependencies</description>
<url>https://github.com/Tencent/spring-cloud-tencent/tree/main</url> <url>https://github.com/Tencent/spring-cloud-tencent/tree/main</url>
<organization> <organization>
<name>Tencent</name> <name>Tencent</name>
<url>https://opensource.tencent.com/</url> <url>https://opensource.tencent.com/</url>
</organization> </organization>
<licenses> <licenses>
<license> <license>
<name>The BSD 3-Clause License (BSD3)</name> <name>The BSD 3-Clause License (BSD3)</name>
<url>https://raw.githubusercontent.com/Tencent/spring-cloud-tencent/main/LICENSE</url> <url>https://raw.githubusercontent.com/Tencent/spring-cloud-tencent/main/LICENSE</url>
<distribution>repo</distribution> <distribution>repo</distribution>
</license> </license>
</licenses> </licenses>
<scm> <scm>
<url>https://github.com/Tencent/spring-cloud-tencent</url> <url>https://github.com/Tencent/spring-cloud-tencent</url>
<connection>scm:git:git@github.com:Tencent/spring-cloud-tencent.git</connection> <connection>scm:git:git@github.com:Tencent/spring-cloud-tencent.git</connection>
<developerConnection>scm:git:git@github.com:Tencent/spring-cloud-tencent.git</developerConnection> <developerConnection>scm:git:git@github.com:Tencent/spring-cloud-tencent.git</developerConnection>
</scm> </scm>
<developers> <developers>
<developer> <developer>
<id>SkyeBeFreeman</id> <id>SkyeBeFreeman</id>
<name>Haotian Zhang</name> <name>Haotian Zhang</name>
<email>928016560@qq.com</email> <email>928016560@qq.com</email>
<organization>Tencent</organization> <organization>Tencent</organization>
<url>https://github.com/SkyeBeFreeman/</url> <url>https://github.com/SkyeBeFreeman/</url>
</developer> </developer>
<developer> <developer>
<name>Andrew Shan</name> <name>Andrew Shan</name>
<email>samshan08@126.com</email> <email>samshan08@126.com</email>
<organization>Tencent</organization> <organization>Tencent</organization>
</developer> </developer>
<developer> <developer>
<id>xiaoyao1999hn</id> <id>xiaoyao1999hn</id>
<name>Jie Cheng</name> <name>Jie Cheng</name>
<email>348893717@qq.com</email> <email>348893717@qq.com</email>
<organization>Tencent</organization> <organization>Tencent</organization>
<url>https://github.com/xiaoyao1999hn/</url> <url>https://github.com/xiaoyao1999hn/</url>
</developer> </developer>
</developers> </developers>
<properties> <properties>
<revision>1.2.0-Hoxton.SR9-SNAPSHOT</revision> <revision>1.2.0-2020.0.5-SNAPSHOT</revision>
<polaris.version>1.3.0</polaris.version> <polaris.version>1.3.1</polaris.version>
<powermock.version>2.0.0</powermock.version> <powermock.version>2.0.0</powermock.version>
<!-- Maven Plugin Versions --> <!-- Maven Plugin Versions -->
<maven-source-plugin.version>3.2.0</maven-source-plugin.version> <maven-source-plugin.version>3.2.0</maven-source-plugin.version>
<maven-javadoc-plugin.version>3.1.1</maven-javadoc-plugin.version> <maven-javadoc-plugin.version>3.1.1</maven-javadoc-plugin.version>
<flatten-maven-plugin.version>1.2.7</flatten-maven-plugin.version> <flatten-maven-plugin.version>1.2.7</flatten-maven-plugin.version>
<maven-gpg-plugin.version>1.6</maven-gpg-plugin.version> <maven-gpg-plugin.version>1.6</maven-gpg-plugin.version>
</properties> </properties>
<dependencyManagement> <dependencyManagement>
<dependencies> <dependencies>
<dependency> <dependency>
<artifactId>polaris-dependencies</artifactId> <artifactId>polaris-dependencies</artifactId>
<groupId>com.tencent.polaris</groupId> <groupId>com.tencent.polaris</groupId>
<version>${polaris.version}</version> <version>${polaris.version}</version>
<type>pom</type> <type>pom</type>
<scope>import</scope> <scope>import</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.tencent.cloud</groupId> <groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-tencent-commons</artifactId> <artifactId>spring-cloud-tencent-commons</artifactId>
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.tencent.cloud</groupId> <groupId>com.tencent.cloud</groupId>
@ -101,24 +101,24 @@
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<!-- polaris starter--> <!-- polaris starter-->
<dependency> <dependency>
<groupId>com.tencent.cloud</groupId> <groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-polaris-ratelimit</artifactId> <artifactId>spring-cloud-starter-tencent-polaris-ratelimit</artifactId>
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.tencent.cloud</groupId> <groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-polaris-circuitbreaker</artifactId> <artifactId>spring-cloud-starter-tencent-polaris-circuitbreaker</artifactId>
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.tencent.cloud</groupId> <groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-polaris-router</artifactId> <artifactId>spring-cloud-starter-tencent-polaris-router</artifactId>
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.tencent.cloud</groupId> <groupId>com.tencent.cloud</groupId>
@ -126,116 +126,116 @@
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.tencent.cloud</groupId> <groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-polaris-discovery</artifactId> <artifactId>spring-cloud-starter-tencent-polaris-discovery</artifactId>
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<!-- powermock-module-junit4 --> <!-- powermock-module-junit4 -->
<dependency> <dependency>
<groupId>org.powermock</groupId> <groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId> <artifactId>powermock-module-junit4</artifactId>
<version>${powermock.version}</version> <version>${powermock.version}</version>
</dependency> </dependency>
<!-- powermock-api-mockito --> <!-- powermock-api-mockito -->
<dependency> <dependency>
<groupId>org.powermock</groupId> <groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito2</artifactId> <artifactId>powermock-api-mockito2</artifactId>
<version>${powermock.version}</version> <version>${powermock.version}</version>
</dependency> </dependency>
</dependencies> </dependencies>
</dependencyManagement> </dependencyManagement>
<build> <build>
<plugins> <plugins>
<plugin> <plugin>
<groupId>org.codehaus.mojo</groupId> <groupId>org.codehaus.mojo</groupId>
<artifactId>flatten-maven-plugin</artifactId> <artifactId>flatten-maven-plugin</artifactId>
<version>${flatten-maven-plugin.version}</version> <version>${flatten-maven-plugin.version}</version>
<configuration> <configuration>
<updatePomFile>true</updatePomFile> <updatePomFile>true</updatePomFile>
<flattenMode>resolveCiFriendliesOnly</flattenMode> <flattenMode>resolveCiFriendliesOnly</flattenMode>
</configuration> </configuration>
<executions> <executions>
<execution> <execution>
<id>flatten</id> <id>flatten</id>
<phase>process-resources</phase> <phase>process-resources</phase>
<goals> <goals>
<goal>flatten</goal> <goal>flatten</goal>
</goals> </goals>
</execution> </execution>
<execution> <execution>
<id>flatten.clean</id> <id>flatten.clean</id>
<phase>clean</phase> <phase>clean</phase>
<goals> <goals>
<goal>clean</goal> <goal>clean</goal>
</goals> </goals>
</execution> </execution>
</executions> </executions>
</plugin> </plugin>
</plugins> </plugins>
</build> </build>
<profiles> <profiles>
<profile> <profile>
<id>release</id> <id>release</id>
<build> <build>
<plugins> <plugins>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId> <artifactId>maven-javadoc-plugin</artifactId>
<executions> <executions>
<execution> <execution>
<id>attach-javadocs</id> <id>attach-javadocs</id>
<goals> <goals>
<goal>jar</goal> <goal>jar</goal>
</goals> </goals>
</execution> </execution>
</executions> </executions>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId> <artifactId>maven-source-plugin</artifactId>
<version>${maven-source-plugin.version}</version> <version>${maven-source-plugin.version}</version>
<executions> <executions>
<execution> <execution>
<phase>package</phase> <phase>package</phase>
<goals> <goals>
<goal>jar-no-fork</goal> <goal>jar-no-fork</goal>
</goals> </goals>
</execution> </execution>
</executions> </executions>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId> <artifactId>maven-gpg-plugin</artifactId>
<version>${maven-gpg-plugin.version}</version> <version>${maven-gpg-plugin.version}</version>
<executions> <executions>
<execution> <execution>
<phase>verify</phase> <phase>verify</phase>
<goals> <goals>
<goal>sign</goal> <goal>sign</goal>
</goals> </goals>
</execution> </execution>
</executions> </executions>
</plugin> </plugin>
</plugins> </plugins>
</build> </build>
<distributionManagement> <distributionManagement>
<snapshotRepository> <snapshotRepository>
<id>nexus-snapshots</id> <id>nexus-snapshots</id>
<url>https://oss.sonatype.org/content/repositories/snapshots/</url> <url>https://oss.sonatype.org/content/repositories/snapshots/</url>
</snapshotRepository> </snapshotRepository>
<repository> <repository>
<id>nexus-releases</id> <id>nexus-releases</id>
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url> <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
</repository> </repository>
</distributionManagement> </distributionManagement>
</profile> </profile>
</profiles> </profiles>
</project> </project>

@ -31,7 +31,7 @@
<dependency> <dependency>
<groupId>org.springframework.cloud</groupId> <groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId> <artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency> </dependency>
</dependencies> </dependencies>

@ -25,8 +25,7 @@ import org.springframework.web.bind.annotation.GetMapping;
* *
* @author Haotian Zhang * @author Haotian Zhang
*/ */
@FeignClient(name = "polaris-circuitbreaker-example-b", @FeignClient(name = "polaris-circuitbreaker-example-b", fallback = ProviderBFallback.class)
fallback = ProviderBFallback.class)
public interface ProviderB { public interface ProviderB {
/** /**

@ -54,9 +54,8 @@ public class ServiceAController {
*/ */
@GetMapping("/testRest") @GetMapping("/testRest")
public String testRest() { public String testRest() {
ResponseEntity<String> entity = restTemplate.getForEntity( ResponseEntity<String> entity = restTemplate
"http://polaris-circuitbreaker-example-b/example/service/b/info", .getForEntity("http://polaris-circuitbreaker-example-b/example/service/b/info", String.class);
String.class);
return entity.getBody(); return entity.getBody();
} }

@ -8,7 +8,7 @@ spring:
address: grpc://127.0.0.1:8091 address: grpc://127.0.0.1:8091
namespace: default namespace: default
feign: feign:
hystrix: circuitbreaker:
enabled: true enabled: true
compression: compression:
request: request:
@ -17,16 +17,6 @@ feign:
min-request-size: 2048 min-request-size: 2048
response: response:
enabled: false enabled: false
ribbon:
polaris:
enabled: true
MaxAutoRetries: 1
MaxAutoRetriesNextServer: 2
OkToRetryOnAllOperations: false
ConnectionTimeout: 1000
ReadTimeout: 1000
eager-load:
enabled: on
serivceB: serivceB:
url: http://localhost:48081 url: http://localhost:48081

@ -28,6 +28,11 @@
<!-- <groupId>org.springframework.cloud</groupId>--> <!-- <groupId>org.springframework.cloud</groupId>-->
<!-- <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>--> <!-- <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>-->
<!-- </dependency>--> <!-- </dependency>-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
</dependencies> </dependencies>
<build> <build>
<plugins> <plugins>

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save