support polaris config center

pull/69/head
lepdou 3 years ago
parent 3994863985
commit a418ae8693

@ -10,3 +10,5 @@
- [send heartbeat if healthcheck url not configured](https://github.com/Tencent/spring-cloud-tencent/pull/54) - [send heartbeat if healthcheck url not configured](https://github.com/Tencent/spring-cloud-tencent/pull/54)
- [feat:optimize project structure and checkstyle](https://github.com/Tencent/spring-cloud-tencent/pull/56) - [feat:optimize project structure and checkstyle](https://github.com/Tencent/spring-cloud-tencent/pull/56)
- [feat:divide storage and transfer of metadata.](https://github.com/Tencent/spring-cloud-tencent/pull/63) - [feat:divide storage and transfer of metadata.](https://github.com/Tencent/spring-cloud-tencent/pull/63)
- [feat:support polaris config center.](https://github.com/Tencent/spring-cloud-tencent/pull/69)

@ -48,6 +48,7 @@
<module>spring-cloud-tencent-dependencies</module> <module>spring-cloud-tencent-dependencies</module>
<module>spring-cloud-tencent-examples</module> <module>spring-cloud-tencent-examples</module>
<module>spring-cloud-tencent-coverage</module> <module>spring-cloud-tencent-coverage</module>
<module>spring-cloud-starter-tencent-polaris-config</module>
</modules> </modules>
<developers> <developers>

@ -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.circuitbreaker;
import com.tencent.cloud.common.constant.ContextConstant;
import com.tencent.cloud.polaris.context.PolarisConfigModifier;
import com.tencent.polaris.factory.config.ConfigurationImpl;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Auto configuration at bootstrap phase.
*
* @author lepdou 2022-03-29
*/
@ConditionalOnProperty(value = "spring.cloud.polaris.circuitbreaker.enabled",
havingValue = "true", matchIfMissing = true)
@Configuration(proxyBeanMethods = false)
public class PolarisCircuitBreakerBootstrapConfiguration {
@Bean
public CircuitBreakerConfigModifier circuitBreakerConfigModifier() {
return new CircuitBreakerConfigModifier();
}
public static class CircuitBreakerConfigModifier implements PolarisConfigModifier {
@Override
public void modify(ConfigurationImpl configuration) {
// Turn on circuitbreaker configuration
configuration.getConsumer().getCircuitBreaker().setEnable(true);
}
@Override
public int getOrder() {
return ContextConstant.ModifierOrder.CIRCUIT_BREAKER_ORDER;
}
}
}

@ -17,14 +17,11 @@
package com.tencent.cloud.polaris.circuitbreaker; package com.tencent.cloud.polaris.circuitbreaker;
import com.tencent.cloud.common.constant.ContextConstant.ModifierOrder;
import com.tencent.cloud.polaris.circuitbreaker.feign.PolarisFeignBeanPostProcessor; import com.tencent.cloud.polaris.circuitbreaker.feign.PolarisFeignBeanPostProcessor;
import com.tencent.cloud.polaris.context.PolarisConfigModifier;
import com.tencent.cloud.polaris.context.PolarisContextConfiguration; import com.tencent.cloud.polaris.context.PolarisContextConfiguration;
import com.tencent.polaris.api.core.ConsumerAPI; import com.tencent.polaris.api.core.ConsumerAPI;
import com.tencent.polaris.client.api.SDKContext; import com.tencent.polaris.client.api.SDKContext;
import com.tencent.polaris.factory.api.DiscoveryAPIFactory; import com.tencent.polaris.factory.api.DiscoveryAPIFactory;
import com.tencent.polaris.factory.config.ConfigurationImpl;
import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.AutoConfigureBefore;
@ -61,24 +58,4 @@ public class PolarisFeignClientAutoConfiguration {
return new PolarisFeignBeanPostProcessor(consumerAPI); return new PolarisFeignBeanPostProcessor(consumerAPI);
} }
@Bean
public CircuitBreakerConfigModifier circuitBreakerConfigModifier() {
return new CircuitBreakerConfigModifier();
}
public static class CircuitBreakerConfigModifier implements PolarisConfigModifier {
@Override
public void modify(ConfigurationImpl configuration) {
// Enable circuit breaker.
configuration.getConsumer().getCircuitBreaker().setEnable(true);
}
@Override
public int getOrder() {
return ModifierOrder.CIRCUIT_BREAKER_ORDER;
}
}
} }

@ -1,2 +1,4 @@
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
com.tencent.cloud.polaris.circuitbreaker.PolarisCircuitBreakerBootstrapConfiguration
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.tencent.cloud.polaris.circuitbreaker.PolarisFeignClientAutoConfiguration com.tencent.cloud.polaris.circuitbreaker.PolarisFeignClientAutoConfiguration

@ -18,6 +18,7 @@
package com.tencent.cloud.polaris.circuitbreaker.feign; package com.tencent.cloud.polaris.circuitbreaker.feign;
import com.tencent.cloud.polaris.circuitbreaker.PolarisFeignClientAutoConfiguration; import com.tencent.cloud.polaris.circuitbreaker.PolarisFeignClientAutoConfiguration;
import com.tencent.cloud.polaris.context.PolarisContextConfiguration;
import feign.Client; import feign.Client;
import org.junit.Test; import org.junit.Test;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
@ -36,7 +37,7 @@ import org.springframework.test.context.junit4.SpringRunner;
*/ */
@RunWith(SpringRunner.class) @RunWith(SpringRunner.class)
@SpringBootTest(classes = TestPolarisFeignApp.class) @SpringBootTest(classes = TestPolarisFeignApp.class)
@ContextConfiguration(classes = { PolarisFeignClientAutoConfiguration.class }) @ContextConfiguration(classes = { PolarisFeignClientAutoConfiguration.class, PolarisContextConfiguration.class })
public class PolarisFeignClientTest { public class PolarisFeignClientTest {
@Autowired @Autowired

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spring-cloud-tencent</artifactId>
<groupId>com.tencent.cloud</groupId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-cloud-starter-tencent-polaris-config</artifactId>
<dependencies>
<!-- Spring Cloud Tencent dependencies start -->
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-tencent-polaris-context</artifactId>
</dependency>
<!-- Spring Cloud Tencent dependencies end -->
<!-- Polaris dependencies start -->
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>polaris-configuration-factory</artifactId>
</dependency>
<!-- Polaris dependencies end -->
<!-- Spring cloud dependencies start -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-context</artifactId>
</dependency>
<!-- Spring cloud dependencies start -->
</dependencies>
</project>

@ -0,0 +1,62 @@
/*
* 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.util.List;
import com.tencent.cloud.common.constant.ContextConstant;
import com.tencent.cloud.common.util.AddressUtils;
import com.tencent.cloud.polaris.config.config.PolarisConfigProperties;
import com.tencent.cloud.polaris.context.PolarisConfigModifier;
import com.tencent.polaris.factory.config.ConfigurationImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
/**
* Read configuration from spring cloud's configuration file and override polaris.yaml.
*
* @author lepdou 2022-03-10
*/
public class ConfigurationModifier implements PolarisConfigModifier {
@Autowired
private PolarisConfigProperties polarisConfigProperties;
@Override
public void modify(ConfigurationImpl configuration) {
configuration.getConfigFile().getServerConnector().setConnectorType("polaris");
if (StringUtils.isEmpty(polarisConfigProperties.getAddresses())) {
return;
}
// override polaris config server address
List<String> addresses = AddressUtils
.parseAddressList(polarisConfigProperties.getAddresses());
configuration.getConfigFile().getServerConnector().setAddresses(addresses);
}
@Override
public int getOrder() {
return ContextConstant.ModifierOrder.CONFIG_ORDER;
}
}

@ -0,0 +1,49 @@
/*
* 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 com.tencent.cloud.polaris.config.adapter.PolarisPropertySourceAutoRefresher;
import com.tencent.cloud.polaris.config.adapter.PolarisPropertySourceManager;
import com.tencent.cloud.polaris.config.config.PolarisConfigProperties;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.context.refresh.ContextRefresher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* polaris config module auto configuration at init application context phase.
*
* @author lepdou 2022-03-28
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(value = "spring.cloud.polaris.config.enabled",
matchIfMissing = true)
public class PolarisConfigAutoConfiguration {
@Bean
public PolarisPropertySourceAutoRefresher polarisPropertySourceAutoRefresher(
PolarisConfigProperties polarisConfigProperties,
PolarisPropertySourceManager polarisPropertySourceManager,
ContextRefresher contextRefresher) {
return new PolarisPropertySourceAutoRefresher(polarisConfigProperties,
polarisPropertySourceManager, contextRefresher);
}
}

@ -0,0 +1,73 @@
/*
* 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 com.tencent.cloud.polaris.config.adapter.PolarisConfigFileLocator;
import com.tencent.cloud.polaris.config.adapter.PolarisPropertySourceManager;
import com.tencent.cloud.polaris.config.config.PolarisConfigProperties;
import com.tencent.cloud.polaris.context.PolarisContextProperties;
import com.tencent.polaris.client.api.SDKContext;
import com.tencent.polaris.configuration.api.core.ConfigFileService;
import com.tencent.polaris.configuration.factory.ConfigFileServiceFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* polaris config module auto configuration at bootstrap phase.
*
* @author lepdou 2022-03-10
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(value = "spring.cloud.polaris.config.enabled",
matchIfMissing = true)
public class PolarisConfigBootstrapAutoConfiguration {
@Bean
public PolarisConfigProperties polarisProperties() {
return new PolarisConfigProperties();
}
@Bean
public ConfigFileService configFileService(SDKContext sdkContext) {
return ConfigFileServiceFactory.createConfigFileService(sdkContext);
}
@Bean
public PolarisPropertySourceManager polarisPropertySourceManager() {
return new PolarisPropertySourceManager();
}
@Bean
public PolarisConfigFileLocator polarisConfigFileLocator(
PolarisConfigProperties polarisConfigProperties,
PolarisContextProperties polarisContextProperties,
ConfigFileService configFileService,
PolarisPropertySourceManager polarisPropertySourceManager) {
return new PolarisConfigFileLocator(polarisConfigProperties,
polarisContextProperties, configFileService,
polarisPropertySourceManager);
}
@Bean
public ConfigurationModifier configurationModifier() {
return new ConfigurationModifier();
}
}

@ -0,0 +1,153 @@
/*
* 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.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import com.tencent.cloud.polaris.config.config.ConfigFileGroup;
import com.tencent.cloud.polaris.config.config.PolarisConfigProperties;
import com.tencent.cloud.polaris.config.enums.ConfigFileFormat;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.bootstrap.config.PropertySourceLocator;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.CompositePropertySource;
import org.springframework.core.env.Environment;
import org.springframework.core.env.PropertySource;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
/**
* Spring cloud reserved core configuration loading SPI.
* <p>
* This SPI is implemented to interface with Polaris configuration center
*
* @author lepdou 2022-03-10
*/
@Order(0)
public class PolarisConfigFileLocator implements PropertySourceLocator {
private static final Logger LOGGER = LoggerFactory
.getLogger(PolarisConfigFileLocator.class);
private static final String POLARIS_CONFIG_PROPERTY_SOURCE_NAME = "polaris-config";
private final PolarisConfigProperties polarisConfigProperties;
private final PolarisContextProperties polarisContextProperties;
private final ConfigFileService configFileService;
private final PolarisPropertySourceManager polarisPropertySourceManager;
public PolarisConfigFileLocator(PolarisConfigProperties polarisConfigProperties,
PolarisContextProperties polarisContextProperties,
ConfigFileService configFileService,
PolarisPropertySourceManager polarisPropertySourceManager) {
this.polarisConfigProperties = polarisConfigProperties;
this.polarisContextProperties = polarisContextProperties;
this.configFileService = configFileService;
this.polarisPropertySourceManager = polarisPropertySourceManager;
}
@Override
public PropertySource<?> locate(Environment environment) {
CompositePropertySource compositePropertySource = new CompositePropertySource(
POLARIS_CONFIG_PROPERTY_SOURCE_NAME);
List<ConfigFileGroup> configFileGroups = polarisConfigProperties.getGroups();
if (CollectionUtils.isEmpty(configFileGroups)) {
return compositePropertySource;
}
initPolarisConfigFiles(compositePropertySource, configFileGroups);
return compositePropertySource;
}
private void initPolarisConfigFiles(CompositePropertySource compositePropertySource,
List<ConfigFileGroup> configFileGroups) {
String namespace = polarisContextProperties.getNamespace();
for (ConfigFileGroup configFileGroup : configFileGroups) {
String group = configFileGroup.getName();
if (StringUtils.isEmpty(group)) {
throw new IllegalArgumentException(
"polaris config group name cannot be empty.");
}
List<String> files = configFileGroup.getFiles();
if (CollectionUtils.isEmpty(files)) {
return;
}
for (String fileName : files) {
PolarisPropertySource polarisPropertySource = loadPolarisPropertySource(
namespace, group, fileName);
compositePropertySource.addPropertySource(polarisPropertySource);
polarisPropertySourceManager.addPropertySource(polarisPropertySource);
LOGGER.info(
"[SCT Config] Load and inject polaris config file success. namespace = {}, group = {}, fileName = {}",
namespace, group, fileName);
}
}
}
private PolarisPropertySource loadPolarisPropertySource(String namespace,
String group, String fileName) {
ConfigKVFile configKVFile;
// unknown extension is resolved as properties file
if (ConfigFileFormat.isPropertyFile(fileName)
|| ConfigFileFormat.isUnknownFile(fileName)) {
configKVFile = configFileService.getConfigPropertiesFile(namespace, group,
fileName);
}
else if (ConfigFileFormat.isYamlFile(fileName)) {
configKVFile = configFileService.getConfigYamlFile(namespace, group,
fileName);
}
else {
LOGGER.warn(
"[SCT Config] Unsupported config file. namespace = {}, group = {}, fileName = {}",
namespace, group, fileName);
throw new IllegalStateException(
"Only configuration files in the format of properties / yaml / yaml"
+ " can be injected into the spring context");
}
Map<String, Object> map = new ConcurrentHashMap<>();
for (String key : configKVFile.getPropertyNames()) {
map.put(key, configKVFile.getProperty(key, null));
}
return new PolarisPropertySource(namespace, group, fileName, configKVFile, map);
}
}

@ -0,0 +1,78 @@
/*
* 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.Map;
import com.tencent.polaris.configuration.api.core.ConfigKVFile;
import org.springframework.core.env.MapPropertySource;
/**
* a polaris config file will be wrapped as polaris property source.
*
* @author lepdou 2022-03-10
*/
public class PolarisPropertySource extends MapPropertySource {
private final String namespace;
private final String group;
private final String fileName;
private final ConfigKVFile configKVFile;
public PolarisPropertySource(String namespace, String group, String fileName,
ConfigKVFile configKVFile, Map<String, Object> source) {
super(namespace + "-" + group + "-" + fileName, source);
this.namespace = namespace;
this.group = group;
this.fileName = fileName;
this.configKVFile = configKVFile;
}
public String getNamespace() {
return namespace;
}
public String getGroup() {
return group;
}
public String getFileName() {
return fileName;
}
public String getPropertySourceName() {
return namespace + "-" + group + "-" + fileName;
}
ConfigKVFile getConfigKVFile() {
return configKVFile;
}
@Override
public String toString() {
return "PolarisPropertySource{" + "namespace='" + namespace + '\'' + ", group='"
+ group + '\'' + ", fileName='" + fileName + '\'' + '}';
}
}

@ -0,0 +1,141 @@
/*
* 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.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import com.tencent.cloud.polaris.config.config.PolarisConfigProperties;
import com.tencent.polaris.configuration.api.core.ConfigKVFileChangeEvent;
import com.tencent.polaris.configuration.api.core.ConfigKVFileChangeListener;
import com.tencent.polaris.configuration.api.core.ConfigPropertyChangeInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.cloud.context.refresh.ContextRefresher;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationListener;
import org.springframework.util.CollectionUtils;
/**
* 1. Listen to the Polaris server configuration publishing event 2. Write the changed
* configuration content to propertySource 3. Refresh the context through contextRefresher
*
* @author lepdou 2022-03-28
*/
public class PolarisPropertySourceAutoRefresher
implements ApplicationListener<ApplicationReadyEvent>, ApplicationContextAware {
private static final Logger LOGGER = LoggerFactory
.getLogger(PolarisPropertySourceAutoRefresher.class);
private final PolarisConfigProperties polarisConfigProperties;
private final PolarisPropertySourceManager polarisPropertySourceManager;
private ApplicationContext applicationContext;
private final ContextRefresher contextRefresher;
private final AtomicBoolean registered = new AtomicBoolean(false);
public PolarisPropertySourceAutoRefresher(
PolarisConfigProperties polarisConfigProperties,
PolarisPropertySourceManager polarisPropertySourceManager,
ContextRefresher contextRefresher) {
this.polarisConfigProperties = polarisConfigProperties;
this.polarisPropertySourceManager = polarisPropertySourceManager;
this.contextRefresher = contextRefresher;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.applicationContext = applicationContext;
}
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
registerPolarisConfigPublishEvent();
}
private void registerPolarisConfigPublishEvent() {
if (!polarisConfigProperties.isAutoRefresh()) {
return;
}
List<PolarisPropertySource> polarisPropertySources = polarisPropertySourceManager
.getAllPropertySources();
if (CollectionUtils.isEmpty(polarisPropertySources)) {
return;
}
if (!registered.compareAndSet(false, true)) {
return;
}
// register polaris config publish event
for (PolarisPropertySource polarisPropertySource : polarisPropertySources) {
polarisPropertySource.getConfigKVFile()
.addChangeListener(new ConfigKVFileChangeListener() {
@Override
public void onChange(
ConfigKVFileChangeEvent configKVFileChangeEvent) {
LOGGER.info(
"[SCT Config] received polaris config change event and will refresh spring context."
+ "namespace = {}, group = {}, fileName = {}",
polarisPropertySource.getNamespace(),
polarisPropertySource.getGroup(),
polarisPropertySource.getFileName());
Map<String, Object> source = polarisPropertySource
.getSource();
for (String changedKey : configKVFileChangeEvent
.changedKeys()) {
ConfigPropertyChangeInfo configPropertyChangeInfo = configKVFileChangeEvent
.getChangeInfo(changedKey);
LOGGER.info("[SCT Config] changed property = {}",
configPropertyChangeInfo);
switch (configPropertyChangeInfo.getChangeType()) {
case MODIFIED:
case ADDED:
source.put(changedKey,
configPropertyChangeInfo.getNewValue());
break;
case DELETED:
source.remove(changedKey);
break;
}
}
// rebuild beans with @RefreshScope annotation
contextRefresher.refresh();
}
});
}
}
}

@ -0,0 +1,44 @@
/*
* 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.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* The manager of polaris property source.
*
* @author lepdou 2022-03-28
*/
public class PolarisPropertySourceManager {
private final Map<String, PolarisPropertySource> polarisPropertySources = new ConcurrentHashMap<>();
public void addPropertySource(PolarisPropertySource polarisPropertySource) {
polarisPropertySources.putIfAbsent(polarisPropertySource.getPropertySourceName(),
polarisPropertySource);
}
public List<PolarisPropertySource> getAllPropertySources() {
return new ArrayList<>(polarisPropertySources.values());
}
}

@ -0,0 +1,60 @@
/*
* 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.config;
import java.util.List;
/**
* the config file group.
*
* @author lepdou 2022-03-28
*/
public class ConfigFileGroup {
/**
* group name.
*/
private String name;
/**
* the files belong to group.
*/
private List<String> files;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<String> getFiles() {
return files;
}
public void setFiles(List<String> files) {
this.files = files;
}
@Override
public String toString() {
return "ConfigFileGroup{" + "name='" + name + '\'' + ", file=" + files + '}';
}
}

@ -0,0 +1,85 @@
/*
* 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.config;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* polaris config module bootstrap configs.
*
* @author lepdou 2022-03-10
*/
@ConfigurationProperties("spring.cloud.polaris.config")
public class PolarisConfigProperties {
/**
* Whether to open the configuration center.
*/
private boolean enabled = true;
/**
* Configuration center service address list.
*/
private String addresses;
/**
* Whether to automatically update to the spring context when the configuration file.
* is updated
*/
private boolean autoRefresh = true;
/**
* List of injected configuration files.
*/
private List<ConfigFileGroup> groups;
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public String getAddresses() {
return addresses;
}
public void setAddresses(String addresses) {
this.addresses = addresses;
}
public boolean isAutoRefresh() {
return autoRefresh;
}
public void setAutoRefresh(boolean autoRefresh) {
this.autoRefresh = autoRefresh;
}
public List<ConfigFileGroup> getGroups() {
return groups;
}
public void setGroups(List<ConfigFileGroup> groups) {
this.groups = groups;
}
}

@ -0,0 +1,84 @@
/*
* 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.enums;
/**
* the format of config file.
*
* @author lepdou 2022-03-28
*/
public enum ConfigFileFormat {
/**
* property format.
*/
PROPERTY(".property"),
/**
* yaml format.
*/
YAML(".yaml"),
/**
* yml format.
*/
YML(".yml"),
/**
* xml format.
*/
XML(".xml"),
/**
* json format.
*/
JSON(".json"),
/**
* text format.
*/
TEXT(".text"),
/**
* html format.
*/
html(".html"),
/**
* unknown format.
*/
UNKNOWN(".unknown");
private final String extension;
ConfigFileFormat(String extension) {
this.extension = extension;
}
public static boolean isPropertyFile(String fileName) {
return fileName.endsWith(PROPERTY.extension);
}
public static boolean isYamlFile(String fileName) {
return fileName.endsWith(YAML.extension) || fileName.endsWith(YML.extension);
}
public static boolean isUnknownFile(String fileName) {
for (ConfigFileFormat format : ConfigFileFormat.values()) {
if (fileName.endsWith(format.extension)) {
return false;
}
}
return true;
}
}

@ -0,0 +1,32 @@
{
"properties": [
{
"name": "spring.cloud.polaris.config.enabled",
"type": "java.lang.Boolean",
"defaultValue": "true",
"description": "The switch of polaris configuration module.",
"sourceType": "com.tencent.cloud.polaris.config.config.PolarisConfigProperties"
},
{
"name": "spring.cloud.polaris.config.addresses",
"type": "java.lang.String",
"defaultValue": "",
"description": "The polaris configuration server addresses.",
"sourceType": "com.tencent.cloud.polaris.config.config.PolarisConfigProperties"
},
{
"name": "spring.cloud.polaris.config.auto-refresh",
"type": "java.lang.Boolean",
"defaultValue": "true",
"description": "Whether to automatically update to the spring context when the configuration file is updated.",
"sourceType": "com.tencent.cloud.polaris.config.config.PolarisConfigProperties"
},
{
"name": "spring.cloud.polaris.config.groups",
"type": "com.tencent.cloud.polaris.config.config.ConfigFileGroup",
"defaultValue": "",
"description": "List of imported config files.",
"sourceType": "com.tencent.cloud.polaris.config.config.PolarisConfigProperties"
}
]
}

@ -0,0 +1,4 @@
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
com.tencent.cloud.polaris.config.PolarisConfigBootstrapAutoConfiguration
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.tencent.cloud.polaris.config.PolarisConfigAutoConfiguration

@ -43,7 +43,7 @@ public class PolarisProperties {
/** /**
* Namespace, separation registry of different environments. * Namespace, separation registry of different environments.
*/ */
@Value("${spring.cloud.polaris.discovery.namespace:#{'default'}}") @Value("${spring.cloud.polaris.discovery.namespace:${spring.cloud.polaris.namespace:#{'default'}}}")
private String namespace; private String namespace;
/** /**

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

@ -44,7 +44,8 @@ public class PolarisDiscoveryClientConfigurationTest {
private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(PolarisContextConfiguration.class, .withConfiguration(AutoConfigurations.of(PolarisContextConfiguration.class,
PolarisDiscoveryClientConfiguration.class)) PolarisDiscoveryClientConfiguration.class,
PolarisContextConfiguration.class))
.withPropertyValues("spring.application.name=" + SERVICE_PROVIDER) .withPropertyValues("spring.application.name=" + SERVICE_PROVIDER)
.withPropertyValues("server.port=" + PORT) .withPropertyValues("server.port=" + PORT)
.withPropertyValues("spring.cloud.polaris.address=grpc://127.0.0.1:10081"); .withPropertyValues("spring.cloud.polaris.address=grpc://127.0.0.1:10081");

@ -53,7 +53,8 @@ public class PolarisServiceDiscoveryTest {
.withConfiguration(AutoConfigurations.of(PolarisContextConfiguration.class, .withConfiguration(AutoConfigurations.of(PolarisContextConfiguration.class,
PolarisServiceDiscoveryTest.PolarisPropertiesConfiguration.class, PolarisServiceDiscoveryTest.PolarisPropertiesConfiguration.class,
PolarisDiscoveryClientConfiguration.class, PolarisDiscoveryClientConfiguration.class,
PolarisDiscoveryAutoConfiguration.class)) PolarisDiscoveryAutoConfiguration.class,
PolarisContextConfiguration.class))
.withPropertyValues("spring.application.name=" + SERVICE_PROVIDER) .withPropertyValues("spring.application.name=" + SERVICE_PROVIDER)
.withPropertyValues("server.port=" + PORT) .withPropertyValues("server.port=" + PORT)
.withPropertyValues("spring.cloud.polaris.address=grpc://127.0.0.1:10081") .withPropertyValues("spring.cloud.polaris.address=grpc://127.0.0.1:10081")

@ -46,7 +46,8 @@ public class PolarisReactiveDiscoveryClientConfigurationTest {
private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(PolarisContextConfiguration.class, .withConfiguration(AutoConfigurations.of(PolarisContextConfiguration.class,
PolarisReactiveDiscoveryClientConfiguration.class, PolarisReactiveDiscoveryClientConfiguration.class,
PolarisDiscoveryClientConfiguration.class)) PolarisDiscoveryClientConfiguration.class,
PolarisContextConfiguration.class))
.withPropertyValues("spring.application.name=" + SERVICE_PROVIDER) .withPropertyValues("spring.application.name=" + SERVICE_PROVIDER)
.withPropertyValues("server.port=" + PORT) .withPropertyValues("server.port=" + PORT)
.withPropertyValues("spring.cloud.polaris.address=grpc://127.0.0.1:10081"); .withPropertyValues("spring.cloud.polaris.address=grpc://127.0.0.1:10081");

@ -19,6 +19,7 @@ package com.tencent.cloud.polaris.ribbon;
import com.netflix.client.config.DefaultClientConfigImpl; import com.netflix.client.config.DefaultClientConfigImpl;
import com.netflix.client.config.IClientConfig; import com.netflix.client.config.IClientConfig;
import com.tencent.cloud.polaris.context.PolarisContextConfiguration;
import com.tencent.cloud.polaris.discovery.PolarisDiscoveryClientConfiguration; import com.tencent.cloud.polaris.discovery.PolarisDiscoveryClientConfiguration;
import com.tencent.cloud.polaris.discovery.PolarisDiscoveryHandler; import com.tencent.cloud.polaris.discovery.PolarisDiscoveryHandler;
import org.junit.Test; import org.junit.Test;
@ -46,7 +47,8 @@ public class PolarisRibbonServerListConfigurationTest {
private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(PolarisRibbonClientTest.class, .withConfiguration(AutoConfigurations.of(PolarisRibbonClientTest.class,
PolarisDiscoveryClientConfiguration.class)) PolarisDiscoveryClientConfiguration.class,
PolarisContextConfiguration.class))
.withPropertyValues("spring.application.name=" + SERVICE_PROVIDER) .withPropertyValues("spring.application.name=" + SERVICE_PROVIDER)
.withPropertyValues("server.port=" + PORT) .withPropertyValues("server.port=" + PORT)
.withPropertyValues("spring.cloud.polaris.address=grpc://127.0.0.1:10081") .withPropertyValues("spring.cloud.polaris.address=grpc://127.0.0.1:10081")

@ -58,7 +58,8 @@ public class PolarisServerListTest {
.withConfiguration(AutoConfigurations.of(PolarisContextConfiguration.class, .withConfiguration(AutoConfigurations.of(PolarisContextConfiguration.class,
PolarisServerListTest.PolarisPropertiesConfiguration.class, PolarisServerListTest.PolarisPropertiesConfiguration.class,
PolarisDiscoveryClientConfiguration.class, PolarisDiscoveryClientConfiguration.class,
PolarisDiscoveryAutoConfiguration.class)) PolarisDiscoveryAutoConfiguration.class,
PolarisContextConfiguration.class))
.withPropertyValues("spring.application.name=" + SERVICE_PROVIDER) .withPropertyValues("spring.application.name=" + SERVICE_PROVIDER)
.withPropertyValues("server.port=" + PORT) .withPropertyValues("server.port=" + PORT)
.withPropertyValues("spring.cloud.polaris.address=grpc://127.0.0.1:10081") .withPropertyValues("spring.cloud.polaris.address=grpc://127.0.0.1:10081")

@ -17,6 +17,7 @@
package com.tencent.cloud.polaris.router.config; package com.tencent.cloud.polaris.router.config;
import com.tencent.cloud.polaris.context.PolarisContextConfiguration;
import com.tencent.polaris.router.api.core.RouterAPI; import com.tencent.polaris.router.api.core.RouterAPI;
import org.junit.Test; import org.junit.Test;
@ -38,7 +39,8 @@ public class PolarisRibbonAutoConfigurationTest {
private ApplicationContextRunner contextRunner = new ApplicationContextRunner() private ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(PolarisRibbonTest.class, .withConfiguration(AutoConfigurations.of(PolarisRibbonTest.class,
PolarisRibbonAutoConfiguration.class)) PolarisRibbonAutoConfiguration.class,
PolarisContextConfiguration.class))
.withPropertyValues("spring.application.name=" + SERVICE_PROVIDER) .withPropertyValues("spring.application.name=" + SERVICE_PROVIDER)
.withPropertyValues("server.port=" + PORT) .withPropertyValues("server.port=" + PORT)
.withPropertyValues("spring.cloud.polaris.address=grpc://127.0.0.1:10081"); .withPropertyValues("spring.cloud.polaris.address=grpc://127.0.0.1:10081");

@ -44,6 +44,11 @@ public final class ContextConstant {
*/ */
public static Integer CIRCUIT_BREAKER_ORDER = 1; public static Integer CIRCUIT_BREAKER_ORDER = 1;
/**
* Order of configuration modifier.
*/
public static Integer CONFIG_ORDER = 1;
} }
} }

@ -0,0 +1,48 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
*/
package com.tencent.cloud.common.util;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
/**
* the utils of parse address.
*
* @author lepdou 2022-03-29
*/
public final class AddressUtils {
private static final String ADDRESS_SEPARATOR = ",";
private AddressUtils() {
}
public static List<String> parseAddressList(String addressInfo) {
List<String> addressList = new ArrayList<>();
String[] addresses = addressInfo.split(ADDRESS_SEPARATOR);
for (String address : addresses) {
URI uri = URI.create(address.trim());
addressList.add(uri.getAuthority());
}
return addressList;
}
}

@ -96,7 +96,6 @@
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.tencent.cloud</groupId> <groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-polaris-ratelimit</artifactId> <artifactId>spring-cloud-starter-tencent-polaris-ratelimit</artifactId>
@ -115,6 +114,12 @@
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-polaris-config</artifactId>
<version>${revision}</version>
</dependency>
<dependency> <dependency>
<groupId>com.tencent.cloud</groupId> <groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-tencent-polaris-context</artifactId> <artifactId>spring-cloud-tencent-polaris-context</artifactId>

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spring-cloud-tencent-examples</artifactId>
<groupId>com.tencent.cloud</groupId>
<version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>polaris-config-example</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Spring Cloud Tencent dependency -->
<dependency>
<groupId>com.tencent.cloud</groupId>
<artifactId>spring-cloud-starter-tencent-polaris-config</artifactId>
</dependency>
</dependencies>
</project>

@ -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.config.example;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* the endpoint for get config.
*
* @author lepdou 2022-03-10
*/
@RestController
@RefreshScope
public class ConfigController {
@Value("${timeout:1000}")
private int timeout;
@Autowired
private Person person;
@Autowired
private Environment environment;
@GetMapping("/timeout")
public int timeout() {
environment.getProperty("timeout", "1000");
return timeout;
}
@GetMapping("/person")
public String person() {
return person.toString();
}
}

@ -0,0 +1,58 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
*/
package com.tencent.cloud.polaris.config.example;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* example property object.
*
* @author lepdou 2022-03-28
*/
@Component
@ConfigurationProperties(prefix = "teacher")
public class Person {
private String name;
private int age;
String getName() {
return name;
}
void setName(String name) {
this.name = name;
}
int getAge() {
return age;
}
void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" + "name='" + name + '\'' + ", age=" + age + '}';
}
}

@ -0,0 +1,35 @@
/*
* Tencent is pleased to support the open source community by making Spring Cloud Tencent available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the BSD 3-Clause License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSD-3-Clause
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package com.tencent.cloud.polaris.config.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* example application starter.
*
* @author lepdou 2022-03-10
*/
@SpringBootApplication
public class PolarisConfigExampleApplication {
public static void main(String[] args) {
SpringApplication.run(PolarisConfigExampleApplication.class, args);
}
}

@ -0,0 +1,76 @@
# Polaris Config Example 使用指南
## 1. bootstrap.yml 配置
> 注意是在 bootstrap.yml 里配置,而不是在 application.yml 里配置。因为配置中心相关的配置是在 bootstrap 阶段依赖的配置。
```` yaml
spring:
application:
name: polaris-config-example
cloud:
polaris:
namespace: dev
config:
addresses: grpc://9.134.122.18:8093 # the address of polaris config server
auto-refresh: true # auto refresh when config file changed
groups:
- name: ${spring.application.name} # group name
files: [ "config/application.properties", "config/bootstrap.yml" ] # config/application.properties takes precedence over config/bootstrap.yml
````
## 2. 在北极星服务端创建配置文件
### 2.1 创建 namespace dev
### 2.2 创建配置文件分组polaris-config-example
北极星的配置文件分组概念为一组配置文件的集合,推荐应用名=分组名,例如在我们的示例中,新建一个 polaris-config-example 的分组。
把 polaris-config-example 应用的配置文件都放在 polaris-config-example 分组下,这样便于配置管理。
### 2.3 创建两个配置文件 config/application.properties 、config/bootstrap.yml
北极星配置中心的控制台,配置文件名可以通过 / 来按树状目录结构展示,通过树状结构可以清晰的管理配置文件。
#### 2.3.1 config/application.properties 文件内容
```` properties
timeout = 3000
````
#### 2.3.2 config/bootstrap.yml 文件内容
````yaml
teacher:
name : 张三
age: 38
````
页面样例如下图所示:
![](polaris-config-ui.png)
## 3. 运行 PolarisConfigExampleApplication
## 4. 访问接口
````
curl "http://localhost:48084/timeout"
curl "http://localhost:48084/person"
````
## 5. 动态推送能力
### 5.1 管控台动态修改并发布 config/application.properties
```` properties
timeout = 5000
````
### 5.2 再次访问接口
````
curl "http://localhost:48084/timeout"
````

@ -0,0 +1,14 @@
server:
port: 48084
spring:
application:
name: polaris-config-example
cloud:
polaris:
namespace: dev
config:
addresses: grpc://127.0.0.1:8093 # the address of polaris config server
auto-refresh: true # auto refresh when config file changed
groups:
- name: ${spring.application.name} # group name
files: [ "config/application.properties", "config/bootstrap.yml" ] # config/application.properties takes precedence over config/bootstrap.yml

@ -0,0 +1,15 @@
log4j.rootLogger=DEBUG,console,FILE
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.threshold=INFO
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d{yyyy-MM-dd HH\:mm\:ss} [%5p] - %c -%F(%L) -%m%n
log4j.appender.FILE=org.apache.log4j.RollingFileAppender
log4j.appender.FILE.Append=true
log4j.appender.FILE.File=applog/%d{yyyy-MM-dd}/%d{yyyy-MM-dd}.log
log4j.appender.FILE.Threshold=INFO
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.ConversionPattern=%d{yyyy-MM-dd HH\:mm\:ss} [%5p] - %c -%F(%L) -%m%n
log4j.appender.FILE.MaxFileSize=10MB

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
<contextName>logback</contextName>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<appender name="logFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
<Prudent>true</Prudent>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>
applog/%d{yyyy-MM-dd}/%d{yyyy-MM-dd}.log
</FileNamePattern>
</rollingPolicy>
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>
%d{yyyy-MM-dd HH:mm:ss} -%msg%n
</Pattern>
</layout>
</appender>
<root level="info">
<appender-ref ref="console"/>
<appender-ref ref="logFile"/>
</root>
</configuration>

@ -8,6 +8,8 @@ spring:
address: grpc://127.0.0.1:8091 address: grpc://127.0.0.1:8091
discovery: discovery:
ip-address: 127.0.0.1 ip-address: 127.0.0.1
inetutils:
default-ip-address: 198.1.1.1
# consul: # consul:
# port: 8500 # port: 8500
# host: 127.0.0.1 # host: 127.0.0.1

@ -20,7 +20,8 @@
<module>polaris-ratelimit-example</module> <module>polaris-ratelimit-example</module>
<module>polaris-circuitbreaker-example</module> <module>polaris-circuitbreaker-example</module>
<module>polaris-gateway-example</module> <module>polaris-gateway-example</module>
</modules> <module>polaris-config-example</module>
</modules>
<properties> <properties>
<maven.deploy.skip>true</maven.deploy.skip> <maven.deploy.skip>true</maven.deploy.skip>

@ -37,11 +37,6 @@
<artifactId>connector-polaris-grpc</artifactId> <artifactId>connector-polaris-grpc</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.tencent.polaris</groupId>
<artifactId>connector-polaris-grpc</artifactId>
</dependency>
<dependency> <dependency>
<groupId>com.tencent.polaris</groupId> <groupId>com.tencent.polaris</groupId>
<artifactId>connector-consul</artifactId> <artifactId>connector-consul</artifactId>

@ -0,0 +1,52 @@
/*
* 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;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* Because polaris-context is initialized in the bootstrap phase, the initialization of
* InetUtilsProperties is required. The impact on user usage is that
* spring.cloud.inetutils.defaultIpAddress needs to be configured in bootstrap.yml to take
* effect.
*
* @see org.springframework.cloud.commons.util.InetUtilsProperties
*/
@ConfigurationProperties(InetUtilsProperties.PREFIX)
public class InetUtilsProperties {
/**
* Prefix for the Inet Utils properties.
*/
public static final String PREFIX = "spring.cloud.inetutils";
/**
* The default IP address. Used in case of errors.
*/
private String defaultIpAddress = "127.0.0.1";
String getDefaultIpAddress() {
return defaultIpAddress;
}
void setDefaultIpAddress(String defaultIpAddress) {
this.defaultIpAddress = defaultIpAddress;
}
}

@ -17,11 +17,10 @@
package com.tencent.cloud.polaris.context; package com.tencent.cloud.polaris.context;
import java.net.URI;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import com.tencent.cloud.common.constant.ContextConstant.ModifierOrder; import com.tencent.cloud.common.constant.ContextConstant.ModifierOrder;
import com.tencent.cloud.common.util.AddressUtils;
import com.tencent.polaris.api.exception.PolarisException; import com.tencent.polaris.api.exception.PolarisException;
import com.tencent.polaris.client.api.SDKContext; import com.tencent.polaris.client.api.SDKContext;
import com.tencent.polaris.factory.config.ConfigurationImpl; import com.tencent.polaris.factory.config.ConfigurationImpl;
@ -37,11 +36,10 @@ import org.springframework.context.annotation.Bean;
* *
* @author Haotian Zhang * @author Haotian Zhang
*/ */
@EnableConfigurationProperties(PolarisContextProperties.class) @EnableConfigurationProperties({ PolarisContextProperties.class,
InetUtilsProperties.class })
public class PolarisContextConfiguration { public class PolarisContextConfiguration {
private static final String ADDRESS_SEPARATOR = ",";
@Bean(name = "polarisContext", initMethod = "init", destroyMethod = "destroy") @Bean(name = "polarisContext", initMethod = "init", destroyMethod = "destroy")
@ConditionalOnMissingBean @ConditionalOnMissingBean
public SDKContext polarisContext(PolarisContextProperties properties) public SDKContext polarisContext(PolarisContextProperties properties)
@ -62,10 +60,14 @@ public class PolarisContextConfiguration {
@Override @Override
public void modify(ConfigurationImpl configuration) { public void modify(ConfigurationImpl configuration) {
if (!StringUtils.isBlank(properties.getAddress())) { if (StringUtils.isBlank(properties.getAddress())) {
configuration.getGlobal().getServerConnector() return;
.setAddresses(getAddressList(properties.getAddress()));
} }
List<String> addresses = AddressUtils
.parseAddressList(properties.getAddress());
configuration.getGlobal().getServerConnector().setAddresses(addresses);
} }
@Override @Override
@ -73,16 +75,6 @@ public class PolarisContextConfiguration {
return ModifierOrder.FIRST; return ModifierOrder.FIRST;
} }
private List<String> getAddressList(String addressInfo) {
List<String> addressList = new ArrayList<>();
String[] addresses = addressInfo.split(ADDRESS_SEPARATOR);
for (String address : addresses) {
URI uri = URI.create(address.trim());
addressList.add(uri.getAuthority());
}
return addressList;
}
} }
} }

@ -29,8 +29,8 @@ import com.tencent.polaris.factory.config.ConfigurationImpl;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.commons.util.InetUtilsProperties;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
@ -43,10 +43,16 @@ import org.springframework.util.CollectionUtils;
public class PolarisContextProperties { public class PolarisContextProperties {
/** /**
* polaris server adress. * polaris server address.
*/ */
private String address; private String address;
/**
* polaris namespace.
*/
@Value("${spring.cloud.polaris.namespace:#{'default'}}")
private String namespace;
@Autowired @Autowired
private InetUtilsProperties inetUtilsProperties; private InetUtilsProperties inetUtilsProperties;
@ -56,14 +62,6 @@ public class PolarisContextProperties {
@Autowired @Autowired
private List<PolarisConfigModifier> modifierList; private List<PolarisConfigModifier> modifierList;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
protected Configuration configuration() { protected Configuration configuration() {
ConfigurationImpl configuration = (ConfigurationImpl) ConfigAPIFactory ConfigurationImpl configuration = (ConfigurationImpl) ConfigAPIFactory
.defaultConfig(ConfigProvider.DEFAULT_CONFIG); .defaultConfig(ConfigProvider.DEFAULT_CONFIG);
@ -91,4 +89,20 @@ public class PolarisContextProperties {
return environment.getProperty("spring.cloud.client.ip-address"); return environment.getProperty("spring.cloud.client.ip-address");
} }
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getNamespace() {
return namespace;
}
public void setNamespace(String namespace) {
this.namespace = namespace;
}
} }

@ -12,6 +12,12 @@
"type": "java.lang.String", "type": "java.lang.String",
"description": "polaris server address list that can be separated by \",\"", "description": "polaris server address list that can be separated by \",\"",
"sourceType": "com.tencent.cloud.polaris.context.PolarisContextProperties" "sourceType": "com.tencent.cloud.polaris.context.PolarisContextProperties"
},
{
"name": "spring.cloud.polaris.namespace",
"type": "java.lang.String",
"description": "polaris namespace",
"sourceType": "com.tencent.cloud.polaris.context.PolarisContextProperties"
} }
], ],
"hints": [] "hints": []

@ -1,2 +1 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.cloud.bootstrap.BootstrapConfiguration=com.tencent.cloud.polaris.context.PolarisContextConfiguration
com.tencent.cloud.polaris.context.PolarisContextConfiguration

@ -24,12 +24,14 @@ import org.junit.platform.commons.util.StringUtils;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class) @RunWith(SpringRunner.class)
@SpringBootTest(classes = PolarisContextApplication.class, @SpringBootTest(classes = PolarisContextApplication.class,
properties = { "spring.config.location = classpath:application-test.yml" }) properties = { "spring.config.location = classpath:bootstrap.yml" })
@ImportAutoConfiguration({ PolarisContextConfiguration.class })
public class PolarisContextGetHostTest { public class PolarisContextGetHostTest {
@Autowired @Autowired
@ -39,7 +41,7 @@ public class PolarisContextGetHostTest {
public void testGetConfigHost() { public void testGetConfigHost() {
String bindIP = polarisContext.getConfig().getGlobal().getAPI().getBindIP(); String bindIP = polarisContext.getConfig().getGlobal().getAPI().getBindIP();
Assert.assertFalse(StringUtils.isBlank(bindIP)); Assert.assertFalse(StringUtils.isBlank(bindIP));
Assert.assertNotEquals(bindIP, "127.0.0.1"); Assert.assertEquals(bindIP, "192.168.1.1");
} }
} }

@ -1,4 +0,0 @@
spring:
cloud:
polaris:
address: grpc://127.0.0.1:8091

@ -0,0 +1,7 @@
spring:
cloud:
polaris:
address: grpc://127.0.0.1:8091
namespace: dev
inetutils:
defaultIpAddress: 192.168.1.1
Loading…
Cancel
Save