From 36ff03b7b746a2fbbce9c9cc152ff5261b391f01 Mon Sep 17 00:00:00 2001 From: lepdou Date: Fri, 10 Jun 2022 18:34:32 +0800 Subject: [PATCH 1/6] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 06c1f8175..c4a5a2b38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,4 @@ # Change Log --- +[Feature: Add config change listener feature support](https://github.com/Tencent/spring-cloud-tencent/pull/220) From 30f57c527dbe456b1fa0e26c508ece625547abac Mon Sep 17 00:00:00 2001 From: lepdou Date: Sat, 11 Jun 2022 18:26:21 +0800 Subject: [PATCH 2/6] add unit test for config module (#229) --- pom.xml | 6 +- ...odeTransferMedataFeignInterceptorTest.java | 15 +- ...sferMedataRestTemplateInterceptorTest.java | 45 ++--- .../pom.xml | 24 +++ ...nditionalOnConnectRemoteServerEnabled.java | 37 ++++ ...larisConfigBootstrapAutoConfiguration.java | 11 +- .../adapter/PolarisConfigFileLocator.java | 13 +- ...itional-spring-configuration-metadata.json | 7 + .../config/adapter/MockedConfigKVFile.java | 170 ++++++++++++++++ .../adapter/PolarisConfigFileLocatorTest.java | 188 ++++++++++++++++++ ...arisPropertiesSourceAutoRefresherTest.java | 122 ++++++++++++ .../listener/ConfigChangeListenerTest.java | 124 ++++++++++++ .../src/test/resources/application-test.yml | 9 + spring-cloud-tencent-coverage/pom.xml | 20 +- 14 files changed, 733 insertions(+), 58 deletions(-) create mode 100644 spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/ConditionalOnConnectRemoteServerEnabled.java create mode 100644 spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/MockedConfigKVFile.java create mode 100644 spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFileLocatorTest.java create mode 100644 spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertiesSourceAutoRefresherTest.java create mode 100644 spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/listener/ConfigChangeListenerTest.java create mode 100644 spring-cloud-starter-tencent-polaris-config/src/test/resources/application-test.yml diff --git a/pom.xml b/pom.xml index 656119d9a..1b982d125 100644 --- a/pom.xml +++ b/pom.xml @@ -38,9 +38,11 @@ - spring-cloud-tencent-polaris-context spring-cloud-tencent-commons + spring-cloud-tencent-polaris-context + spring-cloud-tencent-polaris-loadbalancer spring-cloud-starter-tencent-metadata-transfer + spring-cloud-starter-tencent-polaris-config spring-cloud-starter-tencent-polaris-discovery spring-cloud-starter-tencent-polaris-ratelimit spring-cloud-starter-tencent-polaris-circuitbreaker @@ -48,8 +50,6 @@ spring-cloud-tencent-dependencies spring-cloud-tencent-examples spring-cloud-tencent-coverage - spring-cloud-starter-tencent-polaris-config - spring-cloud-tencent-polaris-loadbalancer diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/intercepter/EncodeTransferMedataFeignInterceptorTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/intercepter/EncodeTransferMedataFeignInterceptorTest.java index ca9671631..ef70e38c7 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/intercepter/EncodeTransferMedataFeignInterceptorTest.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/intercepter/EncodeTransferMedataFeignInterceptorTest.java @@ -19,9 +19,10 @@ package com.tencent.cloud.metadata.core.intercepter; import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; 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.metadata.config.MetadataLocalProperties; import com.tencent.cloud.metadata.core.EncodeTransferMedataFeignInterceptor; import feign.RequestInterceptor; @@ -62,10 +63,9 @@ public class EncodeTransferMedataFeignInterceptorTest { private TestApplication.TestFeign testFeign; @Test - public void test1() { + public void testTransitiveMetadataFromApplicationConfig() { String metadata = testFeign.test(); - Assertions.assertThat(metadata) - .isEqualTo("{\"b\":\"2\"}"); + Assertions.assertThat(metadata).isEqualTo("2"); Assertions.assertThat(metadataLocalProperties.getContent().get("a")) .isEqualTo("1"); Assertions.assertThat(metadataLocalProperties.getContent().get("b")) @@ -81,16 +81,13 @@ public class EncodeTransferMedataFeignInterceptorTest { public String test( @RequestHeader(MetadataConstant.HeaderName.CUSTOM_METADATA) String customMetadataStr) throws UnsupportedEncodingException { - return URLDecoder.decode(customMetadataStr, "UTF-8"); + return MetadataContextHolder.get().getContext(MetadataContext.FRAGMENT_TRANSITIVE, "b"); } @FeignClient(name = "test-feign", url = "http://localhost:8081") public interface TestFeign { - @RequestMapping(value = "/test", - headers = {"X-SCT-Metadata-Transitive-a=11", - "X-SCT-Metadata-Transitive-b=22", - "X-SCT-Metadata-Transitive-c=33"}) + @RequestMapping("/test") String test(); } diff --git a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/intercepter/EncodeTransferMedataRestTemplateInterceptorTest.java b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/intercepter/EncodeTransferMedataRestTemplateInterceptorTest.java index ba5524c9a..78abb33ab 100644 --- a/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/intercepter/EncodeTransferMedataRestTemplateInterceptorTest.java +++ b/spring-cloud-starter-tencent-metadata-transfer/src/test/java/com/tencent/cloud/metadata/core/intercepter/EncodeTransferMedataRestTemplateInterceptorTest.java @@ -19,11 +19,12 @@ package com.tencent.cloud.metadata.core.intercepter; import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; import com.tencent.cloud.common.constant.MetadataConstant; -import com.tencent.cloud.common.metadata.config.MetadataLocalProperties; +import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.common.metadata.MetadataContextHolder; import com.tencent.cloud.metadata.core.EncodeTransferMedataRestTemplateInterceptor; +import org.assertj.core.api.Assertions; import org.junit.Test; import org.junit.runner.RunWith; @@ -32,6 +33,9 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.web.server.LocalServerPort; import org.springframework.context.annotation.Bean; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; @@ -51,9 +55,6 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen properties = { "spring.config.location = classpath:application-test.yml" }) public class EncodeTransferMedataRestTemplateInterceptorTest { - @Autowired - private MetadataLocalProperties metadataLocalProperties; - @Autowired private RestTemplate restTemplate; @@ -61,30 +62,14 @@ public class EncodeTransferMedataRestTemplateInterceptorTest { private int localServerPort; @Test - public void test1() { -// HttpHeaders httpHeaders = new HttpHeaders(); -// httpHeaders.set(MetadataConstant.HeaderName.CUSTOM_METADATA, -// "{\"a\":\"11\",\"b\":\"22\",\"c\":\"33\"}"); -// HttpEntity httpEntity = new HttpEntity<>(httpHeaders); -// String metadata = restTemplate -// .exchange("http://localhost:" + localServerPort + "/test", HttpMethod.GET, -// httpEntity, String.class) -// .getBody(); -// Assertions.assertThat(metadata) -// .isEqualTo("{\"a\":\"11\",\"b\":\"22\",\"c\":\"33\"}"); -// Assertions.assertThat(metadataLocalProperties.getContent().get("a")) -// .isEqualTo("1"); -// Assertions.assertThat(metadataLocalProperties.getContent().get("b")) -// .isEqualTo("2"); -// Assertions -// .assertThat(MetadataContextHolder.get().getContext(MetadataContext.FRAGMENT_TRANSITIVE, "a")) -// .isEqualTo("11"); -// Assertions -// .assertThat(MetadataContextHolder.get().getContext(MetadataContext.FRAGMENT_TRANSITIVE, "b")) -// .isEqualTo("22"); -// Assertions -// .assertThat(MetadataContextHolder.get().getContext(MetadataContext.FRAGMENT_TRANSITIVE, "c")) -// .isEqualTo("33"); + public void testTransitiveMetadataFromApplicationConfig() { + HttpHeaders httpHeaders = new HttpHeaders(); + HttpEntity httpEntity = new HttpEntity<>(httpHeaders); + String metadata = restTemplate + .exchange("http://localhost:" + localServerPort + "/test", HttpMethod.GET, + httpEntity, String.class) + .getBody(); + Assertions.assertThat(metadata).isEqualTo("2"); } @SpringBootApplication @@ -100,7 +85,7 @@ public class EncodeTransferMedataRestTemplateInterceptorTest { public String test( @RequestHeader(MetadataConstant.HeaderName.CUSTOM_METADATA) String customMetadataStr) throws UnsupportedEncodingException { - return URLDecoder.decode(customMetadataStr, "UTF-8"); + return MetadataContextHolder.get().getContext(MetadataContext.FRAGMENT_TRANSITIVE, "b"); } } diff --git a/spring-cloud-starter-tencent-polaris-config/pom.xml b/spring-cloud-starter-tencent-polaris-config/pom.xml index 10b362a67..a7f0e5894 100644 --- a/spring-cloud-starter-tencent-polaris-config/pom.xml +++ b/spring-cloud-starter-tencent-polaris-config/pom.xml @@ -11,6 +11,7 @@ 4.0.0 spring-cloud-starter-tencent-polaris-config + Spring Cloud Starter Tencent Polaris Config @@ -64,5 +65,28 @@ + + org.springframework.boot + spring-boot-starter-test + test + + + + org.mockito + mockito-inline + test + + + + org.mockito + mockito-core + test + + + + net.bytebuddy + byte-buddy + test + diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/ConditionalOnConnectRemoteServerEnabled.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/ConditionalOnConnectRemoteServerEnabled.java new file mode 100644 index 000000000..89283ae18 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/ConditionalOnConnectRemoteServerEnabled.java @@ -0,0 +1,37 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.polaris.config; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; + +/** + * Whether to connect to a remote server, suitable for local development mode. + * + * @author lepdou 2022-06-11 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.TYPE, ElementType.METHOD }) +@ConditionalOnProperty(value = "spring.cloud.polaris.config.connect-remote-server", matchIfMissing = true) +public @interface ConditionalOnConnectRemoteServerEnabled { + +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/PolarisConfigBootstrapAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/PolarisConfigBootstrapAutoConfiguration.java index 1a7e05ac9..101ca4a35 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/PolarisConfigBootstrapAutoConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/PolarisConfigBootstrapAutoConfiguration.java @@ -51,16 +51,18 @@ public class PolarisConfigBootstrapAutoConfiguration { } @Bean - public ConfigFileService configFileService(SDKContext sdkContext) { - return ConfigFileServiceFactory.createConfigFileService(sdkContext); + public PolarisPropertySourceManager polarisPropertySourceManager() { + return new PolarisPropertySourceManager(); } @Bean - public PolarisPropertySourceManager polarisPropertySourceManager() { - return new PolarisPropertySourceManager(); + @ConditionalOnConnectRemoteServerEnabled + public ConfigFileService configFileService(SDKContext sdkContext) { + return ConfigFileServiceFactory.createConfigFileService(sdkContext); } @Bean + @ConditionalOnConnectRemoteServerEnabled public PolarisConfigFileLocator polarisConfigFileLocator( PolarisConfigProperties polarisConfigProperties, PolarisContextProperties polarisContextProperties, @@ -73,6 +75,7 @@ public class PolarisConfigBootstrapAutoConfiguration { } @Bean + @ConditionalOnConnectRemoteServerEnabled public ConfigurationModifier configurationModifier(PolarisConfigProperties polarisConfigProperties, PolarisContextProperties polarisContextProperties) { return new ConfigurationModifier(polarisConfigProperties, polarisContextProperties); diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFileLocator.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFileLocator.java index cad31d1de..240eb4cc0 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFileLocator.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFileLocator.java @@ -84,13 +84,14 @@ public class PolarisConfigFileLocator implements PropertySourceLocator { CompositePropertySource compositePropertySource = new CompositePropertySource( POLARIS_CONFIG_PROPERTY_SOURCE_NAME); + // load spring boot default config files + initInternalConfigFiles(compositePropertySource); + + // load custom config files List configFileGroups = polarisConfigProperties.getGroups(); if (CollectionUtils.isEmpty(configFileGroups)) { return compositePropertySource; } - - initInternalConfigFiles(compositePropertySource); - initCustomPolarisConfigFiles(compositePropertySource, configFileGroups); return compositePropertySource; @@ -190,12 +191,10 @@ public class PolarisConfigFileLocator implements PropertySourceLocator { // unknown extension is resolved as properties file if (ConfigFileFormat.isPropertyFile(fileName) || ConfigFileFormat.isUnknownFile(fileName)) { - configKVFile = configFileService.getConfigPropertiesFile(namespace, group, - fileName); + configKVFile = configFileService.getConfigPropertiesFile(namespace, group, fileName); } else if (ConfigFileFormat.isYamlFile(fileName)) { - configKVFile = configFileService.getConfigYamlFile(namespace, group, - fileName); + configKVFile = configFileService.getConfigYamlFile(namespace, group, fileName); } else { LOGGER.warn( diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-cloud-starter-tencent-polaris-config/src/main/resources/META-INF/additional-spring-configuration-metadata.json index ee84cbd47..9954a62ce 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-cloud-starter-tencent-polaris-config/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -34,6 +34,13 @@ "defaultValue": "", "description": "List of imported config files.", "sourceType": "com.tencent.cloud.polaris.config.config.PolarisConfigProperties" + }, + { + "name": "spring.cloud.polaris.config.connect-remote-server", + "type": "java.lang.Boolean", + "defaultValue": "true", + "description": "Whether to connect to a remote server, suitable for local development mode.", + "sourceType": "com.tencent.cloud.polaris.config.config.PolarisConfigProperties" } ] } diff --git a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/MockedConfigKVFile.java b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/MockedConfigKVFile.java new file mode 100644 index 000000000..026fe4d52 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/MockedConfigKVFile.java @@ -0,0 +1,170 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + */ + +package com.tencent.cloud.polaris.config.adapter; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.tencent.polaris.configuration.api.core.ConfigFileChangeListener; +import com.tencent.polaris.configuration.api.core.ConfigKVFile; +import com.tencent.polaris.configuration.api.core.ConfigKVFileChangeEvent; +import com.tencent.polaris.configuration.api.core.ConfigKVFileChangeListener; + +/** + * Mock config kv file for test. + *@author lepdou 2022-06-11 + */ +public class MockedConfigKVFile implements ConfigKVFile { + + private final Map properties; + private final List listeners = new ArrayList<>(); + + public MockedConfigKVFile(Map properties) { + this.properties = properties; + } + + @Override + public String getProperty(String s, String s1) { + return String.valueOf(properties.get(s)); + } + + @Override + public Integer getIntProperty(String s, Integer integer) { + return null; + } + + @Override + public Long getLongProperty(String s, Long aLong) { + return null; + } + + @Override + public Short getShortProperty(String s, Short aShort) { + return null; + } + + @Override + public Float getFloatProperty(String s, Float aFloat) { + return null; + } + + @Override + public Double getDoubleProperty(String s, Double aDouble) { + return null; + } + + @Override + public Byte getByteProperty(String s, Byte aByte) { + return null; + } + + @Override + public Boolean getBooleanProperty(String s, Boolean aBoolean) { + return null; + } + + @Override + public String[] getArrayProperty(String s, String s1, String[] strings) { + return new String[0]; + } + + @Override + public > T getEnumProperty(String s, Class aClass, T t) { + return null; + } + + @Override + public T getJsonProperty(String s, Class aClass, T t) { + return null; + } + + @Override + public T getJsonProperty(String s, Type type, T t) { + return null; + } + + @Override + public Set getPropertyNames() { + return properties.keySet(); + } + + @Override + public void addChangeListener(ConfigKVFileChangeListener configKVFileChangeListener) { + listeners.add(configKVFileChangeListener); + } + + @Override + public void removeChangeListener(ConfigKVFileChangeListener configKVFileChangeListener) { + + } + + @Override + public String getContent() { + return null; + } + + @Override + public T asJson(Class aClass, T t) { + return null; + } + + @Override + public T asJson(Type type, T t) { + return null; + } + + @Override + public boolean hasContent() { + return false; + } + + @Override + public void addChangeListener(ConfigFileChangeListener configFileChangeListener) { + + } + + @Override + public void removeChangeListener(ConfigFileChangeListener configFileChangeListener) { + + } + + public void fireChangeListener(ConfigKVFileChangeEvent event) { + for (ConfigKVFileChangeListener listener : listeners) { + listener.onChange(event); + } + } + + @Override + public String getNamespace() { + return null; + } + + @Override + public String getFileGroup() { + return null; + } + + @Override + public String getFileName() { + return null; + } +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFileLocatorTest.java b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFileLocatorTest.java new file mode 100644 index 000000000..6fe0bfa2a --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFileLocatorTest.java @@ -0,0 +1,188 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + */ + +package com.tencent.cloud.polaris.config.adapter; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import com.google.common.collect.Lists; +import com.tencent.cloud.polaris.config.config.ConfigFileGroup; +import com.tencent.cloud.polaris.config.config.PolarisConfigProperties; +import com.tencent.cloud.polaris.context.PolarisContextProperties; +import com.tencent.polaris.configuration.api.core.ConfigFileService; +import com.tencent.polaris.configuration.api.core.ConfigKVFile; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import org.springframework.core.env.Environment; +import org.springframework.core.env.PropertySource; + +import static org.mockito.Mockito.when; + +/** + * test for {@link PolarisConfigFileLocator} + *@author lepdou 2022-06-11 + */ +@RunWith(MockitoJUnitRunner.class) +public class PolarisConfigFileLocatorTest { + + @Mock + private PolarisConfigProperties polarisConfigProperties; + @Mock + private PolarisContextProperties polarisContextProperties; + @Mock + private ConfigFileService configFileService; + @Mock + private PolarisPropertySourceManager polarisPropertySourceManager; + @Mock + private Environment environment; + + private final String testNamespace = "testNamespace"; + private final String testServiceName = "testServiceName"; + + @Test + public void testLoadApplicationPropertiesFile() { + PolarisConfigFileLocator locator = new PolarisConfigFileLocator(polarisConfigProperties, polarisContextProperties, + configFileService, polarisPropertySourceManager, environment); + + when(polarisContextProperties.getNamespace()).thenReturn(testNamespace); + when(polarisContextProperties.getService()).thenReturn(testServiceName); + + // application.properties + Map applicationProperties = new HashMap<>(); + applicationProperties.put("k1", "v1"); + applicationProperties.put("k2", "v2"); + applicationProperties.put("k3", "v3"); + ConfigKVFile propertiesFile = new MockedConfigKVFile(applicationProperties); + when(configFileService.getConfigPropertiesFile(testNamespace, testServiceName, "application.properties")) + .thenReturn(propertiesFile); + + Map emptyMap = new HashMap<>(); + ConfigKVFile emptyConfigFile = new MockedConfigKVFile(emptyMap); + when(configFileService.getConfigYamlFile(testNamespace, testServiceName, "application.yml")).thenReturn(emptyConfigFile); + when(configFileService.getConfigPropertiesFile(testNamespace, testServiceName, "bootstrap.properties")).thenReturn(emptyConfigFile); + when(configFileService.getConfigYamlFile(testNamespace, testServiceName, "bootstrap.yml")).thenReturn(emptyConfigFile); + + when(polarisConfigProperties.getGroups()).thenReturn(null); + when(environment.getActiveProfiles()).thenReturn(new String[] {}); + + PropertySource propertySource = locator.locate(environment); + + Assert.assertEquals("v1", propertySource.getProperty("k1")); + Assert.assertEquals("v2", propertySource.getProperty("k2")); + Assert.assertEquals("v3", propertySource.getProperty("k3")); + } + + @Test + public void testActiveProfileFilesPriorityBiggerThanDefault() { + PolarisConfigFileLocator locator = new PolarisConfigFileLocator(polarisConfigProperties, polarisContextProperties, + configFileService, polarisPropertySourceManager, environment); + + when(polarisContextProperties.getNamespace()).thenReturn(testNamespace); + when(polarisContextProperties.getService()).thenReturn(testServiceName); + + // application.properties + Map applicationProperties = new HashMap<>(); + applicationProperties.put("k1", "v1"); + applicationProperties.put("k2", "v2"); + applicationProperties.put("k3", "v3"); + ConfigKVFile propertiesFile = new MockedConfigKVFile(applicationProperties); + when(configFileService.getConfigPropertiesFile(testNamespace, testServiceName, "application.properties")) + .thenReturn(propertiesFile); + + // application-dev.properties + Map devProperties = new HashMap<>(); + devProperties.put("k1", "v11"); + ConfigKVFile devFile = new MockedConfigKVFile(devProperties); + when(configFileService.getConfigPropertiesFile(testNamespace, testServiceName, "application-dev.properties")) + .thenReturn(devFile); + + Map emptyMap = new HashMap<>(); + ConfigKVFile emptyConfigFile = new MockedConfigKVFile(emptyMap); + when(configFileService.getConfigYamlFile(testNamespace, testServiceName, "application.yml")).thenReturn(emptyConfigFile); + when(configFileService.getConfigYamlFile(testNamespace, testServiceName, "application-dev.yml")).thenReturn(emptyConfigFile); + when(configFileService.getConfigPropertiesFile(testNamespace, testServiceName, "bootstrap.properties")).thenReturn(emptyConfigFile); + when(configFileService.getConfigPropertiesFile(testNamespace, testServiceName, "bootstrap-dev.properties")).thenReturn(emptyConfigFile); + when(configFileService.getConfigYamlFile(testNamespace, testServiceName, "bootstrap.yml")).thenReturn(emptyConfigFile); + when(configFileService.getConfigYamlFile(testNamespace, testServiceName, "bootstrap-dev.yml")).thenReturn(emptyConfigFile); + + when(polarisConfigProperties.getGroups()).thenReturn(null); + when(environment.getActiveProfiles()).thenReturn(new String[] {"dev"}); + + PropertySource propertySource = locator.locate(environment); + + Assert.assertEquals("v11", propertySource.getProperty("k1")); + Assert.assertEquals("v2", propertySource.getProperty("k2")); + Assert.assertEquals("v3", propertySource.getProperty("k3")); + } + + @Test + public void testGetCustomFiles() { + PolarisConfigFileLocator locator = new PolarisConfigFileLocator(polarisConfigProperties, polarisContextProperties, + configFileService, polarisPropertySourceManager, environment); + + when(polarisContextProperties.getNamespace()).thenReturn(testNamespace); + when(polarisContextProperties.getService()).thenReturn(testServiceName); + + Map emptyMap = new HashMap<>(); + ConfigKVFile emptyConfigFile = new MockedConfigKVFile(emptyMap); + + when(configFileService.getConfigPropertiesFile(testNamespace, testServiceName, "application.properties")).thenReturn(emptyConfigFile); + when(configFileService.getConfigYamlFile(testNamespace, testServiceName, "application.yml")).thenReturn(emptyConfigFile); + when(configFileService.getConfigPropertiesFile(testNamespace, testServiceName, "bootstrap.properties")).thenReturn(emptyConfigFile); + when(configFileService.getConfigYamlFile(testNamespace, testServiceName, "bootstrap.yml")).thenReturn(emptyConfigFile); + + List customFiles = new LinkedList<>(); + ConfigFileGroup configFileGroup = new ConfigFileGroup(); + String customGroup = "group1"; + configFileGroup.setName(customGroup); + String customFile1 = "file1.properties"; + String customFile2 = "file2.properties"; + configFileGroup.setFiles(Lists.newArrayList(customFile1, customFile2)); + customFiles.add(configFileGroup); + + when(polarisConfigProperties.getGroups()).thenReturn(customFiles); + when(environment.getActiveProfiles()).thenReturn(new String[] {}); + + // file1.properties + Map file1Map = new HashMap<>(); + file1Map.put("k1", "v1"); + file1Map.put("k2", "v2"); + ConfigKVFile file1 = new MockedConfigKVFile(file1Map); + when(configFileService.getConfigPropertiesFile(testNamespace, customGroup, customFile1)).thenReturn(file1); + + // file2.properties + Map file2Map = new HashMap<>(); + file2Map.put("k1", "v11"); + file2Map.put("k3", "v3"); + ConfigKVFile file2 = new MockedConfigKVFile(file2Map); + when(configFileService.getConfigPropertiesFile(testNamespace, customGroup, customFile2)).thenReturn(file2); + + PropertySource propertySource = locator.locate(environment); + + Assert.assertEquals("v1", propertySource.getProperty("k1")); + Assert.assertEquals("v2", propertySource.getProperty("k2")); + Assert.assertEquals("v3", propertySource.getProperty("k3")); + } +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertiesSourceAutoRefresherTest.java b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertiesSourceAutoRefresherTest.java new file mode 100644 index 000000000..648860f35 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertiesSourceAutoRefresherTest.java @@ -0,0 +1,122 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + */ + +package com.tencent.cloud.polaris.config.adapter; + +import java.util.HashMap; +import java.util.Map; + +import com.google.common.collect.Lists; +import com.tencent.cloud.polaris.config.config.PolarisConfigProperties; +import com.tencent.polaris.configuration.api.core.ChangeType; +import com.tencent.polaris.configuration.api.core.ConfigKVFileChangeEvent; +import com.tencent.polaris.configuration.api.core.ConfigPropertyChangeInfo; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import org.springframework.cloud.context.refresh.ContextRefresher; + +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** + * test for {@link PolarisPropertySourceAutoRefresher} + *@author lepdou 2022-06-11 + */ +@RunWith(MockitoJUnitRunner.class) +public class PolarisPropertiesSourceAutoRefresherTest { + + @Mock + private PolarisConfigProperties polarisConfigProperties; + @Mock + private PolarisPropertySourceManager polarisPropertySourceManager; + @Mock + private ContextRefresher contextRefresher; + + private final String testNamespace = "testNamespace"; + private final String testServiceName = "testServiceName"; + private final String testFileName = "application.properties"; + + @Test + public void testConfigFileChanged() { + PolarisPropertySourceAutoRefresher refresher = new PolarisPropertySourceAutoRefresher(polarisConfigProperties, + polarisPropertySourceManager, contextRefresher); + + when(polarisConfigProperties.isAutoRefresh()).thenReturn(true); + + Map content = new HashMap<>(); + content.put("k1", "v1"); + content.put("k2", "v2"); + content.put("k3", "v3"); + MockedConfigKVFile file = new MockedConfigKVFile(content); + PolarisPropertySource polarisPropertySource = new PolarisPropertySource(testNamespace, testServiceName, testFileName, + file, content); + + when(polarisPropertySourceManager.getAllPropertySources()).thenReturn(Lists.newArrayList(polarisPropertySource)); + + ConfigPropertyChangeInfo changeInfo = new ConfigPropertyChangeInfo("k1", "v1", "v11", ChangeType.MODIFIED); + ConfigPropertyChangeInfo changeInfo2 = new ConfigPropertyChangeInfo("k4", null, "v4", ChangeType.ADDED); + ConfigPropertyChangeInfo changeInfo3 = new ConfigPropertyChangeInfo("k2", "v2", null, ChangeType.DELETED); + Map changeInfos = new HashMap<>(); + changeInfos.put("k1", changeInfo); + changeInfos.put("k2", changeInfo3); + changeInfos.put("k4", changeInfo2); + + ConfigKVFileChangeEvent event = new ConfigKVFileChangeEvent(changeInfos); + refresher.onApplicationEvent(null); + + file.fireChangeListener(event); + + Assert.assertEquals("v11", polarisPropertySource.getProperty("k1")); + Assert.assertEquals("v3", polarisPropertySource.getProperty("k3")); + Assert.assertNull(polarisPropertySource.getProperty("k2")); + Assert.assertEquals("v4", polarisPropertySource.getProperty("k4")); + verify(contextRefresher).refresh(); + } + + @Test + public void testNewConfigFile() { + PolarisPropertySourceAutoRefresher refresher = new PolarisPropertySourceAutoRefresher(polarisConfigProperties, + polarisPropertySourceManager, contextRefresher); + + when(polarisConfigProperties.isAutoRefresh()).thenReturn(true); + + Map emptyContent = new HashMap<>(); + MockedConfigKVFile file = new MockedConfigKVFile(emptyContent); + PolarisPropertySource polarisPropertySource = new PolarisPropertySource(testNamespace, testServiceName, testFileName, + file, emptyContent); + + when(polarisPropertySourceManager.getAllPropertySources()).thenReturn(Lists.newArrayList(polarisPropertySource)); + + ConfigPropertyChangeInfo changeInfo = new ConfigPropertyChangeInfo("k1", null, "v1", ChangeType.ADDED); + Map changeInfos = new HashMap<>(); + changeInfos.put("k1", changeInfo); + + ConfigKVFileChangeEvent event = new ConfigKVFileChangeEvent(changeInfos); + refresher.onApplicationEvent(null); + + file.fireChangeListener(event); + + Assert.assertEquals("v1", polarisPropertySource.getProperty("k1")); + verify(contextRefresher).refresh(); + } + +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/listener/ConfigChangeListenerTest.java b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/listener/ConfigChangeListenerTest.java new file mode 100644 index 000000000..f3f70b4bc --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/listener/ConfigChangeListenerTest.java @@ -0,0 +1,124 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + */ + +package com.tencent.cloud.polaris.config.listener; + +import com.google.common.collect.Sets; +import com.tencent.cloud.polaris.config.annotation.PolarisConfigKVFileChangeListener; +import com.tencent.polaris.configuration.api.core.ConfigPropertyChangeInfo; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.cloud.context.environment.EnvironmentChangeEvent; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.stereotype.Component; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.DEFINED_PORT; + +/** + * Integration testing for change listener. + *@author lepdou 2022-06-11 + */ +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = DEFINED_PORT, + classes = ConfigChangeListenerTest.TestApplication.class, + properties = {"server.port=8081", + "spring.config.location = classpath:application-test.yml"}) +public class ConfigChangeListenerTest { + + @Autowired + private ApplicationEventPublisher applicationEventPublisher; + @Autowired + private ConfigurableApplicationContext applicationContext; + @Autowired + private TestApplication.TestConfig testConfig; + + @Test + public void test() throws InterruptedException { + //before change + Assert.assertEquals(1000, testConfig.getTimeout()); + + //submit change event + System.setProperty("timeout", "2000"); + EnvironmentChangeEvent event = new EnvironmentChangeEvent(applicationContext, + Sets.newHashSet("timeout")); + + applicationEventPublisher.publishEvent(event); + + //after change + Assert.assertEquals(2, testConfig.getChangeCnt()); + Assert.assertEquals(2000, testConfig.getTimeout()); + } + + + @SpringBootApplication + protected static class TestApplication { + + @Component + protected static class TestConfig { + + @Value("${timeout:1000}") + private int timeout; + + private int changeCnt; + + public int getTimeout() { + return timeout; + } + + public void setTimeout(int timeout) { + this.timeout = timeout; + } + + public int getChangeCnt() { + return changeCnt; + } + + @PolarisConfigKVFileChangeListener(interestedKeys = {"timeout"}) + public void configChangedListener(ConfigChangeEvent event) { + ConfigPropertyChangeInfo changeInfo = event.getChange("timeout"); + timeout = Integer.parseInt(changeInfo.getNewValue()); + changeCnt++; + } + + @PolarisConfigKVFileChangeListener(interestedKeyPrefixes = {"timeout"}) + public void configChangedListener2(ConfigChangeEvent event) { + ConfigPropertyChangeInfo changeInfo = event.getChange("timeout"); + timeout = Integer.parseInt(changeInfo.getNewValue()); + changeCnt++; + } + } + + @Component + protected static class EventPublisher implements ApplicationEventPublisher { + + @Override + public void publishEvent(Object o) { + + } + } + } + +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/test/resources/application-test.yml b/spring-cloud-starter-tencent-polaris-config/src/test/resources/application-test.yml new file mode 100644 index 000000000..c90d1340b --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/test/resources/application-test.yml @@ -0,0 +1,9 @@ +spring: + application: + name: test + cloud: + polaris: + address: grpc://127.0.0.1:8091 + namespace: default + config: + connect-remote-server: false diff --git a/spring-cloud-tencent-coverage/pom.xml b/spring-cloud-tencent-coverage/pom.xml index 1c8ba0ed4..37903c143 100644 --- a/spring-cloud-tencent-coverage/pom.xml +++ b/spring-cloud-tencent-coverage/pom.xml @@ -24,6 +24,16 @@ spring-cloud-tencent-commons + + com.tencent.cloud + spring-cloud-tencent-polaris-context + + + + com.tencent.cloud + spring-cloud-tencent-polaris-loadbalancer + + com.tencent.cloud spring-cloud-starter-tencent-polaris-discovery @@ -49,10 +59,10 @@ spring-cloud-starter-tencent-polaris-router - - com.tencent.cloud - spring-cloud-tencent-polaris-context - + + com.tencent.cloud + spring-cloud-starter-tencent-polaris-config + @@ -75,4 +85,4 @@ - \ No newline at end of file + From 68620d9f8fbd86d6660ed36922a52914c53c705b Mon Sep 17 00:00:00 2001 From: lepdou Date: Tue, 14 Jun 2022 18:01:04 +0800 Subject: [PATCH 3/6] support spring cloud gateway routers (#230) --- CHANGELOG.md | 1 + .../pom.xml | 6 + .../PolarisLoadBalancerBeanPostProcessor.java | 24 ++- .../PolarisLoadBalancerCompositeRule.java | 6 +- .../router/config/FeignAutoConfiguration.java | 58 ++++++ ...va => FeignLoadBalancerConfiguration.java} | 7 +- .../router/config/RibbonConfiguration.java | 7 +- .../config/RouterAutoConfiguration.java | 29 +-- .../PolarisMetadataRouterProperties.java | 2 +- .../PolarisNearByRouterProperties.java | 2 +- .../PolarisRuleBasedRouterProperties.java | 2 +- .../scg/PolarisLoadBalancerClientFilter.java | 144 +++++++++++++ .../router/spi/RouterLabelResolver.java | 9 + .../main/resources/META-INF/spring.factories | 3 +- .../PolarisLoadBalancerCompositeRuleTest.java | 6 +- ...arisLoadBalancerBeanPostProcessorTest.java | 1 + .../PolarisLoadBalancerClientFilterTest.java | 192 ++++++++++++++++++ .../src/main/resources/bootstrap.yml | 4 + .../gateway-callee-service2/pom.xml | 26 +++ .../callee/GatewayCalleeApplication2.java | 35 ++++ .../callee/GatewayCalleeController.java | 71 +++++++ .../src/main/resources/bootstrap.yml | 14 ++ .../gateway-scg-service/pom.xml | 4 +- .../src/main/resources/bootstrap.yml | 20 +- .../example/CustomRouterLabelResolver.java | 6 + 25 files changed, 622 insertions(+), 57 deletions(-) rename spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/{resttemplate => }/PolarisLoadBalancerBeanPostProcessor.java (64%) create mode 100644 spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/FeignAutoConfiguration.java rename spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/{FeignConfiguration.java => FeignLoadBalancerConfiguration.java} (87%) rename spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/{ => properties}/PolarisMetadataRouterProperties.java (95%) rename spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/{ => properties}/PolarisNearByRouterProperties.java (95%) rename spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/{ => properties}/PolarisRuleBasedRouterProperties.java (95%) create mode 100644 spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/scg/PolarisLoadBalancerClientFilter.java create mode 100644 spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/scg/PolarisLoadBalancerClientFilterTest.java create mode 100644 spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service2/pom.xml create mode 100644 spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service2/src/main/java/com/tencent/cloud/polaris/gateway/example/callee/GatewayCalleeApplication2.java create mode 100644 spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service2/src/main/java/com/tencent/cloud/polaris/gateway/example/callee/GatewayCalleeController.java create mode 100644 spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service2/src/main/resources/bootstrap.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index c4a5a2b38..fe9ef2c3f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,3 +2,4 @@ --- [Feature: Add config change listener feature support](https://github.com/Tencent/spring-cloud-tencent/pull/220) +[Feature: Support spring cloud gateway routers](https://github.com/Tencent/spring-cloud-tencent/pull/230) diff --git a/spring-cloud-starter-tencent-polaris-router/pom.xml b/spring-cloud-starter-tencent-polaris-router/pom.xml index 91e482abb..1424f98b5 100644 --- a/spring-cloud-starter-tencent-polaris-router/pom.xml +++ b/spring-cloud-starter-tencent-polaris-router/pom.xml @@ -52,6 +52,12 @@ true + + org.springframework.cloud + spring-cloud-gateway-server + true + + org.springframework.boot spring-boot-starter-test diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerBeanPostProcessor.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/PolarisLoadBalancerBeanPostProcessor.java similarity index 64% rename from spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerBeanPostProcessor.java rename to spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/PolarisLoadBalancerBeanPostProcessor.java index 5bafbd9fb..33ad50073 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerBeanPostProcessor.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/PolarisLoadBalancerBeanPostProcessor.java @@ -16,13 +16,14 @@ * */ -package com.tencent.cloud.polaris.router.resttemplate; +package com.tencent.cloud.polaris.router; import java.util.List; import com.tencent.cloud.common.metadata.config.MetadataLocalProperties; import com.tencent.cloud.common.util.BeanFactoryUtils; -import com.tencent.cloud.polaris.router.RouterRuleLabelResolver; +import com.tencent.cloud.polaris.router.resttemplate.PolarisLoadBalancerInterceptor; +import com.tencent.cloud.polaris.router.scg.PolarisLoadBalancerClientFilter; import com.tencent.cloud.polaris.router.spi.RouterLabelResolver; import org.springframework.beans.BeansException; @@ -32,11 +33,14 @@ import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; import org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor; import org.springframework.cloud.client.loadbalancer.LoadBalancerRequestFactory; +import org.springframework.cloud.gateway.config.LoadBalancerProperties; +import org.springframework.cloud.gateway.filter.LoadBalancerClientFilter; /** * Replace LoadBalancerInterceptor with PolarisLoadBalancerInterceptor. * PolarisLoadBalancerInterceptor can pass routing context information. - * + *
+ * Replace LoadBalancerClientFilter with PolarisLoadBalancerClientFilter. *@author lepdou 2022-05-18 */ public class PolarisLoadBalancerBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware { @@ -51,6 +55,8 @@ public class PolarisLoadBalancerBeanPostProcessor implements BeanPostProcessor, @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof LoadBalancerInterceptor) { + // Support rest template router. + // Replaces the default LoadBalancerInterceptor implementation and returns a custom PolarisLoadBalancerInterceptor LoadBalancerRequestFactory requestFactory = this.factory.getBean(LoadBalancerRequestFactory.class); LoadBalancerClient loadBalancerClient = this.factory.getBean(LoadBalancerClient.class); List routerLabelResolvers = BeanFactoryUtils.getBeans(factory, RouterLabelResolver.class); @@ -60,6 +66,18 @@ public class PolarisLoadBalancerBeanPostProcessor implements BeanPostProcessor, return new PolarisLoadBalancerInterceptor(loadBalancerClient, requestFactory, routerLabelResolvers, metadataLocalProperties, routerRuleLabelResolver); } + else if (bean instanceof LoadBalancerClientFilter) { + // Support spring cloud gateway router. + // Replaces the default LoadBalancerClientFilter implementation and returns a custom PolarisLoadBalancerClientFilter + LoadBalancerClient loadBalancerClient = this.factory.getBean(LoadBalancerClient.class); + LoadBalancerProperties loadBalancerProperties = this.factory.getBean(LoadBalancerProperties.class); + List routerLabelResolvers = BeanFactoryUtils.getBeans(factory, RouterLabelResolver.class); + MetadataLocalProperties metadataLocalProperties = this.factory.getBean(MetadataLocalProperties.class); + RouterRuleLabelResolver routerRuleLabelResolver = this.factory.getBean(RouterRuleLabelResolver.class); + + return new PolarisLoadBalancerClientFilter(loadBalancerClient, loadBalancerProperties, + metadataLocalProperties, routerRuleLabelResolver, routerLabelResolvers); + } return bean; } } diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/PolarisLoadBalancerCompositeRule.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/PolarisLoadBalancerCompositeRule.java index 4b9dc5900..4be83e682 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/PolarisLoadBalancerCompositeRule.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/PolarisLoadBalancerCompositeRule.java @@ -40,9 +40,9 @@ import com.tencent.cloud.common.pojo.PolarisServer; import com.tencent.cloud.polaris.loadbalancer.LoadBalancerUtils; import com.tencent.cloud.polaris.loadbalancer.PolarisWeightedRule; import com.tencent.cloud.polaris.loadbalancer.config.PolarisLoadBalancerProperties; -import com.tencent.cloud.polaris.router.config.PolarisMetadataRouterProperties; -import com.tencent.cloud.polaris.router.config.PolarisNearByRouterProperties; -import com.tencent.cloud.polaris.router.config.PolarisRuleBasedRouterProperties; +import com.tencent.cloud.polaris.router.config.properties.PolarisMetadataRouterProperties; +import com.tencent.cloud.polaris.router.config.properties.PolarisNearByRouterProperties; +import com.tencent.cloud.polaris.router.config.properties.PolarisRuleBasedRouterProperties; import com.tencent.polaris.api.pojo.Instance; import com.tencent.polaris.api.pojo.ServiceInfo; import com.tencent.polaris.api.pojo.ServiceInstances; diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/FeignAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/FeignAutoConfiguration.java new file mode 100644 index 000000000..5b87668ea --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/FeignAutoConfiguration.java @@ -0,0 +1,58 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + */ + +package com.tencent.cloud.polaris.router.config; + +import java.util.List; + +import com.tencent.cloud.common.metadata.config.MetadataLocalProperties; +import com.tencent.cloud.polaris.router.RouterRuleLabelResolver; +import com.tencent.cloud.polaris.router.feign.PolarisCachingSpringLoadBalanceFactory; +import com.tencent.cloud.polaris.router.feign.RouterLabelFeignInterceptor; +import com.tencent.cloud.polaris.router.spi.RouterLabelResolver; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.cloud.netflix.ribbon.RibbonClients; +import org.springframework.cloud.netflix.ribbon.SpringClientFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.lang.Nullable; + +/** + * configuration for feign singleton components. + * Feign-related components need to be loaded only in the feign environment. + *@author lepdou 2022-06-10 + */ +@Configuration +@ConditionalOnClass(name = {"org.springframework.cloud.openfeign.ribbon.FeignLoadBalancer"}) +@RibbonClients(defaultConfiguration = {FeignLoadBalancerConfiguration.class}) +public class FeignAutoConfiguration { + + @Bean + public RouterLabelFeignInterceptor routerLabelInterceptor(@Nullable List routerLabelResolvers, + MetadataLocalProperties metadataLocalProperties, + RouterRuleLabelResolver routerRuleLabelResolver) { + return new RouterLabelFeignInterceptor(routerLabelResolvers, metadataLocalProperties, routerRuleLabelResolver); + } + + @Bean + public PolarisCachingSpringLoadBalanceFactory polarisCachingSpringLoadBalanceFactory(SpringClientFactory factory) { + return new PolarisCachingSpringLoadBalanceFactory(factory); + } + +} diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/FeignConfiguration.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/FeignLoadBalancerConfiguration.java similarity index 87% rename from spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/FeignConfiguration.java rename to spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/FeignLoadBalancerConfiguration.java index d5d22444e..e6368cc85 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/FeignConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/FeignLoadBalancerConfiguration.java @@ -25,15 +25,12 @@ import com.tencent.cloud.polaris.router.feign.PolarisFeignLoadBalancer; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.cloud.netflix.ribbon.ServerIntrospector; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; /** - * configuration for feign component. - * + * configuration for feign load balance components. PolarisFeignLoadBalancer is not singleton bean, Each service corresponds to a PolarisFeignLoadBalancer. *@author lepdou 2022-05-16 */ -@Configuration -public class FeignConfiguration { +public class FeignLoadBalancerConfiguration { @Bean @ConditionalOnMissingBean diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/RibbonConfiguration.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/RibbonConfiguration.java index b9c60fbfb..9bc17b276 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/RibbonConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/RibbonConfiguration.java @@ -22,16 +22,17 @@ import com.netflix.client.config.IClientConfig; import com.netflix.loadbalancer.IRule; import com.tencent.cloud.polaris.loadbalancer.config.PolarisLoadBalancerProperties; import com.tencent.cloud.polaris.router.PolarisLoadBalancerCompositeRule; +import com.tencent.cloud.polaris.router.config.properties.PolarisMetadataRouterProperties; +import com.tencent.cloud.polaris.router.config.properties.PolarisNearByRouterProperties; +import com.tencent.cloud.polaris.router.config.properties.PolarisRuleBasedRouterProperties; import com.tencent.polaris.router.api.core.RouterAPI; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; /** - * Auto configuration for ribbon components. + * Configuration for ribbon components. IRule is not singleton bean, Each service corresponds to an IRule. * @author lepdou 2022-05-17 */ -@Configuration public class RibbonConfiguration { @Bean diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/RouterAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/RouterAutoConfiguration.java index 6d274bc1c..e92b0f45d 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/RouterAutoConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/RouterAutoConfiguration.java @@ -18,48 +18,31 @@ package com.tencent.cloud.polaris.router.config; -import java.util.List; - -import com.tencent.cloud.common.metadata.config.MetadataLocalProperties; import com.tencent.cloud.polaris.context.ServiceRuleManager; +import com.tencent.cloud.polaris.router.PolarisLoadBalancerBeanPostProcessor; import com.tencent.cloud.polaris.router.RouterRuleLabelResolver; -import com.tencent.cloud.polaris.router.feign.PolarisCachingSpringLoadBalanceFactory; -import com.tencent.cloud.polaris.router.feign.RouterLabelFeignInterceptor; -import com.tencent.cloud.polaris.router.resttemplate.PolarisLoadBalancerBeanPostProcessor; -import com.tencent.cloud.polaris.router.spi.RouterLabelResolver; +import com.tencent.cloud.polaris.router.config.properties.PolarisMetadataRouterProperties; +import com.tencent.cloud.polaris.router.config.properties.PolarisNearByRouterProperties; +import com.tencent.cloud.polaris.router.config.properties.PolarisRuleBasedRouterProperties; import org.springframework.cloud.netflix.ribbon.RibbonClients; -import org.springframework.cloud.netflix.ribbon.SpringClientFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.core.annotation.Order; -import org.springframework.lang.Nullable; import static org.springframework.core.Ordered.HIGHEST_PRECEDENCE; /** - * router module auto configuration. + * configuration for router module singleton beans. * *@author lepdou 2022-05-11 */ @Configuration -@RibbonClients(defaultConfiguration = {FeignConfiguration.class, RibbonConfiguration.class}) +@RibbonClients(defaultConfiguration = {RibbonConfiguration.class}) @Import({PolarisNearByRouterProperties.class, PolarisMetadataRouterProperties.class, PolarisRuleBasedRouterProperties.class}) public class RouterAutoConfiguration { - @Bean - public RouterLabelFeignInterceptor routerLabelInterceptor(@Nullable List routerLabelResolvers, - MetadataLocalProperties metadataLocalProperties, - RouterRuleLabelResolver routerRuleLabelResolver) { - return new RouterLabelFeignInterceptor(routerLabelResolvers, metadataLocalProperties, routerRuleLabelResolver); - } - - @Bean - public PolarisCachingSpringLoadBalanceFactory polarisCachingSpringLoadBalanceFactory(SpringClientFactory factory) { - return new PolarisCachingSpringLoadBalanceFactory(factory); - } - @Bean @Order(HIGHEST_PRECEDENCE) public PolarisLoadBalancerBeanPostProcessor polarisLoadBalancerBeanPostProcessor() { diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/PolarisMetadataRouterProperties.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/PolarisMetadataRouterProperties.java similarity index 95% rename from spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/PolarisMetadataRouterProperties.java rename to spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/PolarisMetadataRouterProperties.java index 4a20e53f6..70ded3a8c 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/PolarisMetadataRouterProperties.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/PolarisMetadataRouterProperties.java @@ -16,7 +16,7 @@ * */ -package com.tencent.cloud.polaris.router.config; +package com.tencent.cloud.polaris.router.config.properties; import org.springframework.boot.context.properties.ConfigurationProperties; diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/PolarisNearByRouterProperties.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/PolarisNearByRouterProperties.java similarity index 95% rename from spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/PolarisNearByRouterProperties.java rename to spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/PolarisNearByRouterProperties.java index 3467b0587..3cd69ca12 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/PolarisNearByRouterProperties.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/PolarisNearByRouterProperties.java @@ -16,7 +16,7 @@ * */ -package com.tencent.cloud.polaris.router.config; +package com.tencent.cloud.polaris.router.config.properties; import org.springframework.boot.context.properties.ConfigurationProperties; diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/PolarisRuleBasedRouterProperties.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/PolarisRuleBasedRouterProperties.java similarity index 95% rename from spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/PolarisRuleBasedRouterProperties.java rename to spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/PolarisRuleBasedRouterProperties.java index 89b4bead5..67a17975f 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/PolarisRuleBasedRouterProperties.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/properties/PolarisRuleBasedRouterProperties.java @@ -16,7 +16,7 @@ * */ -package com.tencent.cloud.polaris.router.config; +package com.tencent.cloud.polaris.router.config.properties; import org.springframework.boot.context.properties.ConfigurationProperties; diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/scg/PolarisLoadBalancerClientFilter.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/scg/PolarisLoadBalancerClientFilter.java new file mode 100644 index 000000000..35de57737 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/scg/PolarisLoadBalancerClientFilter.java @@ -0,0 +1,144 @@ +/* + * 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.scg; + +import java.net.URI; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.common.metadata.MetadataContextHolder; +import com.tencent.cloud.common.metadata.config.MetadataLocalProperties; +import com.tencent.cloud.common.util.ExpressionLabelUtils; +import com.tencent.cloud.polaris.router.PolarisRouterContext; +import com.tencent.cloud.polaris.router.RouterRuleLabelResolver; +import com.tencent.cloud.polaris.router.spi.RouterLabelResolver; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; +import org.springframework.cloud.gateway.config.LoadBalancerProperties; +import org.springframework.cloud.gateway.filter.LoadBalancerClientFilter; +import org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient; +import org.springframework.core.Ordered; +import org.springframework.util.CollectionUtils; +import org.springframework.web.server.ServerWebExchange; + +import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR; + +/** + * Replaces the default LoadBalancerClientFilter implementation. + *@author lepdou 2022-06-10 + */ +public class PolarisLoadBalancerClientFilter extends LoadBalancerClientFilter { + private final static Logger LOGGER = LoggerFactory.getLogger(PolarisLoadBalancerClientFilter.class); + + private final MetadataLocalProperties metadataLocalProperties; + private final RouterRuleLabelResolver routerRuleLabelResolver; + private final List routerLabelResolvers; + + private final boolean isRibbonLoadBalanceClient; + + public PolarisLoadBalancerClientFilter(LoadBalancerClient loadBalancer, LoadBalancerProperties properties, + MetadataLocalProperties metadataLocalProperties, + RouterRuleLabelResolver routerRuleLabelResolver, + List routerLabelResolvers) { + super(loadBalancer, properties); + this.metadataLocalProperties = metadataLocalProperties; + this.routerRuleLabelResolver = routerRuleLabelResolver; + + if (!CollectionUtils.isEmpty(routerLabelResolvers)) { + routerLabelResolvers.sort(Comparator.comparingInt(Ordered::getOrder)); + this.routerLabelResolvers = routerLabelResolvers; + } + else { + this.routerLabelResolvers = null; + } + + this.isRibbonLoadBalanceClient = loadBalancer instanceof RibbonLoadBalancerClient; + } + + @Override + protected ServiceInstance choose(ServerWebExchange exchange) { + String peerServiceName = ((URI) exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR)).getHost(); + + if (isRibbonLoadBalanceClient) { + // Pass routing context to ribbon load balancer + PolarisRouterContext routerContext = genRouterContext(exchange, peerServiceName); + return ((RibbonLoadBalancerClient) loadBalancer).choose(peerServiceName, routerContext); + } + else { + return loadBalancer.choose(peerServiceName); + } + } + + PolarisRouterContext genRouterContext(ServerWebExchange exchange, String peerServiceName) { + // local service labels + Map labels = new HashMap<>(metadataLocalProperties.getContent()); + + // labels from rule expression + Map ruleExpressionLabels = getExpressionLabels(exchange, peerServiceName); + if (!CollectionUtils.isEmpty(ruleExpressionLabels)) { + labels.putAll(ruleExpressionLabels); + } + + // labels from request + if (!CollectionUtils.isEmpty(routerLabelResolvers)) { + routerLabelResolvers.forEach(resolver -> { + try { + Map customResolvedLabels = resolver.resolve(exchange); + if (!CollectionUtils.isEmpty(customResolvedLabels)) { + labels.putAll(customResolvedLabels); + } + } + catch (Throwable t) { + LOGGER.error("[SCT][Router] revoke RouterLabelResolver occur some exception. ", t); + } + }); + } + + // labels from downstream + Map transitiveLabels = MetadataContextHolder.get() + .getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE); + labels.putAll(transitiveLabels); + + PolarisRouterContext routerContext = new PolarisRouterContext(); + + routerContext.setLabels(PolarisRouterContext.RULE_ROUTER_LABELS, labels); + routerContext.setLabels(PolarisRouterContext.TRANSITIVE_LABELS, transitiveLabels); + + return routerContext; + } + + private Map getExpressionLabels(ServerWebExchange exchange, String peerServiceName) { + Set labelKeys = routerRuleLabelResolver.getExpressionLabelKeys(MetadataContext.LOCAL_NAMESPACE, + MetadataContext.LOCAL_SERVICE, peerServiceName); + + if (CollectionUtils.isEmpty(labelKeys)) { + return Collections.emptyMap(); + } + + return ExpressionLabelUtils.resolve(exchange, labelKeys); + } +} diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/spi/RouterLabelResolver.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/spi/RouterLabelResolver.java index 49b9ccf4c..44dbbb471 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/spi/RouterLabelResolver.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/spi/RouterLabelResolver.java @@ -24,6 +24,7 @@ import feign.RequestTemplate; import org.springframework.core.Ordered; import org.springframework.http.HttpRequest; +import org.springframework.web.server.ServerWebExchange; /** * The spi for resolving labels from request. @@ -46,4 +47,12 @@ public interface RouterLabelResolver extends Ordered { * @return resolved labels */ Map resolve(HttpRequest request, byte[] body); + + + /** + * resolve labels from server web exchange. + * @param exchange the server web exchange. + * @return resolved labels + */ + Map resolve(ServerWebExchange exchange); } diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/resources/META-INF/spring.factories b/spring-cloud-starter-tencent-polaris-router/src/main/resources/META-INF/spring.factories index d33dcea7f..3b20deb56 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-starter-tencent-polaris-router/src/main/resources/META-INF/spring.factories @@ -1,2 +1,3 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ - com.tencent.cloud.polaris.router.config.RouterAutoConfiguration + com.tencent.cloud.polaris.router.config.RouterAutoConfiguration,\ + com.tencent.cloud.polaris.router.config.FeignAutoConfiguration diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/PolarisLoadBalancerCompositeRuleTest.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/PolarisLoadBalancerCompositeRuleTest.java index 1eccb542c..0d55e9cde 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/PolarisLoadBalancerCompositeRuleTest.java +++ b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/PolarisLoadBalancerCompositeRuleTest.java @@ -41,9 +41,9 @@ import com.tencent.cloud.common.pojo.PolarisServer; import com.tencent.cloud.common.util.ApplicationContextAwareUtils; import com.tencent.cloud.polaris.loadbalancer.PolarisWeightedRule; import com.tencent.cloud.polaris.loadbalancer.config.PolarisLoadBalancerProperties; -import com.tencent.cloud.polaris.router.config.PolarisMetadataRouterProperties; -import com.tencent.cloud.polaris.router.config.PolarisNearByRouterProperties; -import com.tencent.cloud.polaris.router.config.PolarisRuleBasedRouterProperties; +import com.tencent.cloud.polaris.router.config.properties.PolarisMetadataRouterProperties; +import com.tencent.cloud.polaris.router.config.properties.PolarisNearByRouterProperties; +import com.tencent.cloud.polaris.router.config.properties.PolarisRuleBasedRouterProperties; import com.tencent.polaris.api.pojo.DefaultInstance; import com.tencent.polaris.api.pojo.DefaultServiceInstances; import com.tencent.polaris.api.pojo.Instance; diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerBeanPostProcessorTest.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerBeanPostProcessorTest.java index e335e83fa..cfcfa5877 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerBeanPostProcessorTest.java +++ b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerBeanPostProcessorTest.java @@ -20,6 +20,7 @@ package com.tencent.cloud.polaris.router.resttemplate; import com.tencent.cloud.common.metadata.config.MetadataLocalProperties; import com.tencent.cloud.common.util.BeanFactoryUtils; +import com.tencent.cloud.polaris.router.PolarisLoadBalancerBeanPostProcessor; import com.tencent.cloud.polaris.router.RouterRuleLabelResolver; import com.tencent.cloud.polaris.router.spi.RouterLabelResolver; import org.junit.Assert; diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/scg/PolarisLoadBalancerClientFilterTest.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/scg/PolarisLoadBalancerClientFilterTest.java new file mode 100644 index 000000000..6010689af --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/scg/PolarisLoadBalancerClientFilterTest.java @@ -0,0 +1,192 @@ +/* + * 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.scg; + + +import java.net.URI; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import com.tencent.cloud.common.metadata.MetadataContext; +import com.tencent.cloud.common.metadata.MetadataContextHolder; +import com.tencent.cloud.common.metadata.config.MetadataLocalProperties; +import com.tencent.cloud.common.util.ApplicationContextAwareUtils; +import com.tencent.cloud.polaris.router.PolarisRouterContext; +import com.tencent.cloud.polaris.router.RouterRuleLabelResolver; +import com.tencent.cloud.polaris.router.spi.RouterLabelResolver; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; + +import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; +import org.springframework.cloud.gateway.config.LoadBalancerProperties; +import org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient; +import org.springframework.mock.http.server.reactive.MockServerHttpRequest; +import org.springframework.mock.web.server.MockServerWebExchange; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR; + +/** + * test for ${@link PolarisLoadBalancerClientFilter} + *@author lepdou 2022-06-13 + */ +@RunWith(MockitoJUnitRunner.class) +public class PolarisLoadBalancerClientFilterTest { + + @Mock + private MetadataLocalProperties metadataLocalProperties; + @Mock + private RouterRuleLabelResolver routerRuleLabelResolver; + @Mock + private RouterLabelResolver routerLabelResolver; + @Mock + private LoadBalancerClient loadBalancerClient; + @Mock + private LoadBalancerProperties loadBalancerProperties; + + private static final String callerService = "callerService"; + private static final String calleeService = "calleeService"; + + private static MockedStatic mockedApplicationContextAwareUtils; + private static MockedStatic mockedMetadataContextHolder; + + @BeforeClass + public static void beforeClass() { + mockedApplicationContextAwareUtils = Mockito.mockStatic(ApplicationContextAwareUtils.class); + mockedApplicationContextAwareUtils.when(() -> ApplicationContextAwareUtils.getProperties(anyString())) + .thenReturn(callerService); + + MetadataContext metadataContext = Mockito.mock(MetadataContext.class); + + // mock transitive metadata + Map transitiveLabels = new HashMap<>(); + transitiveLabels.put("t1", "v1"); + transitiveLabels.put("t2", "v2"); + when(metadataContext.getFragmentContext(MetadataContext.FRAGMENT_TRANSITIVE)).thenReturn(transitiveLabels); + + mockedMetadataContextHolder = Mockito.mockStatic(MetadataContextHolder.class); + mockedMetadataContextHolder.when(MetadataContextHolder::get).thenReturn(metadataContext); + } + + @AfterClass + public static void afterClass() { + mockedApplicationContextAwareUtils.close(); + mockedMetadataContextHolder.close(); + } + + @Test + public void testGenRouterContext() { + PolarisLoadBalancerClientFilter polarisLoadBalancerClientFilter = new PolarisLoadBalancerClientFilter( + loadBalancerClient, loadBalancerProperties, metadataLocalProperties, routerRuleLabelResolver, + Lists.newArrayList(routerLabelResolver)); + + Map localMetadata = new HashMap<>(); + localMetadata.put("env", "blue"); + when(metadataLocalProperties.getContent()).thenReturn(localMetadata); + + Set expressionLabelKeys = Sets.newHashSet("${http.header.k1}", "${http.query.userid}"); + when(routerRuleLabelResolver.getExpressionLabelKeys(anyString(), anyString(), anyString())).thenReturn(expressionLabelKeys); + + MockServerHttpRequest request = MockServerHttpRequest.get("/" + calleeService + "/users") + .header("k1", "v1") + .queryParam("userid", "zhangsan") + .build(); + MockServerWebExchange webExchange = new MockServerWebExchange.Builder(request).build(); + + Map customMetadata = new HashMap<>(); + customMetadata.put("k2", "v2"); + when(routerLabelResolver.resolve(webExchange)).thenReturn(customMetadata); + + PolarisRouterContext routerContext = polarisLoadBalancerClientFilter.genRouterContext(webExchange, calleeService); + + Map routerLabels = routerContext.getLabels(PolarisRouterContext.RULE_ROUTER_LABELS); + Assert.assertEquals("v1", routerLabels.get("${http.header.k1}")); + Assert.assertEquals("zhangsan", routerLabels.get("${http.query.userid}")); + Assert.assertEquals("blue", routerLabels.get("env")); + Assert.assertEquals("v1", routerLabels.get("t1")); + Assert.assertEquals("v2", routerLabels.get("t2")); + } + + @Test + public void testChooseInstanceWithoutRibbon() { + PolarisLoadBalancerClientFilter polarisLoadBalancerClientFilter = new PolarisLoadBalancerClientFilter( + loadBalancerClient, loadBalancerProperties, metadataLocalProperties, routerRuleLabelResolver, + Lists.newArrayList(routerLabelResolver)); + + String url = "/" + calleeService + "/users"; + MockServerHttpRequest request = MockServerHttpRequest.get(url) + .header("k1", "v1") + .queryParam("userid", "zhangsan") + .build(); + MockServerWebExchange webExchange = new MockServerWebExchange.Builder(request).build(); + webExchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, URI.create("http://" + calleeService + "/users")); + + polarisLoadBalancerClientFilter.choose(webExchange); + + verify(loadBalancerClient).choose(calleeService); + verify(metadataLocalProperties, times(0)).getContent(); + } + + @Test + public void testChooseInstanceWithRibbon() { + RibbonLoadBalancerClient ribbonLoadBalancerClient = Mockito.mock(RibbonLoadBalancerClient.class); + + PolarisLoadBalancerClientFilter polarisLoadBalancerClientFilter = new PolarisLoadBalancerClientFilter( + ribbonLoadBalancerClient, loadBalancerProperties, metadataLocalProperties, routerRuleLabelResolver, + Lists.newArrayList(routerLabelResolver)); + + Map localMetadata = new HashMap<>(); + localMetadata.put("env", "blue"); + when(metadataLocalProperties.getContent()).thenReturn(localMetadata); + + Set expressionLabelKeys = Sets.newHashSet("${http.header.k1}", "${http.query.userid}"); + when(routerRuleLabelResolver.getExpressionLabelKeys(anyString(), anyString(), anyString())).thenReturn(expressionLabelKeys); + + String url = "/" + calleeService + "/users"; + MockServerHttpRequest request = MockServerHttpRequest.get(url) + .header("k1", "v1") + .queryParam("userid", "zhangsan") + .build(); + MockServerWebExchange webExchange = new MockServerWebExchange.Builder(request).build(); + webExchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, URI.create("http://" + calleeService + "/users")); + + Map customMetadata = new HashMap<>(); + customMetadata.put("k2", "v2"); + when(routerLabelResolver.resolve(webExchange)).thenReturn(customMetadata); + + polarisLoadBalancerClientFilter.choose(webExchange); + + verify(ribbonLoadBalancerClient).choose(anyString(), any()); + verify(metadataLocalProperties, times(1)).getContent(); + } +} diff --git a/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service/src/main/resources/bootstrap.yml index 2d0d75a41..c6d40440f 100644 --- a/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service/src/main/resources/bootstrap.yml +++ b/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service/src/main/resources/bootstrap.yml @@ -5,6 +5,10 @@ spring: application: name: GatewayCalleeService cloud: + tencent: + metadata: + content: + env: blue polaris: address: grpc://183.47.111.80:8091 namespace: default diff --git a/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service2/pom.xml b/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service2/pom.xml new file mode 100644 index 000000000..6454f43d7 --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service2/pom.xml @@ -0,0 +1,26 @@ + + + + polaris-gateway-example + com.tencent.cloud + ${revision} + ../pom.xml + + 4.0.0 + + gateway-callee-service2 + + + + com.tencent.cloud + spring-cloud-starter-tencent-polaris-discovery + + + + org.springframework.boot + spring-boot-starter-web + + + diff --git a/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service2/src/main/java/com/tencent/cloud/polaris/gateway/example/callee/GatewayCalleeApplication2.java b/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service2/src/main/java/com/tencent/cloud/polaris/gateway/example/callee/GatewayCalleeApplication2.java new file mode 100644 index 000000000..5d261d56f --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service2/src/main/java/com/tencent/cloud/polaris/gateway/example/callee/GatewayCalleeApplication2.java @@ -0,0 +1,35 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ + +package com.tencent.cloud.polaris.gateway.example.callee; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * Gateway callee application. + * + * @author Haotian Zhang + */ +@SpringBootApplication +public class GatewayCalleeApplication2 { + + public static void main(String[] args) { + SpringApplication.run(GatewayCalleeApplication2.class, args); + } + +} diff --git a/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service2/src/main/java/com/tencent/cloud/polaris/gateway/example/callee/GatewayCalleeController.java b/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service2/src/main/java/com/tencent/cloud/polaris/gateway/example/callee/GatewayCalleeController.java new file mode 100644 index 000000000..40ddeb240 --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service2/src/main/java/com/tencent/cloud/polaris/gateway/example/callee/GatewayCalleeController.java @@ -0,0 +1,71 @@ +/* + * 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.gateway.example.callee; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; + +import com.tencent.cloud.common.constant.MetadataConstant; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * Gateway callee controller. + * + * @author Haotian Zhang + */ +@RestController +@RequestMapping("/gateway/example/callee") +public class GatewayCalleeController { + + private static Logger LOG = LoggerFactory.getLogger(GatewayCalleeController.class); + + @Value("${server.port:0}") + private int port; + + /** + * Get information of callee. + * @return information of callee + */ + @RequestMapping("/info") + public String info() { + LOG.info("Gateway Example Callee [{}] is called.", port); + return String.format("Gateway Example Callee [%s] is called.", port); + } + + /** + * Get metadata in HTTP header. + * + * @param metadataStr metadata string + * @return metadata in HTTP header + * @throws UnsupportedEncodingException encoding exception + */ + @RequestMapping("/echo") + public String echoHeader( + @RequestHeader(MetadataConstant.HeaderName.CUSTOM_METADATA) String metadataStr) + throws UnsupportedEncodingException { + LOG.info(URLDecoder.decode(metadataStr, "UTF-8")); + return URLDecoder.decode(metadataStr, "UTF-8"); + } + +} diff --git a/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service2/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service2/src/main/resources/bootstrap.yml new file mode 100644 index 000000000..a0cf12581 --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-gateway-example/gateway-callee-service2/src/main/resources/bootstrap.yml @@ -0,0 +1,14 @@ +server: + session-timeout: 1800 + port: 48082 +spring: + application: + name: GatewayCalleeService + cloud: + tencent: + metadata: + content: + env: green + polaris: + address: grpc://183.47.111.80:8091 + namespace: default diff --git a/spring-cloud-tencent-examples/polaris-gateway-example/gateway-scg-service/pom.xml b/spring-cloud-tencent-examples/polaris-gateway-example/gateway-scg-service/pom.xml index 5e02ccb43..755b04d63 100644 --- a/spring-cloud-tencent-examples/polaris-gateway-example/gateway-scg-service/pom.xml +++ b/spring-cloud-tencent-examples/polaris-gateway-example/gateway-scg-service/pom.xml @@ -26,7 +26,7 @@ com.tencent.cloud - spring-cloud-starter-tencent-metadata-transfer + spring-cloud-starter-tencent-polaris-router @@ -34,4 +34,4 @@ spring-cloud-starter-gateway - \ No newline at end of file + diff --git a/spring-cloud-tencent-examples/polaris-gateway-example/gateway-scg-service/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/polaris-gateway-example/gateway-scg-service/src/main/resources/bootstrap.yml index 5d949573b..f50100264 100644 --- a/spring-cloud-tencent-examples/polaris-gateway-example/gateway-scg-service/src/main/resources/bootstrap.yml +++ b/spring-cloud-tencent-examples/polaris-gateway-example/gateway-scg-service/src/main/resources/bootstrap.yml @@ -8,15 +8,13 @@ spring: tencent: metadata: content: - a: 1 + env: blue transitive: - - a + - env polaris: address: grpc://183.47.111.80:8091 namespace: default enabled: true - discovery: - service-list-refresh-interval: 1000 gateway: discovery: locator: @@ -52,13 +50,13 @@ spring: maxBackoff: '''500ms''' factor: 2 basedOnPreviousValue: false -# routes: -# - id: GatewayCalleeService -# uri: lb://GatewayCalleeService -# predicates: -# - Path=/GatewayCalleeService/** -# filters: -# - StripPrefix=1 + routes: + - id: GatewayCalleeService + uri: lb://GatewayCalleeService + predicates: + - Path=/GatewayCalleeService/** + filters: + - StripPrefix=1 logging: level: diff --git a/spring-cloud-tencent-examples/polaris-router-example/router-caller-service/src/main/java/com/tencent/cloud/polaris/router/example/CustomRouterLabelResolver.java b/spring-cloud-tencent-examples/polaris-router-example/router-caller-service/src/main/java/com/tencent/cloud/polaris/router/example/CustomRouterLabelResolver.java index bd289abb9..ea8c2ceb0 100644 --- a/spring-cloud-tencent-examples/polaris-router-example/router-caller-service/src/main/java/com/tencent/cloud/polaris/router/example/CustomRouterLabelResolver.java +++ b/spring-cloud-tencent-examples/polaris-router-example/router-caller-service/src/main/java/com/tencent/cloud/polaris/router/example/CustomRouterLabelResolver.java @@ -27,6 +27,7 @@ import feign.RequestTemplate; import org.springframework.http.HttpRequest; import org.springframework.stereotype.Component; +import org.springframework.web.server.ServerWebExchange; /** * @@ -58,6 +59,11 @@ public class CustomRouterLabelResolver implements RouterLabelResolver { return labels; } + @Override + public Map resolve(ServerWebExchange exchange) { + return null; + } + @Override public int getOrder() { return 0; From 80cc2882c60ff796b17d31dec6515be38ce5cca4 Mon Sep 17 00:00:00 2001 From: lepdou Date: Wed, 15 Jun 2022 20:38:35 +0800 Subject: [PATCH 4/6] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fe9ef2c3f..249fbfeeb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,5 @@ # Change Log --- - +[UT: Add config module unit test](https://github.com/Tencent/spring-cloud-tencent/pull/229) [Feature: Add config change listener feature support](https://github.com/Tencent/spring-cloud-tencent/pull/220) [Feature: Support spring cloud gateway routers](https://github.com/Tencent/spring-cloud-tencent/pull/230) From d49520dd115ea41402f7eed0bee19518b6d8f38d Mon Sep 17 00:00:00 2001 From: lepdou Date: Thu, 16 Jun 2022 11:40:11 +0800 Subject: [PATCH 5/6] fix guava version conflict bug & fix router strong dependency on LoadBalancerClientFilter (#236) --- CHANGELOG.md | 1 + ...BalancerClientFilterBeanPostProcessor.java | 66 +++++++++++++++++++ ...BalancerInterceptorBeanPostProcessor.java} | 22 +------ .../config/RouterAutoConfiguration.java | 18 ++++- ...arisLoadBalancerBeanPostProcessorTest.java | 8 +-- spring-cloud-tencent-dependencies/pom.xml | 22 +++++++ .../polaris-gateway-example/pom.xml | 3 +- 7 files changed, 113 insertions(+), 27 deletions(-) create mode 100644 spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/beanprocessor/LoadBalancerClientFilterBeanPostProcessor.java rename spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/{PolarisLoadBalancerBeanPostProcessor.java => beanprocessor/LoadBalancerInterceptorBeanPostProcessor.java} (67%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 249fbfeeb..f1dc5324b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,3 +3,4 @@ [UT: Add config module unit test](https://github.com/Tencent/spring-cloud-tencent/pull/229) [Feature: Add config change listener feature support](https://github.com/Tencent/spring-cloud-tencent/pull/220) [Feature: Support spring cloud gateway routers](https://github.com/Tencent/spring-cloud-tencent/pull/230) +[Bugfix: fix guava version conflict bug & fix router strong dependency on LoadBalancerClientFilter](https://github.com/Tencent/spring-cloud-tencent/pull/236) diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/beanprocessor/LoadBalancerClientFilterBeanPostProcessor.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/beanprocessor/LoadBalancerClientFilterBeanPostProcessor.java new file mode 100644 index 000000000..5111bda51 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/beanprocessor/LoadBalancerClientFilterBeanPostProcessor.java @@ -0,0 +1,66 @@ +/* + * 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.beanprocessor; + +import java.util.List; + +import com.tencent.cloud.common.metadata.config.MetadataLocalProperties; +import com.tencent.cloud.common.util.BeanFactoryUtils; +import com.tencent.cloud.polaris.router.RouterRuleLabelResolver; +import com.tencent.cloud.polaris.router.scg.PolarisLoadBalancerClientFilter; +import com.tencent.cloud.polaris.router.spi.RouterLabelResolver; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanFactoryAware; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; +import org.springframework.cloud.gateway.config.LoadBalancerProperties; +import org.springframework.cloud.gateway.filter.LoadBalancerClientFilter; + +/** + * Replace LoadBalancerClientFilter with PolarisLoadBalancerClientFilter. + *@author lepdou 2022-06-15 + */ +public class LoadBalancerClientFilterBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware { + + private BeanFactory factory; + + @Override + public void setBeanFactory(BeanFactory beanFactory) throws BeansException { + this.factory = beanFactory; + } + + @Override + public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { + if (bean instanceof LoadBalancerClientFilter) { + // Support spring cloud gateway router. + // Replaces the default LoadBalancerClientFilter implementation and returns a custom PolarisLoadBalancerClientFilter + LoadBalancerClient loadBalancerClient = this.factory.getBean(LoadBalancerClient.class); + LoadBalancerProperties loadBalancerProperties = this.factory.getBean(LoadBalancerProperties.class); + List routerLabelResolvers = BeanFactoryUtils.getBeans(factory, RouterLabelResolver.class); + MetadataLocalProperties metadataLocalProperties = this.factory.getBean(MetadataLocalProperties.class); + RouterRuleLabelResolver routerRuleLabelResolver = this.factory.getBean(RouterRuleLabelResolver.class); + + return new PolarisLoadBalancerClientFilter(loadBalancerClient, loadBalancerProperties, + metadataLocalProperties, routerRuleLabelResolver, routerLabelResolvers); + } + return bean; + } +} diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/PolarisLoadBalancerBeanPostProcessor.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/beanprocessor/LoadBalancerInterceptorBeanPostProcessor.java similarity index 67% rename from spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/PolarisLoadBalancerBeanPostProcessor.java rename to spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/beanprocessor/LoadBalancerInterceptorBeanPostProcessor.java index 33ad50073..0b383a682 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/PolarisLoadBalancerBeanPostProcessor.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/beanprocessor/LoadBalancerInterceptorBeanPostProcessor.java @@ -16,14 +16,14 @@ * */ -package com.tencent.cloud.polaris.router; +package com.tencent.cloud.polaris.router.beanprocessor; import java.util.List; import com.tencent.cloud.common.metadata.config.MetadataLocalProperties; import com.tencent.cloud.common.util.BeanFactoryUtils; +import com.tencent.cloud.polaris.router.RouterRuleLabelResolver; import com.tencent.cloud.polaris.router.resttemplate.PolarisLoadBalancerInterceptor; -import com.tencent.cloud.polaris.router.scg.PolarisLoadBalancerClientFilter; import com.tencent.cloud.polaris.router.spi.RouterLabelResolver; import org.springframework.beans.BeansException; @@ -33,17 +33,13 @@ import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; import org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor; import org.springframework.cloud.client.loadbalancer.LoadBalancerRequestFactory; -import org.springframework.cloud.gateway.config.LoadBalancerProperties; -import org.springframework.cloud.gateway.filter.LoadBalancerClientFilter; /** * Replace LoadBalancerInterceptor with PolarisLoadBalancerInterceptor. * PolarisLoadBalancerInterceptor can pass routing context information. - *
- * Replace LoadBalancerClientFilter with PolarisLoadBalancerClientFilter. *@author lepdou 2022-05-18 */ -public class PolarisLoadBalancerBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware { +public class LoadBalancerInterceptorBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware { private BeanFactory factory; @@ -66,18 +62,6 @@ public class PolarisLoadBalancerBeanPostProcessor implements BeanPostProcessor, return new PolarisLoadBalancerInterceptor(loadBalancerClient, requestFactory, routerLabelResolvers, metadataLocalProperties, routerRuleLabelResolver); } - else if (bean instanceof LoadBalancerClientFilter) { - // Support spring cloud gateway router. - // Replaces the default LoadBalancerClientFilter implementation and returns a custom PolarisLoadBalancerClientFilter - LoadBalancerClient loadBalancerClient = this.factory.getBean(LoadBalancerClient.class); - LoadBalancerProperties loadBalancerProperties = this.factory.getBean(LoadBalancerProperties.class); - List routerLabelResolvers = BeanFactoryUtils.getBeans(factory, RouterLabelResolver.class); - MetadataLocalProperties metadataLocalProperties = this.factory.getBean(MetadataLocalProperties.class); - RouterRuleLabelResolver routerRuleLabelResolver = this.factory.getBean(RouterRuleLabelResolver.class); - - return new PolarisLoadBalancerClientFilter(loadBalancerClient, loadBalancerProperties, - metadataLocalProperties, routerRuleLabelResolver, routerLabelResolvers); - } return bean; } } diff --git a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/RouterAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/RouterAutoConfiguration.java index e92b0f45d..a57c16857 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/RouterAutoConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-router/src/main/java/com/tencent/cloud/polaris/router/config/RouterAutoConfiguration.java @@ -19,12 +19,16 @@ package com.tencent.cloud.polaris.router.config; import com.tencent.cloud.polaris.context.ServiceRuleManager; -import com.tencent.cloud.polaris.router.PolarisLoadBalancerBeanPostProcessor; import com.tencent.cloud.polaris.router.RouterRuleLabelResolver; +import com.tencent.cloud.polaris.router.beanprocessor.LoadBalancerClientFilterBeanPostProcessor; +import com.tencent.cloud.polaris.router.beanprocessor.LoadBalancerInterceptorBeanPostProcessor; import com.tencent.cloud.polaris.router.config.properties.PolarisMetadataRouterProperties; import com.tencent.cloud.polaris.router.config.properties.PolarisNearByRouterProperties; import com.tencent.cloud.polaris.router.config.properties.PolarisRuleBasedRouterProperties; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor; +import org.springframework.cloud.gateway.filter.LoadBalancerClientFilter; import org.springframework.cloud.netflix.ribbon.RibbonClients; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -45,8 +49,16 @@ public class RouterAutoConfiguration { @Bean @Order(HIGHEST_PRECEDENCE) - public PolarisLoadBalancerBeanPostProcessor polarisLoadBalancerBeanPostProcessor() { - return new PolarisLoadBalancerBeanPostProcessor(); + @ConditionalOnClass(LoadBalancerInterceptor.class) + public LoadBalancerInterceptorBeanPostProcessor loadBalancerInterceptorBeanPostProcessor() { + return new LoadBalancerInterceptorBeanPostProcessor(); + } + + @Bean + @Order(HIGHEST_PRECEDENCE) + @ConditionalOnClass(LoadBalancerClientFilter.class) + public LoadBalancerClientFilterBeanPostProcessor loadBalancerClientFilterBeanPostProcessor() { + return new LoadBalancerClientFilterBeanPostProcessor(); } @Bean diff --git a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerBeanPostProcessorTest.java b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerBeanPostProcessorTest.java index cfcfa5877..18229efa6 100644 --- a/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerBeanPostProcessorTest.java +++ b/spring-cloud-starter-tencent-polaris-router/src/test/java/com/tencent/cloud/polaris/router/resttemplate/PolarisLoadBalancerBeanPostProcessorTest.java @@ -20,8 +20,8 @@ package com.tencent.cloud.polaris.router.resttemplate; import com.tencent.cloud.common.metadata.config.MetadataLocalProperties; import com.tencent.cloud.common.util.BeanFactoryUtils; -import com.tencent.cloud.polaris.router.PolarisLoadBalancerBeanPostProcessor; import com.tencent.cloud.polaris.router.RouterRuleLabelResolver; +import com.tencent.cloud.polaris.router.beanprocessor.LoadBalancerInterceptorBeanPostProcessor; import com.tencent.cloud.polaris.router.spi.RouterLabelResolver; import org.junit.Assert; import org.junit.Test; @@ -39,7 +39,7 @@ import org.springframework.cloud.client.loadbalancer.LoadBalancerRequestFactory; import static org.mockito.Mockito.when; /** - * Test for ${@link PolarisLoadBalancerBeanPostProcessor} + * Test for ${@link LoadBalancerInterceptorBeanPostProcessor} * @author lepdou 2022-05-26 */ @RunWith(MockitoJUnitRunner.class) @@ -68,7 +68,7 @@ public class PolarisLoadBalancerBeanPostProcessorTest { .thenReturn(null); LoadBalancerInterceptor loadBalancerInterceptor = new LoadBalancerInterceptor(loadBalancerClient, loadBalancerRequestFactory); - PolarisLoadBalancerBeanPostProcessor processor = new PolarisLoadBalancerBeanPostProcessor(); + LoadBalancerInterceptorBeanPostProcessor processor = new LoadBalancerInterceptorBeanPostProcessor(); processor.setBeanFactory(beanFactory); Object bean = processor.postProcessBeforeInitialization(loadBalancerInterceptor, ""); @@ -79,7 +79,7 @@ public class PolarisLoadBalancerBeanPostProcessorTest { @Test public void testNotWrapperLoadBalancerInterceptor() { - PolarisLoadBalancerBeanPostProcessor processor = new PolarisLoadBalancerBeanPostProcessor(); + LoadBalancerInterceptorBeanPostProcessor processor = new LoadBalancerInterceptorBeanPostProcessor(); processor.setBeanFactory(beanFactory); OtherBean otherBean = new OtherBean(); diff --git a/spring-cloud-tencent-dependencies/pom.xml b/spring-cloud-tencent-dependencies/pom.xml index dc60d1741..6ac04bb47 100644 --- a/spring-cloud-tencent-dependencies/pom.xml +++ b/spring-cloud-tencent-dependencies/pom.xml @@ -75,6 +75,7 @@ 1.2.7 4.5.1 1.12.10 + 31.0.1-jre 3.2.0 @@ -147,6 +148,27 @@ ${revision}
+ + + com.google.guava + guava + ${guava.version} + + + jsr305 + com.google.code.findbugs + + + animal-sniffer-annotations + org.codehaus.mojo + + + error_prone_annotations + com.google.errorprone + + + + ch.qos.logback logback-classic diff --git a/spring-cloud-tencent-examples/polaris-gateway-example/pom.xml b/spring-cloud-tencent-examples/polaris-gateway-example/pom.xml index 2645ccc62..fb7a97f2c 100644 --- a/spring-cloud-tencent-examples/polaris-gateway-example/pom.xml +++ b/spring-cloud-tencent-examples/polaris-gateway-example/pom.xml @@ -18,6 +18,7 @@ gateway-zuul-service gateway-scg-service gateway-callee-service + gateway-callee-service2 @@ -35,4 +36,4 @@ - \ No newline at end of file + From 750e5fd415195796b2e7a269fbf0ce5da86bbb5e Mon Sep 17 00:00:00 2001 From: lepdou Date: Thu, 16 Jun 2022 17:29:30 +0800 Subject: [PATCH 6/6] add instance metadata spi for registration (#244) --- CHANGELOG.md | 1 + .../polaris/registry/PolarisRegistration.java | 49 ++++++++++++++-- ...larisServiceRegistryAutoConfiguration.java | 6 +- .../registry/PolarisRegistrationTest.java | 4 +- .../metadata/StaticMetadataManager.java | 15 ++++- .../service/callee/CustomMetadata.java | 56 +++++++++++++++++++ .../context/spi/InstanceMetadataProvider.java | 55 ++++++++++++++++++ 7 files changed, 174 insertions(+), 12 deletions(-) create mode 100644 spring-cloud-tencent-examples/polaris-discovery-example/discovery-callee-service/src/main/java/com/tencent/cloud/polaris/discovery/service/callee/CustomMetadata.java create mode 100644 spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/spi/InstanceMetadataProvider.java diff --git a/CHANGELOG.md b/CHANGELOG.md index f1dc5324b..7cc73b071 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,4 +3,5 @@ [UT: Add config module unit test](https://github.com/Tencent/spring-cloud-tencent/pull/229) [Feature: Add config change listener feature support](https://github.com/Tencent/spring-cloud-tencent/pull/220) [Feature: Support spring cloud gateway routers](https://github.com/Tencent/spring-cloud-tencent/pull/230) +[Feature: Add instance metadata spi for registration](https://github.com/Tencent/spring-cloud-tencent/pull/244) [Bugfix: fix guava version conflict bug & fix router strong dependency on LoadBalancerClientFilter](https://github.com/Tencent/spring-cloud-tencent/pull/236) diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisRegistration.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisRegistration.java index bf83ee293..20cfcf6ed 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisRegistration.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisRegistration.java @@ -19,12 +19,14 @@ package com.tencent.cloud.polaris.registry; import java.net.URI; +import java.util.Collections; import java.util.HashMap; import java.util.Map; import com.tencent.cloud.common.metadata.StaticMetadataManager; import com.tencent.cloud.polaris.DiscoveryPropertiesAutoConfiguration; import com.tencent.cloud.polaris.PolarisDiscoveryProperties; +import com.tencent.cloud.polaris.context.spi.InstanceMetadataProvider; import com.tencent.polaris.client.api.SDKContext; import org.apache.commons.lang.StringUtils; @@ -40,6 +42,9 @@ import org.springframework.util.CollectionUtils; */ public class PolarisRegistration implements Registration, ServiceInstance { + private final static String METADATA_KEY_IP = "internal-ip"; + private final static String METADATA_KEY_ADDRESS = "internal-address"; + private final DiscoveryPropertiesAutoConfiguration discoveryPropertiesAutoConfiguration; private final PolarisDiscoveryProperties polarisDiscoveryProperties; @@ -48,15 +53,24 @@ public class PolarisRegistration implements Registration, ServiceInstance { private final StaticMetadataManager staticMetadataManager; + private final InstanceMetadataProvider instanceMetadataProvider; + private Map metadata; + private final String host; + public PolarisRegistration( DiscoveryPropertiesAutoConfiguration discoveryPropertiesAutoConfiguration, - PolarisDiscoveryProperties polarisDiscoveryProperties, SDKContext context, StaticMetadataManager staticMetadataManager) { + PolarisDiscoveryProperties polarisDiscoveryProperties, SDKContext context, + StaticMetadataManager staticMetadataManager, + InstanceMetadataProvider instanceMetadataProvider) { this.discoveryPropertiesAutoConfiguration = discoveryPropertiesAutoConfiguration; this.polarisDiscoveryProperties = polarisDiscoveryProperties; this.polarisContext = context; this.staticMetadataManager = staticMetadataManager; + this.instanceMetadataProvider = instanceMetadataProvider; + + host = polarisContext.getConfig().getGlobal().getAPI().getBindIP(); } @Override @@ -66,7 +80,7 @@ public class PolarisRegistration implements Registration, ServiceInstance { @Override public String getHost() { - return polarisContext.getConfig().getGlobal().getAPI().getBindIP(); + return host; } @Override @@ -92,10 +106,35 @@ public class PolarisRegistration implements Registration, ServiceInstance { @Override public Map getMetadata() { if (CollectionUtils.isEmpty(metadata)) { - metadata = new HashMap<>(); - metadata.putAll(staticMetadataManager.getMergedStaticMetadata()); + Map instanceMetadata = new HashMap<>(); + + // put internal metadata + instanceMetadata.put(METADATA_KEY_IP, host); + instanceMetadata.put(METADATA_KEY_ADDRESS, host + ":" + polarisDiscoveryProperties.getPort()); + + instanceMetadata.putAll(staticMetadataManager.getMergedStaticMetadata()); + // location info will be putted both in metadata and instance's field - metadata.putAll(staticMetadataManager.getLocationMetadata()); + instanceMetadata.putAll(staticMetadataManager.getLocationMetadata()); + + // custom metadata from spi + if (instanceMetadataProvider != null) { + if (StringUtils.isNotBlank(instanceMetadataProvider.getRegion())) { + instanceMetadata.put(StaticMetadataManager.LOCATION_KEY_ZONE, instanceMetadataProvider.getRegion()); + } + if (StringUtils.isNotBlank(instanceMetadataProvider.getZone())) { + instanceMetadata.put(StaticMetadataManager.LOCATION_KEY_ZONE, instanceMetadataProvider.getZone()); + } + if (StringUtils.isNotBlank(instanceMetadataProvider.getCampus())) { + instanceMetadata.put(StaticMetadataManager.LOCATION_KEY_ZONE, instanceMetadataProvider.getCampus()); + } + + if (!CollectionUtils.isEmpty(instanceMetadataProvider.getMetadata())) { + instanceMetadata.putAll(instanceMetadataProvider.getMetadata()); + } + } + + this.metadata = Collections.unmodifiableMap(instanceMetadata); } return metadata; } diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistryAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistryAutoConfiguration.java index 5eadee573..e868996d5 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistryAutoConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/main/java/com/tencent/cloud/polaris/registry/PolarisServiceRegistryAutoConfiguration.java @@ -21,6 +21,7 @@ package com.tencent.cloud.polaris.registry; import com.tencent.cloud.common.metadata.StaticMetadataManager; import com.tencent.cloud.polaris.DiscoveryPropertiesAutoConfiguration; import com.tencent.cloud.polaris.PolarisDiscoveryProperties; +import com.tencent.cloud.polaris.context.spi.InstanceMetadataProvider; import com.tencent.cloud.polaris.discovery.PolarisDiscoveryAutoConfiguration; import com.tencent.cloud.polaris.discovery.PolarisDiscoveryHandler; import com.tencent.polaris.client.api.SDKContext; @@ -34,6 +35,7 @@ import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationC import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.lang.Nullable; /** * Autoconfiguration of service registry of Polaris. @@ -62,9 +64,9 @@ public class PolarisServiceRegistryAutoConfiguration { public PolarisRegistration polarisRegistration( DiscoveryPropertiesAutoConfiguration discoveryPropertiesAutoConfiguration, PolarisDiscoveryProperties polarisDiscoveryProperties, SDKContext context, - StaticMetadataManager staticMetadataManager) { + StaticMetadataManager staticMetadataManager, @Nullable InstanceMetadataProvider instanceMetadataProvider) { return new PolarisRegistration(discoveryPropertiesAutoConfiguration, - polarisDiscoveryProperties, context, staticMetadataManager); + polarisDiscoveryProperties, context, staticMetadataManager, instanceMetadataProvider); } @Bean diff --git a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/registry/PolarisRegistrationTest.java b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/registry/PolarisRegistrationTest.java index a81d69d2a..11d380a75 100644 --- a/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/registry/PolarisRegistrationTest.java +++ b/spring-cloud-starter-tencent-polaris-discovery/src/test/java/com/tencent/cloud/polaris/registry/PolarisRegistrationTest.java @@ -78,7 +78,7 @@ public class PolarisRegistrationTest { doReturn(Collections.singletonMap("key2", "value2")).when(staticMetadataManager).getLocationMetadata(); polarisRegistration = new PolarisRegistration( - discoveryPropertiesAutoConfiguration, polarisDiscoveryProperties, polarisContext, staticMetadataManager); + discoveryPropertiesAutoConfiguration, polarisDiscoveryProperties, polarisContext, staticMetadataManager, null); } @Test @@ -111,7 +111,7 @@ public class PolarisRegistrationTest { Map metadata = polarisRegistration.getMetadata(); assertThat(metadata).isNotNull(); assertThat(metadata).isNotEmpty(); - assertThat(metadata.size()).isEqualTo(2); + assertThat(metadata.size()).isEqualTo(4); assertThat(metadata.get("key1")).isEqualTo("value1"); assertThat(metadata.get("key2")).isEqualTo("value2"); } diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/StaticMetadataManager.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/StaticMetadataManager.java index 95557598c..575775bf7 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/StaticMetadataManager.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/metadata/StaticMetadataManager.java @@ -43,9 +43,18 @@ public class StaticMetadataManager { private static final String ENV_METADATA_REGION = "SCT_METADATA_REGION"; private static final String ENV_METADATA_CAMPUS = "SCT_METADATA_CAMPUS"; - private static final String LOCATION_KEY_REGION = "region"; - private static final String LOCATION_KEY_ZONE = "zone"; - private static final String LOCATION_KEY_CAMPUS = "campus"; + /** + * the metadata key of region. + */ + public static final String LOCATION_KEY_REGION = "region"; + /** + * the metadata key of zone. + */ + public static final String LOCATION_KEY_ZONE = "zone"; + /** + * the metadata key of campus/datacenter. + */ + public static final String LOCATION_KEY_CAMPUS = "campus"; private Map envMetadata; private Map envTransitiveMetadata; diff --git a/spring-cloud-tencent-examples/polaris-discovery-example/discovery-callee-service/src/main/java/com/tencent/cloud/polaris/discovery/service/callee/CustomMetadata.java b/spring-cloud-tencent-examples/polaris-discovery-example/discovery-callee-service/src/main/java/com/tencent/cloud/polaris/discovery/service/callee/CustomMetadata.java new file mode 100644 index 000000000..efe3f8167 --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-discovery-example/discovery-callee-service/src/main/java/com/tencent/cloud/polaris/discovery/service/callee/CustomMetadata.java @@ -0,0 +1,56 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + */ + +package com.tencent.cloud.polaris.discovery.service.callee; + +import java.util.HashMap; +import java.util.Map; + +import com.tencent.cloud.polaris.context.spi.InstanceMetadataProvider; + +import org.springframework.stereotype.Component; + +/** + * custom metadata for instance. + *@author lepdou 2022-06-16 + */ +@Component +public class CustomMetadata implements InstanceMetadataProvider { + + @Override + public Map getMetadata() { + Map metadata = new HashMap<>(); + metadata.put("k1", "v1"); + return metadata; + } + + @Override + public String getRegion() { + return "shanghai"; + } + + @Override + public String getZone() { + return null; + } + + @Override + public String getCampus() { + return null; + } +} diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/spi/InstanceMetadataProvider.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/spi/InstanceMetadataProvider.java new file mode 100644 index 000000000..6b2b73a6b --- /dev/null +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/spi/InstanceMetadataProvider.java @@ -0,0 +1,55 @@ +/* + * 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.context.spi; + +import java.util.Map; + +/** + * + * Instance's custom metadata, metadata will be register to polaris server. + * @author lepdou 2022-06-16 + */ +public interface InstanceMetadataProvider { + + /** + * @return the metadata of instance. + */ + Map getMetadata(); + + /** + * The region of current instance. + * + * @return the region info. + */ + String getRegion(); + + /** + * The zone of current instance. + * + * @return the zone info. + */ + String getZone(); + + /** + * The campus/datacenter of current instance. + * + * @return the campus or datacenter info. + */ + String getCampus(); +}