diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a4babd2..cf1e2dac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - [Feature: add rate limit filter debug log](https://github.com/Tencent/spring-cloud-tencent/pull/437) - [Add configurable heartbeat interval support](https://github.com/Tencent/spring-cloud-tencent/pull/444) - [feat:enhance Feign and RestTemplate and support Polaris monitor.](https://github.com/Tencent/spring-cloud-tencent/pull/447) +- [Feature: support spring cloud config data.](https://github.com/Tencent/spring-cloud-tencent/pull/451) - [Optimize feign & rest-template circuit-breaker logic](https://github.com/Tencent/spring-cloud-tencent/pull/454) - [Feature: Add disposable metadata transfer support](https://github.com/Tencent/spring-cloud-tencent/pull/459) - [docs:update mvnw.](https://github.com/Tencent/spring-cloud-tencent/pull/476) 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 a67c8a89..e558f61f 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 @@ -27,6 +27,7 @@ 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.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -50,6 +51,7 @@ public class PolarisConfigBootstrapAutoConfiguration { } @Bean + @ConditionalOnMissingBean public PolarisPropertySourceManager polarisPropertySourceManager() { return new PolarisPropertySourceManager(); } 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 a3ed86f1..b37568f9 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 @@ -17,21 +17,12 @@ package com.tencent.cloud.polaris.config.adapter; -import java.util.LinkedList; 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.config.PolarisContextProperties; -import com.tencent.polaris.configuration.api.core.ConfigFileMetadata; import com.tencent.polaris.configuration.api.core.ConfigFileService; -import com.tencent.polaris.configuration.api.core.ConfigKVFile; -import com.tencent.polaris.configuration.client.internal.DefaultConfigFileMetadata; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.springframework.cloud.bootstrap.config.PropertySourceLocator; import org.springframework.core.annotation.Order; @@ -39,7 +30,6 @@ 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. @@ -51,28 +41,18 @@ import org.springframework.util.StringUtils; @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; - - private final Environment environment; + private final PolarisConfigFilePuller polarisConfigFilePuller; public PolarisConfigFileLocator(PolarisConfigProperties polarisConfigProperties, PolarisContextProperties polarisContextProperties, ConfigFileService configFileService, PolarisPropertySourceManager polarisPropertySourceManager, Environment environment) { this.polarisConfigProperties = polarisConfigProperties; - this.polarisContextProperties = polarisContextProperties; - this.configFileService = configFileService; - this.polarisPropertySourceManager = polarisPropertySourceManager; - this.environment = environment; + this.polarisConfigFilePuller = PolarisConfigFilePuller.get(polarisContextProperties, configFileService, + polarisPropertySourceManager); } @Override @@ -81,126 +61,16 @@ public class PolarisConfigFileLocator implements PropertySourceLocator { POLARIS_CONFIG_PROPERTY_SOURCE_NAME); // load spring boot default config files - initInternalConfigFiles(compositePropertySource); + String[] activeProfiles = environment.getActiveProfiles(); + String serviceName = environment.getProperty("spring.application.name"); + polarisConfigFilePuller.initInternalConfigFiles(compositePropertySource, activeProfiles, serviceName); // load custom config files List configFileGroups = polarisConfigProperties.getGroups(); if (CollectionUtils.isEmpty(configFileGroups)) { return compositePropertySource; } - initCustomPolarisConfigFiles(compositePropertySource, configFileGroups); - + polarisConfigFilePuller.initCustomPolarisConfigFiles(compositePropertySource, configFileGroups); return compositePropertySource; } - - private void initInternalConfigFiles(CompositePropertySource compositePropertySource) { - List internalConfigFiles = getInternalConfigFiles(); - - for (ConfigFileMetadata configFile : internalConfigFiles) { - PolarisPropertySource polarisPropertySource = loadPolarisPropertySource( - configFile.getNamespace(), configFile.getFileGroup(), configFile.getFileName()); - - compositePropertySource.addPropertySource(polarisPropertySource); - - polarisPropertySourceManager.addPropertySource(polarisPropertySource); - - LOGGER.info("[SCT Config] Load and inject polaris config file. file = {}", configFile); - } - } - - private List getInternalConfigFiles() { - String namespace = polarisContextProperties.getNamespace(); - String serviceName = polarisContextProperties.getService(); - if (!StringUtils.hasText(serviceName)) { - serviceName = environment.getProperty("spring.application.name"); - } - - List internalConfigFiles = new LinkedList<>(); - - // priority: application-${profile} > application > boostrap-${profile} > boostrap - String[] activeProfiles = environment.getActiveProfiles(); - - for (String activeProfile : activeProfiles) { - if (!StringUtils.hasText(activeProfile)) { - continue; - } - - internalConfigFiles.add(new DefaultConfigFileMetadata(namespace, serviceName, "application-" + activeProfile + ".properties")); - internalConfigFiles.add(new DefaultConfigFileMetadata(namespace, serviceName, "application-" + activeProfile + ".yml")); - } - - internalConfigFiles.add(new DefaultConfigFileMetadata(namespace, serviceName, "application.properties")); - internalConfigFiles.add(new DefaultConfigFileMetadata(namespace, serviceName, "application.yml")); - - for (String activeProfile : activeProfiles) { - if (!StringUtils.hasText(activeProfile)) { - continue; - } - - internalConfigFiles.add(new DefaultConfigFileMetadata(namespace, serviceName, "bootstrap-" + activeProfile + ".properties")); - internalConfigFiles.add(new DefaultConfigFileMetadata(namespace, serviceName, "bootstrap-" + activeProfile + ".yml")); - } - - internalConfigFiles.add(new DefaultConfigFileMetadata(namespace, serviceName, "bootstrap.properties")); - internalConfigFiles.add(new DefaultConfigFileMetadata(namespace, serviceName, "bootstrap.yml")); - - - return internalConfigFiles; - } - - - private void initCustomPolarisConfigFiles(CompositePropertySource compositePropertySource, - List configFileGroups) { - String namespace = polarisContextProperties.getNamespace(); - - for (ConfigFileGroup configFileGroup : configFileGroups) { - String group = configFileGroup.getName(); - - if (!StringUtils.hasText(group)) { - throw new IllegalArgumentException("polaris config group name cannot be empty."); - } - - List 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 map = new ConcurrentHashMap<>(); - for (String key : configKVFile.getPropertyNames()) { - map.put(key, configKVFile.getProperty(key, null)); - } - - return new PolarisPropertySource(namespace, group, fileName, configKVFile, map); - } } diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFilePuller.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFilePuller.java new file mode 100644 index 00000000..f6b5631a --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFilePuller.java @@ -0,0 +1,195 @@ +/* + * 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.LinkedList; +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.configdata.PolarisConfigDataLoader; +import com.tencent.cloud.polaris.config.enums.ConfigFileFormat; +import com.tencent.cloud.polaris.context.config.PolarisContextProperties; +import com.tencent.polaris.configuration.api.core.ConfigFileMetadata; +import com.tencent.polaris.configuration.api.core.ConfigFileService; +import com.tencent.polaris.configuration.api.core.ConfigKVFile; +import com.tencent.polaris.configuration.client.internal.DefaultConfigFileMetadata; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.core.env.CompositePropertySource; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; + +/** + * PolarisConfigFilePuller pull configFile from Polaris. + * + * @author wlx + */ +public final class PolarisConfigFilePuller { + + private static final Logger LOGGER = LoggerFactory.getLogger(PolarisConfigFileLocator.class); + + private PolarisContextProperties polarisContextProperties; + + private ConfigFileService configFileService; + + private PolarisPropertySourceManager polarisPropertySourceManager; + + private PolarisConfigFilePuller() { + } + + /** + * InitInternalConfigFiles for {@link PolarisConfigDataLoader}. + * + * @param compositePropertySource compositePropertySource + * @param activeProfiles activeProfiles + * @param serviceName serviceName + */ + public void initInternalConfigFiles(CompositePropertySource compositePropertySource, String[] activeProfiles, String serviceName) { + List internalConfigFiles = getInternalConfigFiles(activeProfiles, serviceName); + for (ConfigFileMetadata configFile : internalConfigFiles) { + PolarisPropertySource polarisPropertySource = loadPolarisPropertySource( + configFile.getNamespace(), configFile.getFileGroup(), configFile.getFileName()); + compositePropertySource.addPropertySource(polarisPropertySource); + polarisPropertySourceManager.addPropertySource(polarisPropertySource); + LOGGER.info("[SCT Config] Load and inject polaris config file. file = {}", configFile); + } + } + + /** + * Init multiple CustomPolarisConfigFile. + * + * @param compositePropertySource compositePropertySource + * @param configFileGroups configFileGroups + */ + public void initCustomPolarisConfigFiles(CompositePropertySource compositePropertySource, + List configFileGroups) { + configFileGroups.forEach( + configFileGroup -> initCustomPolarisConfigFile(compositePropertySource, configFileGroup) + ); + } + + /** + * Init single CustomPolarisConfigFile. + * + * @param compositePropertySource compositePropertySource + * @param configFileGroup configFileGroup + */ + public void initCustomPolarisConfigFile(CompositePropertySource compositePropertySource, + ConfigFileGroup configFileGroup) { + String namespace = polarisContextProperties.getNamespace(); + String group = configFileGroup.getName(); + if (!StringUtils.hasText(group)) { + throw new IllegalArgumentException("polaris config group name cannot be empty."); + } + List 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 map = new ConcurrentHashMap<>(); + for (String key : configKVFile.getPropertyNames()) { + map.put(key, configKVFile.getProperty(key, null)); + } + return new PolarisPropertySource(namespace, group, fileName, configKVFile, map); + } + + + private List getInternalConfigFiles(String[] activeProfiles, String serviceName) { + String namespace = polarisContextProperties.getNamespace(); + if (StringUtils.hasText(polarisContextProperties.getService())) { + serviceName = polarisContextProperties.getService(); + } + // priority: application-${profile} > application > boostrap-${profile} > boostrap + return getInternalConfigFiles(activeProfiles, namespace, serviceName); + } + + private List getInternalConfigFiles(String[] activeProfiles, String namespace, String serviceName) { + List internalConfigFiles = new LinkedList<>(); + for (String activeProfile : activeProfiles) { + if (!StringUtils.hasText(activeProfile)) { + continue; + } + internalConfigFiles.add(new DefaultConfigFileMetadata(namespace, serviceName, "application-" + activeProfile + ".properties")); + internalConfigFiles.add(new DefaultConfigFileMetadata(namespace, serviceName, "application-" + activeProfile + ".yml")); + } + + internalConfigFiles.add(new DefaultConfigFileMetadata(namespace, serviceName, "application.properties")); + internalConfigFiles.add(new DefaultConfigFileMetadata(namespace, serviceName, "application.yml")); + + for (String activeProfile : activeProfiles) { + if (!StringUtils.hasText(activeProfile)) { + continue; + } + + internalConfigFiles.add(new DefaultConfigFileMetadata(namespace, serviceName, "bootstrap-" + activeProfile + ".properties")); + internalConfigFiles.add(new DefaultConfigFileMetadata(namespace, serviceName, "bootstrap-" + activeProfile + ".yml")); + } + + internalConfigFiles.add(new DefaultConfigFileMetadata(namespace, serviceName, "bootstrap.properties")); + internalConfigFiles.add(new DefaultConfigFileMetadata(namespace, serviceName, "bootstrap.yml")); + + return internalConfigFiles; + } + + /** + * Factory method to create PolarisConfigFilePuller for + * {@link PolarisConfigDataLoader},{@link PolarisConfigFileLocator}. + * + * @param polarisContextProperties polarisContextProperties + * @param configFileService configFileService + * @param polarisPropertySourceManager polarisPropertySourceManager + * @return PolarisConfigFilePuller instance + */ + public static PolarisConfigFilePuller get(PolarisContextProperties polarisContextProperties, ConfigFileService configFileService, + PolarisPropertySourceManager polarisPropertySourceManager) { + PolarisConfigFilePuller puller = new PolarisConfigFilePuller(); + puller.polarisContextProperties = polarisContextProperties; + puller.configFileService = configFileService; + puller.polarisPropertySourceManager = polarisPropertySourceManager; + return puller; + } +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/config/PolarisConfigProperties.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/config/PolarisConfigProperties.java index f39c5337..01bc70e6 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/config/PolarisConfigProperties.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/config/PolarisConfigProperties.java @@ -50,6 +50,12 @@ public class PolarisConfigProperties { */ private boolean autoRefresh = true; + /** + * When the local configuration is consistent with the remote configuration, whether to + * preferentially load the remote configuration. + */ + private boolean preference = true; + /** * List of injected configuration files. */ @@ -94,4 +100,12 @@ public class PolarisConfigProperties { public void setGroups(List groups) { this.groups = groups; } + + public boolean isPreference() { + return preference; + } + + public void setPreference(boolean preference) { + this.preference = preference; + } } diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/configdata/PolarisConfigDataLoader.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/configdata/PolarisConfigDataLoader.java new file mode 100644 index 00000000..9b0f0855 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/configdata/PolarisConfigDataLoader.java @@ -0,0 +1,152 @@ +/* + * 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.configdata; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +import com.tencent.cloud.polaris.config.adapter.PolarisConfigFilePuller; +import com.tencent.cloud.polaris.config.adapter.PolarisPropertySourceManager; +import com.tencent.cloud.polaris.config.config.ConfigFileGroup; +import com.tencent.cloud.polaris.config.config.PolarisConfigProperties; +import com.tencent.polaris.client.api.SDKContext; +import com.tencent.polaris.configuration.api.core.ConfigFileService; +import com.tencent.polaris.configuration.factory.ConfigFileServiceFactory; +import org.apache.commons.logging.Log; + +import org.springframework.boot.ConfigurableBootstrapContext; +import org.springframework.boot.context.config.ConfigData; +import org.springframework.boot.context.config.ConfigDataLoader; +import org.springframework.boot.context.config.ConfigDataLoaderContext; +import org.springframework.boot.context.config.ConfigDataResourceNotFoundException; +import org.springframework.boot.context.config.Profiles; +import org.springframework.boot.logging.DeferredLogFactory; +import org.springframework.core.env.CompositePropertySource; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; + +import static org.springframework.boot.context.config.ConfigData.Option.IGNORE_IMPORTS; +import static org.springframework.boot.context.config.ConfigData.Option.IGNORE_PROFILES; +import static org.springframework.boot.context.config.ConfigData.Option.PROFILE_SPECIFIC; + +/** + * Implementation of {@link ConfigDataLoader}.can be used to load {@link ConfigData} for a given + * {@link PolarisConfigDataResource} . + *

+ * Load {@link ConfigData} via {@link PolarisConfigDataLoader} + * + * @author wlx + * @date 2022/7/5 11:14 下午 + */ +public class PolarisConfigDataLoader implements ConfigDataLoader { + + private static final String POLARIS_CONFIG_PROPERTY_SOURCE_NAME = "polaris-config"; + + private final Log log; + + private ConfigFileService configFileService; + + private PolarisConfigFilePuller puller; + + static final AtomicBoolean INTERNAL_CONFIG_FILES_LOADED = new AtomicBoolean(false); + + static final AtomicBoolean CUSTOM_POLARIS_CONFIG_FILE_LOADED = new AtomicBoolean(false); + + public PolarisConfigDataLoader(DeferredLogFactory logFactory) { + this.log = logFactory.getLog(getClass()); + } + + @Override + public ConfigData load(ConfigDataLoaderContext context, PolarisConfigDataResource resource) + throws ConfigDataResourceNotFoundException { + try { + return load(context.getBootstrapContext(), resource); + } + catch (Exception e) { + log.warn("Error getting properties from polaris: " + resource, e); + if (!resource.isOptional()) { + throw new ConfigDataResourceNotFoundException(resource, e); + } + return null; + } + } + + public ConfigData load(ConfigurableBootstrapContext bootstrapContext, PolarisConfigDataResource resource) { + CompositePropertySource compositePropertySource = locate(bootstrapContext, resource); + return new ConfigData(compositePropertySource.getPropertySources(), getOptions(resource)); + } + + private CompositePropertySource locate(ConfigurableBootstrapContext bootstrapContext, + PolarisConfigDataResource resource) { + CompositePropertySource compositePropertySource = new CompositePropertySource( + POLARIS_CONFIG_PROPERTY_SOURCE_NAME); + SDKContext sdkContext = bootstrapContext.get(SDKContext.class); + if (null == this.configFileService) { + this.configFileService = ConfigFileServiceFactory.createConfigFileService(sdkContext); + } + if (null == this.puller) { + this.puller = PolarisConfigFilePuller.get(resource.getPolarisContextProperties(), + configFileService, bootstrapContext.get(PolarisPropertySourceManager.class)); + } + Profiles profiles = resource.getProfiles(); + if (INTERNAL_CONFIG_FILES_LOADED.compareAndSet(false, true)) { + log.info("loading internal config files"); + List profilesActive = profiles.getActive(); + String[] activeProfiles = profilesActive.toArray(new String[]{}); + this.puller.initInternalConfigFiles(compositePropertySource, activeProfiles, resource.getServiceName()); + } + + PolarisConfigProperties polarisConfigProperties = resource.getPolarisConfigProperties(); + if (!CollectionUtils.isEmpty(polarisConfigProperties.getGroups()) && + CUSTOM_POLARIS_CONFIG_FILE_LOADED.compareAndSet(false, true)) { + log.info("loading custom config files"); + this.puller.initCustomPolarisConfigFiles(compositePropertySource, + polarisConfigProperties.getGroups()); + } + // load config data + if (StringUtils.hasText(resource.getFileName())) { + log.info("loading config data config file, group:" + resource.getGroupName() + " file: " + resource.getFileName()); + this.puller.initCustomPolarisConfigFile(compositePropertySource, configFileGroup(resource)); + } + return compositePropertySource; + } + + private ConfigData.Option[] getOptions(PolarisConfigDataResource resource) { + List options = new ArrayList<>(); + options.add(IGNORE_IMPORTS); + options.add(IGNORE_PROFILES); + PolarisConfigProperties polarisConfigProperties = resource.getPolarisConfigProperties(); + if (polarisConfigProperties.isPreference()) { + // mark it as 'PROFILE_SPECIFIC' config, it has higher priority + options.add(PROFILE_SPECIFIC); + } + return options.toArray(new ConfigData.Option[]{}); + } + + private ConfigFileGroup configFileGroup(PolarisConfigDataResource polarisConfigDataResource) { + String fileName = polarisConfigDataResource.getFileName(); + String groupName = polarisConfigDataResource.getGroupName(); + ConfigFileGroup configFileGroup = new ConfigFileGroup(); + configFileGroup.setName(groupName); + List files = new ArrayList<>(); + files.add(fileName); + configFileGroup.setFiles(files); + return configFileGroup; + } +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/configdata/PolarisConfigDataLocationResolver.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/configdata/PolarisConfigDataLocationResolver.java new file mode 100644 index 00000000..a3554c5f --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/configdata/PolarisConfigDataLocationResolver.java @@ -0,0 +1,291 @@ +/* + * 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.configdata; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +import com.tencent.cloud.polaris.config.ConfigurationModifier; +import com.tencent.cloud.polaris.config.adapter.PolarisPropertySourceManager; +import com.tencent.cloud.polaris.config.config.PolarisConfigProperties; +import com.tencent.cloud.polaris.context.ModifyAddress; +import com.tencent.cloud.polaris.context.PolarisConfigModifier; +import com.tencent.cloud.polaris.context.config.PolarisContextProperties; +import com.tencent.polaris.api.utils.StringUtils; +import com.tencent.polaris.client.api.SDKContext; +import org.apache.commons.logging.Log; + +import org.springframework.boot.BootstrapRegistry; +import org.springframework.boot.ConfigurableBootstrapContext; +import org.springframework.boot.context.config.ConfigDataLocation; +import org.springframework.boot.context.config.ConfigDataLocationNotFoundException; +import org.springframework.boot.context.config.ConfigDataLocationResolver; +import org.springframework.boot.context.config.ConfigDataLocationResolverContext; +import org.springframework.boot.context.config.ConfigDataResourceNotFoundException; +import org.springframework.boot.context.config.Profiles; +import org.springframework.boot.context.properties.bind.BindHandler; +import org.springframework.boot.context.properties.bind.Bindable; +import org.springframework.boot.context.properties.bind.Binder; +import org.springframework.boot.logging.DeferredLogFactory; +import org.springframework.core.Ordered; + +/** + * Implementation of {@link ConfigDataLocationResolver}, used to resolve {@link ConfigDataLocation locations} + * into one or more {@link PolarisConfigDataResource polarisConfigDataResource}. + * + * @author wlx + */ +public class PolarisConfigDataLocationResolver implements + ConfigDataLocationResolver, Ordered { + + + /** + * Prefix for Config Server imports. + */ + public static final String PREFIX = "polaris"; + + /** + * Prefix for Polaris configurationProperties. + */ + public static final String POLARIS_PREFIX = "spring.cloud.polaris"; + + /** + * COLON. + */ + public static final String COLON = ":"; + + /** + * Empty String. + */ + public static final String EMPTY_STRING = ""; + + private final Log log; + + public PolarisConfigDataLocationResolver(DeferredLogFactory logFactory) { + this.log = logFactory.getLog(getClass()); + } + + @Override + public boolean isResolvable(ConfigDataLocationResolverContext context, ConfigDataLocation location) { + if (!location.hasPrefix(PREFIX)) { + return false; + } + return context.getBinder() + .bind("spring.cloud.polaris.config.enabled", Boolean.class) + .orElse(true); + } + + @Override + public List resolve( + ConfigDataLocationResolverContext context, ConfigDataLocation location) + throws ConfigDataLocationNotFoundException, + ConfigDataResourceNotFoundException { + return Collections.emptyList(); + } + + + @Override + public List resolveProfileSpecific( + ConfigDataLocationResolverContext resolverContext, + ConfigDataLocation location, Profiles profiles) + throws ConfigDataLocationNotFoundException { + + ConfigurableBootstrapContext bootstrapContext = resolverContext.getBootstrapContext(); + + PolarisConfigProperties polarisConfigProperties = loadPolarisConfigProperties( + resolverContext, + PolarisConfigProperties.class, + POLARIS_PREFIX + ".config" + ); + if (Objects.isNull(polarisConfigProperties)) { + polarisConfigProperties = new PolarisConfigProperties(); + } + + PolarisContextProperties polarisContextProperties = loadPolarisConfigProperties( + resolverContext, + PolarisContextProperties.class, + POLARIS_PREFIX + ); + if (Objects.isNull(polarisContextProperties)) { + polarisContextProperties = new PolarisContextProperties(); + } + + // prepare and init earlier Polaris SDKContext to pull config files from remote. + prepareAndInitEarlierPolarisSdkContext(resolverContext, polarisConfigProperties, polarisContextProperties); + + bootstrapContext.registerIfAbsent(PolarisConfigProperties.class, + BootstrapRegistry.InstanceSupplier.of(polarisConfigProperties)); + + bootstrapContext.registerIfAbsent(PolarisContextProperties.class, + BootstrapRegistry.InstanceSupplier.of(polarisContextProperties)); + + bootstrapContext.registerIfAbsent(PolarisPropertySourceManager.class, + BootstrapRegistry.InstanceSupplier.of(new PolarisPropertySourceManager())); + + bootstrapContext.addCloseListener( + event -> { + // destroy earlier Polaris sdkContext + event.getBootstrapContext().get(SDKContext.class).destroy(); + // register PolarisPropertySourceManager to context + PolarisPropertySourceManager polarisPropertySourceManager = event.getBootstrapContext().get(PolarisPropertySourceManager.class); + event.getApplicationContext().getBeanFactory().registerSingleton( + "polarisPropertySourceManager", polarisPropertySourceManager); + } + ); + + return loadConfigDataResources(resolverContext, + location, profiles, polarisConfigProperties, polarisContextProperties); + } + + @Override + public int getOrder() { + return -1; + } + + protected T loadPolarisConfigProperties( + ConfigDataLocationResolverContext context, + Class typeClass, + String prefix) { + Binder binder = context.getBinder(); + BindHandler bindHandler = getBindHandler(context); + + T instance; + if (!registerNotNecessary(typeClass) && context.getBootstrapContext().isRegistered(typeClass)) { + instance = context.getBootstrapContext().get(typeClass); + } + else { + instance = binder.bind(prefix, Bindable.of(typeClass), bindHandler) + .map(properties -> binder.bind(prefix, Bindable.ofInstance(properties), bindHandler) + .orElse(properties)) + .orElseGet(() -> binder.bind(prefix, Bindable.of(typeClass), bindHandler) + .orElseGet(() -> null)); + } + return instance; + } + + private BindHandler getBindHandler(ConfigDataLocationResolverContext context) { + return context.getBootstrapContext().getOrElse(BindHandler.class, null); + } + + private List loadConfigDataResources(ConfigDataLocationResolverContext resolverContext, + ConfigDataLocation location, + Profiles profiles, + PolarisConfigProperties polarisConfigProperties, + PolarisContextProperties polarisContextProperties) { + List result = new ArrayList<>(); + boolean optional = location.isOptional(); + String groupFileName = getRealGroupFileName(location); + String serviceName = loadPolarisConfigProperties(resolverContext, + String.class, "spring.application.name"); + if (StringUtils.isBlank(serviceName)) { + serviceName = "application"; + log.warn("No spring.application.name found, defaulting to 'application'"); + } + String groupName = StringUtils.isBlank(groupFileName) ? EMPTY_STRING : parseGroupName(groupFileName, serviceName); + if (StringUtils.isNotBlank(groupName)) { + log.info("group from configDataLocation is " + groupName); + } + String fileName = StringUtils.isBlank(groupFileName) ? EMPTY_STRING : parseFileName(groupFileName); + if (StringUtils.isNotBlank(fileName)) { + log.info("file from configDataLocation is " + fileName); + } + PolarisConfigDataResource polarisConfigDataResource = new PolarisConfigDataResource( + polarisConfigProperties, + polarisContextProperties, + profiles, optional, + fileName, groupName, serviceName + ); + result.add(polarisConfigDataResource); + return result; + } + + private String getRealGroupFileName(ConfigDataLocation location) { + String prefixedValue = location.getNonPrefixedValue(PREFIX); + if (StringUtils.isBlank(prefixedValue) || !prefixedValue.startsWith(COLON)) { + return prefixedValue; + } + return prefixedValue.substring(1); + } + + private String parseFileName(String groupFileName) { + String[] split = groupFileName.split(COLON); + if (split.length > 1) { + return split[1]; + } + else { + return split[0]; + } + } + + private String parseGroupName(String groupFileName, String serviceName) { + String[] split = groupFileName.split(COLON); + if (split.length > 1) { + return split[0]; + } + else { + return serviceName; + } + } + + private void prepareAndInitEarlierPolarisSdkContext(ConfigDataLocationResolverContext resolverContext, + PolarisConfigProperties polarisConfigProperties, + PolarisContextProperties polarisContextProperties) { + ConfigurableBootstrapContext bootstrapContext = resolverContext.getBootstrapContext(); + if (!bootstrapContext.isRegistered(SDKContext.class)) { + SDKContext sdkContext = sdkContext(resolverContext, + polarisConfigProperties, polarisContextProperties); + sdkContext.init(); + bootstrapContext.register(SDKContext.class, BootstrapRegistry.InstanceSupplier.of(sdkContext)); + } + + } + + private SDKContext sdkContext(ConfigDataLocationResolverContext resolverContext, + PolarisConfigProperties polarisConfigProperties, + PolarisContextProperties polarisContextProperties) { + List modifierList = modifierList(polarisConfigProperties, polarisContextProperties); + return SDKContext.initContextByConfig(polarisContextProperties.configuration(modifierList, () -> { + return loadPolarisConfigProperties(resolverContext, String.class, "spring.cloud.client.ip-address"); + })); + } + + private List modifierList(PolarisConfigProperties polarisConfigProperties, + PolarisContextProperties polarisContextProperties) { + // add ModifyAddress and ConfigurationModifier to load SDKContext + List modifierList = new ArrayList<>(); + ModifyAddress modifyAddress = new ModifyAddress(); + modifyAddress.setProperties(polarisContextProperties); + + ConfigurationModifier configurationModifier = new ConfigurationModifier(polarisConfigProperties, + polarisContextProperties); + modifierList.add(modifyAddress); + modifierList.add(configurationModifier); + return modifierList; + } + + private boolean registerNotNecessary(Class typeClass) { + return typeClass.isPrimitive() || + Number.class.isAssignableFrom(typeClass) || + String.class.isAssignableFrom(typeClass) || + Character.class.isAssignableFrom(typeClass) || + Boolean.class.isAssignableFrom(typeClass); + } +} + diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/configdata/PolarisConfigDataMissingEnvironmentPostProcessor.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/configdata/PolarisConfigDataMissingEnvironmentPostProcessor.java new file mode 100644 index 00000000..6c946e6c --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/configdata/PolarisConfigDataMissingEnvironmentPostProcessor.java @@ -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.configdata; + +import org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor; +import org.springframework.cloud.commons.ConfigDataMissingEnvironmentPostProcessor; +import org.springframework.cloud.util.PropertyUtils; +import org.springframework.core.env.Environment; + +/** + * PolarisConfigDataMissingEnvironmentPostProcessor to check if miss PolarisConfigData config,if miss config + * will throw {@link ImportException}. + * + * @author wlx + * @see ConfigDataMissingEnvironmentPostProcessor + * @see ConfigDataMissingEnvironmentPostProcessor.ImportException + */ +public class PolarisConfigDataMissingEnvironmentPostProcessor extends ConfigDataMissingEnvironmentPostProcessor { + + /** + * run after {@link ConfigDataEnvironmentPostProcessor}. + */ + public static final int ORDER = ConfigDataEnvironmentPostProcessor.ORDER + 1; + + @Override + public int getOrder() { + return ORDER; + } + + @Override + protected boolean shouldProcessEnvironment(Environment environment) { + // if using bootstrap or legacy processing don't run + if (!PropertyUtils.bootstrapEnabled(environment) && !PropertyUtils.useLegacyProcessing(environment)) { + boolean configEnabled = environment.getProperty("spring.cloud.polaris.config.enabled", Boolean.class, true); + boolean importCheckEnabled = environment.getProperty("spring.cloud.polaris.config.import-check.enabled", Boolean.class, true); + return configEnabled && importCheckEnabled; + } + else { + return false; + } + } + + @Override + protected String getPrefix() { + return PolarisConfigDataLocationResolver.PREFIX; + } +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/configdata/PolarisConfigDataResource.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/configdata/PolarisConfigDataResource.java new file mode 100644 index 00000000..04b81a48 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/configdata/PolarisConfigDataResource.java @@ -0,0 +1,114 @@ +/* + * 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.configdata; + +import java.util.Objects; + +import com.tencent.cloud.polaris.config.config.PolarisConfigProperties; +import com.tencent.cloud.polaris.context.config.PolarisContextProperties; + +import org.springframework.boot.context.config.ConfigData; +import org.springframework.boot.context.config.ConfigDataResource; +import org.springframework.boot.context.config.Profiles; + +/** + * A polaris configData resource from which {@link ConfigData} can be loaded. + * + * @author wlx + * @date 2022/7/5 11:13 下午 + */ +public class PolarisConfigDataResource extends ConfigDataResource { + + private final PolarisConfigProperties polarisConfigProperties; + + private final PolarisContextProperties polarisContextProperties; + + private final Profiles profiles; + + private final boolean optional; + + private final String fileName; + + private final String groupName; + + private final String serviceName; + + public PolarisConfigDataResource(PolarisConfigProperties polarisConfigProperties, + PolarisContextProperties polarisContextProperties, + Profiles profiles, boolean optional, + String fileName, String groupName, String serviceName) { + this.polarisConfigProperties = polarisConfigProperties; + this.polarisContextProperties = polarisContextProperties; + this.profiles = profiles; + this.optional = optional; + this.fileName = fileName; + this.groupName = groupName; + this.serviceName = serviceName; + } + + public PolarisConfigProperties getPolarisConfigProperties() { + return polarisConfigProperties; + } + + public PolarisContextProperties getPolarisContextProperties() { + return polarisContextProperties; + } + + public Profiles getProfiles() { + return profiles; + } + + public boolean isOptional() { + return optional; + } + + public String getFileName() { + return fileName; + } + + public String getGroupName() { + return groupName; + } + + public String getServiceName() { + return serviceName; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + PolarisConfigDataResource that = (PolarisConfigDataResource) o; + return optional == that.optional && + polarisConfigProperties.equals(that.polarisConfigProperties) && + polarisContextProperties.equals(that.polarisContextProperties) && + profiles.equals(that.profiles) && + fileName.equals(that.fileName) && + groupName.equals(that.groupName) && + serviceName.equals(that.serviceName); + } + + @Override + public int hashCode() { + return Objects.hash(polarisConfigProperties, polarisContextProperties, profiles, optional, fileName, groupName, serviceName); + } +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/configdata/PolarisImportExceptionFailureAnalyzer.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/configdata/PolarisImportExceptionFailureAnalyzer.java new file mode 100644 index 00000000..fd626b6d --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/configdata/PolarisImportExceptionFailureAnalyzer.java @@ -0,0 +1,35 @@ +package com.tencent.cloud.polaris.config.configdata; + +import org.springframework.boot.diagnostics.AbstractFailureAnalyzer; +import org.springframework.boot.diagnostics.FailureAnalysis; +import org.springframework.cloud.commons.ConfigDataMissingEnvironmentPostProcessor; + +/** + * Class for most {@code FailureAnalyzer} implementations, to analyze ImportException when + * miss Polaris configData config. + *

Refer to the Nacos project implementation: + * + * ImportExceptionFailureAnalyzer + * + * @author wlx + * @see AbstractFailureAnalyzer + */ +public class PolarisImportExceptionFailureAnalyzer extends + AbstractFailureAnalyzer { + + @Override + protected FailureAnalysis analyze(Throwable rootFailure, ConfigDataMissingEnvironmentPostProcessor.ImportException cause) { + String description; + if (cause.missingPrefix) { + description = "The spring.config.import property is missing a " + PolarisConfigDataLocationResolver.PREFIX + + " entry"; + } + else { + description = "No spring.config.import property has been defined"; + } + String action = "Add a spring.config.import=polaris property to your configuration.\n" + + "\tIf configuration is not required add spring.config.import=optional:polaris instead.\n" + + "\tTo disable this check, set spring.cloud.polaris.config.import-check.enabled=false."; + return new FailureAnalysis(description, action, cause); + } +} 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 9954a62c..09c3e0f6 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 @@ -41,6 +41,18 @@ "defaultValue": "true", "description": "Whether to connect to a remote server, suitable for local development mode.", "sourceType": "com.tencent.cloud.polaris.config.config.PolarisConfigProperties" + }, + { + "name": "spring.cloud.polaris.config.import-check.enabled", + "type": "java.lang.Boolean", + "defaultValue": true, + "description": "Whether to enable import-check." + }, + { + "name": "spring.cloud.polaris.config.preference", + "type": "java.lang.Boolean", + "defaultValue": true, + "description": "Whether to preferentially load the remote configuration." } ] } diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/resources/META-INF/spring.factories b/spring-cloud-starter-tencent-polaris-config/src/main/resources/META-INF/spring.factories index 98221a39..d51d4f58 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-starter-tencent-polaris-config/src/main/resources/META-INF/spring.factories @@ -2,4 +2,17 @@ org.springframework.cloud.bootstrap.BootstrapConfiguration=\ com.tencent.cloud.polaris.config.PolarisConfigBootstrapAutoConfiguration org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.tencent.cloud.polaris.config.PolarisConfigAutoConfiguration,\ - com.tencent.cloud.polaris.config.endpoint.PolarisConfigEndpointAutoConfiguration + com.tencent.cloud.polaris.config.endpoint.PolarisConfigEndpointAutoConfiguration,\ + com.tencent.cloud.polaris.config.PolarisConfigBootstrapAutoConfiguration + +# ConfigData Location Resolvers +org.springframework.boot.context.config.ConfigDataLocationResolver=\ + com.tencent.cloud.polaris.config.configdata.PolarisConfigDataLocationResolver +# ConfigData Loaders +org.springframework.boot.context.config.ConfigDataLoader=\ + com.tencent.cloud.polaris.config.configdata.PolarisConfigDataLoader +org.springframework.boot.diagnostics.FailureAnalyzer=\ + com.tencent.cloud.polaris.config.configdata.PolarisImportExceptionFailureAnalyzer +org.springframework.boot.env.EnvironmentPostProcessor=\ + com.tencent.cloud.polaris.config.configdata.PolarisConfigDataMissingEnvironmentPostProcessor + 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 index bfe1fc5d..835b83a7 100644 --- 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 @@ -42,8 +42,7 @@ import static org.mockito.Mockito.when; /** * test for {@link PolarisConfigFileLocator}. - * - * @author lepdou 2022-06-11 + *@author lepdou 2022-06-11 */ @RunWith(MockitoJUnitRunner.class) public class PolarisConfigFileLocatorTest { diff --git a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFilePullerTest.java b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFilePullerTest.java new file mode 100644 index 00000000..3d5ef742 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigFilePullerTest.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.util.ArrayList; +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.context.config.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.CompositePropertySource; + +import static org.mockito.Mockito.when; + +/** + * Test for {@link PolarisConfigFilePuller}. + * + * @author wlx + */ +@RunWith(MockitoJUnitRunner.class) +public class PolarisConfigFilePullerTest { + + @Mock + private PolarisContextProperties polarisContextProperties; + @Mock + private ConfigFileService configFileService; + @Mock + private PolarisPropertySourceManager polarisPropertySourceManager; + + private final String testNamespace = "testNamespace"; + private final String testServiceName = "testServiceName"; + private final String polarisConfigPropertySourceName = "polaris-config"; + + @Test + public void testPullInternalConfigFiles() { + PolarisConfigFilePuller puller = PolarisConfigFilePuller.get(polarisContextProperties, configFileService, + polarisPropertySourceManager); + + 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); + CompositePropertySource compositePropertySource = new CompositePropertySource(polarisConfigPropertySourceName); + + puller.initInternalConfigFiles(compositePropertySource, new String[]{}, testServiceName); + + Assert.assertEquals("v1", compositePropertySource.getProperty("k1")); + Assert.assertEquals("v2", compositePropertySource.getProperty("k2")); + Assert.assertEquals("v3", compositePropertySource.getProperty("k3")); + } + + @Test + public void testPullInternalConfigFilesWithProfile() { + PolarisConfigFilePuller puller = PolarisConfigFilePuller.get(polarisContextProperties, configFileService, + polarisPropertySourceManager); + + 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); + List active = new ArrayList<>(); + active.add("dev"); + String[] activeProfiles = active.toArray(new String[]{}); + CompositePropertySource compositePropertySource = new CompositePropertySource(polarisConfigPropertySourceName); + puller.initInternalConfigFiles(compositePropertySource, activeProfiles, testServiceName); + + Assert.assertEquals("v11", compositePropertySource.getProperty("k1")); + Assert.assertEquals("v2", compositePropertySource.getProperty("k2")); + Assert.assertEquals("v3", compositePropertySource.getProperty("k3")); + } + + @Test + public void testPullCustomConfigFilesWithProfile() { + PolarisConfigFilePuller puller = PolarisConfigFilePuller.get(polarisContextProperties, configFileService, + polarisPropertySourceManager); + + when(polarisContextProperties.getNamespace()).thenReturn(testNamespace); + + 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); + + // 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); + + CompositePropertySource compositePropertySource = new CompositePropertySource(polarisConfigPropertySourceName); + puller.initCustomPolarisConfigFiles(compositePropertySource, customFiles); + + Assert.assertEquals("v1", compositePropertySource.getProperty("k1")); + Assert.assertEquals("v2", compositePropertySource.getProperty("k2")); + Assert.assertEquals("v3", compositePropertySource.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 index 779ddfb4..f6629736 100644 --- 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 @@ -39,8 +39,7 @@ import static org.mockito.Mockito.when; /** * test for {@link PolarisPropertySourceAutoRefresher}. - * - * @author lepdou 2022-06-11 + *@author lepdou 2022-06-11 */ @RunWith(MockitoJUnitRunner.class) public class PolarisPropertiesSourceAutoRefresherTest { diff --git a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/configdata/PolarisConfigDataLoaderTest.java b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/configdata/PolarisConfigDataLoaderTest.java new file mode 100644 index 00000000..a9dcdce2 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/configdata/PolarisConfigDataLoaderTest.java @@ -0,0 +1,288 @@ +/* + * 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.configdata; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.google.common.collect.Lists; +import com.tencent.cloud.polaris.config.adapter.MockedConfigKVFile; +import com.tencent.cloud.polaris.config.adapter.PolarisPropertySourceManager; +import com.tencent.cloud.polaris.config.config.PolarisConfigProperties; +import com.tencent.cloud.polaris.context.config.PolarisContextProperties; +import com.tencent.polaris.client.api.SDKContext; +import com.tencent.polaris.configuration.api.core.ConfigFileService; +import com.tencent.polaris.configuration.api.core.ConfigKVFile; +import com.tencent.polaris.configuration.factory.ConfigFileServiceFactory; +import org.junit.Assert; +import org.junit.Test; +import org.junit.jupiter.api.AfterAll; +import org.junit.runner.RunWith; +import org.mockito.MockedStatic; +import org.mockito.junit.MockitoJUnitRunner; + +import org.springframework.boot.ConfigurableBootstrapContext; +import org.springframework.boot.context.config.ConfigData; +import org.springframework.boot.context.config.ConfigDataLoaderContext; +import org.springframework.boot.context.config.Profiles; +import org.springframework.boot.logging.DeferredLogs; +import org.springframework.core.env.CompositePropertySource; +import org.springframework.core.env.PropertySource; + +import static com.tencent.cloud.polaris.config.configdata.PolarisConfigDataLoader.CUSTOM_POLARIS_CONFIG_FILE_LOADED; +import static com.tencent.cloud.polaris.config.configdata.PolarisConfigDataLoader.INTERNAL_CONFIG_FILES_LOADED; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.when; + +/** + * Test for {@link PolarisConfigDataLoader}. + * + * @author wlx + */ +@RunWith(MockitoJUnitRunner.class) +public class PolarisConfigDataLoaderTest { + + private static final SDKContext sdkContext = SDKContext.initContext(); + + private final String testNamespace = "testNamespace"; + private final String testServiceName = "testServiceName"; + private final String polarisConfigPropertySourceName = "polaris-config"; + + @Test + public void loadConfigDataInternalConfigFilesTest() { + try (MockedStatic mockedStatic = mockStatic(ConfigFileServiceFactory.class)) { + ConfigDataLoaderContext context = mock(ConfigDataLoaderContext.class); + PolarisConfigDataResource polarisConfigDataResource = mock(PolarisConfigDataResource.class); + ConfigurableBootstrapContext bootstrapContext = mock(ConfigurableBootstrapContext.class); + PolarisConfigProperties polarisConfigProperties = mock(PolarisConfigProperties.class); + PolarisContextProperties polarisContextProperties = mock(PolarisContextProperties.class); + ConfigFileService configFileService = mock(ConfigFileService.class); + Profiles profiles = mock(Profiles.class); + 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); + 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); + when(context.getBootstrapContext()).thenReturn(bootstrapContext); + when(bootstrapContext.get(eq(SDKContext.class))).thenReturn(sdkContext); + + when(bootstrapContext.get(eq(PolarisPropertySourceManager.class))).thenReturn(new PolarisPropertySourceManager()); + + when(polarisContextProperties.getNamespace()).thenReturn(testNamespace); + when(polarisContextProperties.getService()).thenReturn(testServiceName); + + when(polarisConfigProperties.getGroups()).thenReturn(null); + when(profiles.getActive()).thenReturn(Lists.newArrayList()); + + PolarisConfigDataLoader polarisConfigDataLoader = new PolarisConfigDataLoader(new DeferredLogs()); + if (INTERNAL_CONFIG_FILES_LOADED.get()) { + INTERNAL_CONFIG_FILES_LOADED.compareAndSet(true, false); + } + if (CUSTOM_POLARIS_CONFIG_FILE_LOADED.get()) { + CUSTOM_POLARIS_CONFIG_FILE_LOADED.compareAndSet(true, false); + } + when(polarisConfigDataResource.getPolarisConfigProperties()).thenReturn(polarisConfigProperties); + when(polarisConfigDataResource.getPolarisContextProperties()).thenReturn(polarisContextProperties); + when(polarisConfigDataResource.getServiceName()).thenReturn(testServiceName); + when(polarisConfigDataResource.getProfiles()).thenReturn(profiles); + + mockedStatic.when(() -> { + ConfigFileServiceFactory.createConfigFileService(sdkContext); + }).thenReturn(configFileService); + + ConfigData configData = polarisConfigDataLoader.load(context, polarisConfigDataResource); + List> propertySources = configData.getPropertySources(); + CompositePropertySource compositePropertySource = new CompositePropertySource(polarisConfigPropertySourceName); + propertySources.forEach(compositePropertySource::addPropertySource); + Assert.assertEquals("v1", compositePropertySource.getProperty("k1")); + Assert.assertEquals("v2", compositePropertySource.getProperty("k2")); + Assert.assertEquals("v3", compositePropertySource.getProperty("k3")); + } + } + + @Test + public void loadConfigDataInternalConfigFilesTestWithProfile() { + try (MockedStatic mockedStatic = mockStatic(ConfigFileServiceFactory.class)) { + ConfigDataLoaderContext context = mock(ConfigDataLoaderContext.class); + PolarisConfigDataResource polarisConfigDataResource = mock(PolarisConfigDataResource.class); + ConfigurableBootstrapContext bootstrapContext = mock(ConfigurableBootstrapContext.class); + PolarisConfigProperties polarisConfigProperties = mock(PolarisConfigProperties.class); + PolarisContextProperties polarisContextProperties = mock(PolarisContextProperties.class); + ConfigFileService configFileService = mock(ConfigFileService.class); + Profiles profiles = mock(Profiles.class); + 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(polarisConfigProperties.getGroups()).thenReturn(null); + List active = new ArrayList<>(); + active.add("dev"); + when(profiles.getActive()).thenReturn(active); + + when(context.getBootstrapContext()).thenReturn(bootstrapContext); + when(bootstrapContext.get(eq(SDKContext.class))).thenReturn(sdkContext); + when(bootstrapContext.get(eq(PolarisPropertySourceManager.class))).thenReturn(new PolarisPropertySourceManager()); + + when(polarisContextProperties.getNamespace()).thenReturn(testNamespace); + when(polarisContextProperties.getService()).thenReturn(testServiceName); + + when(polarisConfigProperties.getGroups()).thenReturn(null); + + PolarisConfigDataLoader polarisConfigDataLoader = new PolarisConfigDataLoader(new DeferredLogs()); + if (INTERNAL_CONFIG_FILES_LOADED.get()) { + INTERNAL_CONFIG_FILES_LOADED.compareAndSet(true, false); + } + if (CUSTOM_POLARIS_CONFIG_FILE_LOADED.get()) { + CUSTOM_POLARIS_CONFIG_FILE_LOADED.compareAndSet(true, false); + } + when(polarisConfigDataResource.getPolarisConfigProperties()).thenReturn(polarisConfigProperties); + when(polarisConfigDataResource.getPolarisContextProperties()).thenReturn(polarisContextProperties); + when(polarisConfigDataResource.getServiceName()).thenReturn(testServiceName); + when(polarisConfigDataResource.getProfiles()).thenReturn(profiles); + + mockedStatic.when(() -> { + ConfigFileServiceFactory.createConfigFileService(sdkContext); + }).thenReturn(configFileService); + + ConfigData configData = polarisConfigDataLoader.load(context, polarisConfigDataResource); + List> propertySources = configData.getPropertySources(); + + CompositePropertySource compositePropertySource = new CompositePropertySource(polarisConfigPropertySourceName); + propertySources.forEach(compositePropertySource::addPropertySource); + + Assert.assertEquals("v11", compositePropertySource.getProperty("k1")); + Assert.assertEquals("v2", compositePropertySource.getProperty("k2")); + Assert.assertEquals("v3", compositePropertySource.getProperty("k3")); + + } + } + + @Test + public void loadConfigDataCustomConfigFilesTestWithProfile() { + try (MockedStatic mockedStatic = mockStatic(ConfigFileServiceFactory.class)) { + ConfigDataLoaderContext context = mock(ConfigDataLoaderContext.class); + PolarisConfigDataResource polarisConfigDataResource = mock(PolarisConfigDataResource.class); + ConfigurableBootstrapContext bootstrapContext = mock(ConfigurableBootstrapContext.class); + PolarisConfigProperties polarisConfigProperties = mock(PolarisConfigProperties.class); + PolarisContextProperties polarisContextProperties = mock(PolarisContextProperties.class); + ConfigFileService configFileService = mock(ConfigFileService.class); + Profiles profiles = mock(Profiles.class); + 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); + + String customGroup = "group1"; + String customFile1 = "file1.properties"; + when(polarisConfigDataResource.getFileName()).thenReturn(customFile1); + when(polarisConfigDataResource.getGroupName()).thenReturn(customGroup); + + when(polarisConfigProperties.getGroups()).thenReturn(null); + when(profiles.getActive()).thenReturn(Lists.newArrayList()); + + // file1.properties + Map file1Map = new HashMap<>(); + file1Map.put("k1", "v1"); + file1Map.put("k2", "v2"); + file1Map.put("k3", "v3"); + ConfigKVFile file1 = new MockedConfigKVFile(file1Map); + when(configFileService.getConfigPropertiesFile(testNamespace, customGroup, customFile1)).thenReturn(file1); + + when(context.getBootstrapContext()).thenReturn(bootstrapContext); + when(bootstrapContext.get(eq(SDKContext.class))).thenReturn(sdkContext); + + when(bootstrapContext.get(eq(PolarisPropertySourceManager.class))).thenReturn(new PolarisPropertySourceManager()); + + when(polarisContextProperties.getNamespace()).thenReturn(testNamespace); + when(polarisContextProperties.getService()).thenReturn(testServiceName); + + when(polarisConfigProperties.getGroups()).thenReturn(null); + when(profiles.getActive()).thenReturn(Lists.newArrayList()); + + PolarisConfigDataLoader polarisConfigDataLoader = new PolarisConfigDataLoader(new DeferredLogs()); + + if (INTERNAL_CONFIG_FILES_LOADED.get()) { + INTERNAL_CONFIG_FILES_LOADED.compareAndSet(true, false); + } + if (CUSTOM_POLARIS_CONFIG_FILE_LOADED.get()) { + CUSTOM_POLARIS_CONFIG_FILE_LOADED.compareAndSet(true, false); + } + when(polarisConfigDataResource.getPolarisConfigProperties()).thenReturn(polarisConfigProperties); + when(polarisConfigDataResource.getPolarisContextProperties()).thenReturn(polarisContextProperties); + when(polarisConfigDataResource.getServiceName()).thenReturn(testServiceName); + when(polarisConfigDataResource.getProfiles()).thenReturn(profiles); + + mockedStatic.when(() -> { + ConfigFileServiceFactory.createConfigFileService(sdkContext); + }).thenReturn(configFileService); + + ConfigData configData = polarisConfigDataLoader.load(context, polarisConfigDataResource); + List> propertySources = configData.getPropertySources(); + CompositePropertySource compositePropertySource = new CompositePropertySource(polarisConfigPropertySourceName); + propertySources.forEach(compositePropertySource::addPropertySource); + + Assert.assertEquals("v1", compositePropertySource.getProperty("k1")); + Assert.assertEquals("v2", compositePropertySource.getProperty("k2")); + Assert.assertEquals("v3", compositePropertySource.getProperty("k3")); + + } + } + + @AfterAll + static void afterAll() { + if (sdkContext != null) { + sdkContext.destroy(); + } + } +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/configdata/PolarisConfigDataLocationResolverTest.java b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/configdata/PolarisConfigDataLocationResolverTest.java new file mode 100644 index 00000000..f0a1d6d0 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/configdata/PolarisConfigDataLocationResolverTest.java @@ -0,0 +1,74 @@ +/* + * 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.configdata; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import org.springframework.boot.context.config.ConfigDataLocation; +import org.springframework.boot.context.config.ConfigDataLocationResolverContext; +import org.springframework.boot.context.properties.bind.Binder; +import org.springframework.boot.logging.DeferredLogs; +import org.springframework.mock.env.MockEnvironment; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; + +/** + * Test for {@link PolarisConfigDataLocationResolver}. + * + * @author wlx + */ +@RunWith(MockitoJUnitRunner.class) +public class PolarisConfigDataLocationResolverTest { + + private final PolarisConfigDataLocationResolver resolver = new PolarisConfigDataLocationResolver(new DeferredLogs()); + + @Mock + private ConfigDataLocationResolverContext context; + + private final MockEnvironment environment = new MockEnvironment(); + + private final Binder environmentBinder = Binder.get(this.environment); + + @Test + public void testIsResolvable() { + when(context.getBinder()).thenReturn(environmentBinder); + assertThat( + this.resolver.isResolvable(this.context, ConfigDataLocation.of("configserver:"))) + .isFalse(); + assertThat( + this.resolver.isResolvable(this.context, ConfigDataLocation.of("polaris:"))) + .isTrue(); + assertThat( + this.resolver.isResolvable(this.context, ConfigDataLocation.of("polaris"))) + .isTrue(); + } + + @Test + public void unEnabledPolarisConfigData() { + environment.setProperty("spring.cloud.polaris.config.enabled", "false"); + when(context.getBinder()).thenReturn(environmentBinder); + assertThat( + this.resolver.isResolvable(this.context, ConfigDataLocation.of("polaris:"))) + .isFalse(); + } +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/configdata/PolarisConfigDataMissingEnvironmentPostProcessorTest.java b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/configdata/PolarisConfigDataMissingEnvironmentPostProcessorTest.java new file mode 100644 index 00000000..eec5929c --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/configdata/PolarisConfigDataMissingEnvironmentPostProcessorTest.java @@ -0,0 +1,105 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + */ + +package com.tencent.cloud.polaris.config.configdata; + +import org.junit.Test; + +import org.springframework.boot.SpringApplication; +import org.springframework.mock.env.MockEnvironment; + +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.Mockito.mock; + +/** + * Test for {@link PolarisConfigDataMissingEnvironmentPostProcessor}. + * + * @author wlx + */ +public class PolarisConfigDataMissingEnvironmentPostProcessorTest { + + @Test + public void missConfigData() { + MockEnvironment environment = new MockEnvironment(); + SpringApplication app = mock(SpringApplication.class); + PolarisConfigDataMissingEnvironmentPostProcessor processor = new PolarisConfigDataMissingEnvironmentPostProcessor(); + assertThatThrownBy(() -> processor.postProcessEnvironment(environment, app)) + .isInstanceOf(PolarisConfigDataMissingEnvironmentPostProcessor.ImportException.class); + } + + @Test + public void bootstrapEnabledTest() { + MockEnvironment environment = new MockEnvironment(); + environment.setProperty("spring.cloud.bootstrap.enabled", "true"); + SpringApplication app = mock(SpringApplication.class); + PolarisConfigDataMissingEnvironmentPostProcessor processor = new PolarisConfigDataMissingEnvironmentPostProcessor(); + // if bootstrap enabled,don't throw ImportException + assertThatCode(() -> processor.postProcessEnvironment(environment, app)).doesNotThrowAnyException(); + } + + @Test + public void legacyProcessingTest() { + MockEnvironment environment = new MockEnvironment(); + environment.setProperty("spring.config.use-legacy-processing", "true"); + SpringApplication app = mock(SpringApplication.class); + PolarisConfigDataMissingEnvironmentPostProcessor processor = new PolarisConfigDataMissingEnvironmentPostProcessor(); + // if use-legacy-processing,don't throw ImportException + assertThatCode(() -> processor.postProcessEnvironment(environment, app)).doesNotThrowAnyException(); + } + + @Test + public void closeImportCheck() { + MockEnvironment environment = new MockEnvironment(); + environment.setProperty("spring.cloud.polaris.config.import-check.enabled", "false"); + SpringApplication app = mock(SpringApplication.class); + PolarisConfigDataMissingEnvironmentPostProcessor processor = new PolarisConfigDataMissingEnvironmentPostProcessor(); + // if import-check.enabled is false,don't throw ImportException + assertThatCode(() -> processor.postProcessEnvironment(environment, app)).doesNotThrowAnyException(); + } + + @Test + public void closePolarisConfig() { + MockEnvironment environment = new MockEnvironment(); + environment.setProperty("spring.cloud.polaris.config.enabled", "false"); + SpringApplication app = mock(SpringApplication.class); + PolarisConfigDataMissingEnvironmentPostProcessor processor = new PolarisConfigDataMissingEnvironmentPostProcessor(); + // if polaris.config is false,don't throw ImportException + assertThatCode(() -> processor.postProcessEnvironment(environment, app)).doesNotThrowAnyException(); + } + + @Test + public void normalConfigDataImport() { + MockEnvironment environment = new MockEnvironment(); + environment.setProperty("spring.config.import", "polaris"); + SpringApplication app = mock(SpringApplication.class); + PolarisConfigDataMissingEnvironmentPostProcessor processor = new PolarisConfigDataMissingEnvironmentPostProcessor(); + // config polaris config import ,don't throw ImportException + assertThatCode(() -> processor.postProcessEnvironment(environment, app)).doesNotThrowAnyException(); + } + + @Test + public void importOtherConfigDataWithoutPolaris() { + MockEnvironment environment = new MockEnvironment(); + environment.setProperty("spring.config.import", "file:application.properties"); + SpringApplication app = mock(SpringApplication.class); + PolarisConfigDataMissingEnvironmentPostProcessor processor = new PolarisConfigDataMissingEnvironmentPostProcessor(); + assertThatThrownBy(() -> processor.postProcessEnvironment(environment, app)) + .isInstanceOf(PolarisConfigDataMissingEnvironmentPostProcessor.ImportException.class); + } +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/configdata/PolarisImportExceptionFailureAnalyzerTest.java b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/configdata/PolarisImportExceptionFailureAnalyzerTest.java new file mode 100644 index 00000000..542557f1 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/configdata/PolarisImportExceptionFailureAnalyzerTest.java @@ -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.config.configdata; + +import com.tencent.polaris.api.utils.StringUtils; +import org.junit.Test; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.diagnostics.FailureAnalysis; +import org.springframework.mock.env.MockEnvironment; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.catchThrowable; +import static org.mockito.Mockito.mock; + +/** + * Test for {@link PolarisImportExceptionFailureAnalyzer}. + * + * @author wlx + */ +public class PolarisImportExceptionFailureAnalyzerTest { + + @Test + public void failureAnalyzerTest() { + SpringApplication app = mock(SpringApplication.class); + MockEnvironment environment = new MockEnvironment(); + PolarisConfigDataMissingEnvironmentPostProcessor processor = new PolarisConfigDataMissingEnvironmentPostProcessor(); + assertThatThrownBy(() -> processor.postProcessEnvironment(environment, app)) + .isInstanceOf(PolarisConfigDataMissingEnvironmentPostProcessor.ImportException.class); + Throwable throwable = catchThrowable(() -> processor.postProcessEnvironment(environment, app)); + PolarisImportExceptionFailureAnalyzer failureAnalyzer = new PolarisImportExceptionFailureAnalyzer(); + FailureAnalysis analyze = failureAnalyzer.analyze(throwable); + assertThat(StringUtils.isNotBlank(analyze.getAction())).isTrue(); + } +} 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 index c90d1340..c990773f 100644 --- 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 @@ -7,3 +7,7 @@ spring: namespace: default config: connect-remote-server: false +# auto-refresh: true + config: + import: + - optional:polaris \ No newline at end of file diff --git a/spring-cloud-tencent-examples/polaris-config-data-example/pom.xml b/spring-cloud-tencent-examples/polaris-config-data-example/pom.xml new file mode 100644 index 00000000..106ad3d6 --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-config-data-example/pom.xml @@ -0,0 +1,63 @@ + + + + spring-cloud-tencent-examples + com.tencent.cloud + ${revision} + ../pom.xml + + 4.0.0 + + polaris-config-data-example + + + + org.springframework.boot + spring-boot-starter-web + + + + + com.tencent.cloud + spring-cloud-starter-tencent-polaris-config + + + + org.springframework.boot + spring-boot-starter-actuator + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + org.apache.maven.plugins + maven-source-plugin + 3.2.0 + + + attach-sources + + jar + + + + + + + + \ No newline at end of file diff --git a/spring-cloud-tencent-examples/polaris-config-data-example/src/main/java/com/tencent/cloud/polaris/config/example/ConfigController.java b/spring-cloud-tencent-examples/polaris-config-data-example/src/main/java/com/tencent/cloud/polaris/config/example/ConfigController.java new file mode 100644 index 00000000..d06a732e --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-config-data-example/src/main/java/com/tencent/cloud/polaris/config/example/ConfigController.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.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(); + } + +} diff --git a/spring-cloud-tencent-examples/polaris-config-data-example/src/main/java/com/tencent/cloud/polaris/config/example/Person.java b/spring-cloud-tencent-examples/polaris-config-data-example/src/main/java/com/tencent/cloud/polaris/config/example/Person.java new file mode 100644 index 00000000..1d97d1fb --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-config-data-example/src/main/java/com/tencent/cloud/polaris/config/example/Person.java @@ -0,0 +1,58 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + */ + +package com.tencent.cloud.polaris.config.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; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + @Override + public String toString() { + return "User{" + "name='" + name + '\'' + ", age=" + age + '}'; + } + +} diff --git a/spring-cloud-tencent-examples/polaris-config-data-example/src/main/java/com/tencent/cloud/polaris/config/example/PersonConfigChangeListener.java b/spring-cloud-tencent-examples/polaris-config-data-example/src/main/java/com/tencent/cloud/polaris/config/example/PersonConfigChangeListener.java new file mode 100644 index 00000000..b0efd8b3 --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-config-data-example/src/main/java/com/tencent/cloud/polaris/config/example/PersonConfigChangeListener.java @@ -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.example; + +import java.util.Set; + +import com.tencent.cloud.polaris.config.annotation.PolarisConfigKVFileChangeListener; +import com.tencent.cloud.polaris.config.listener.ConfigChangeEvent; + +import org.springframework.stereotype.Component; + +/** + * Custom Config Listener Example . + * + * @author Palmer Xu 2022-06-06 + */ +@Component +public final class PersonConfigChangeListener { + + /** + * PolarisConfigKVFileChangeListener Example . + * @param event instance of {@link ConfigChangeEvent} + */ + @PolarisConfigKVFileChangeListener(interestedKeyPrefixes = "teacher") + public void onChange(ConfigChangeEvent event) { + Set changedKeys = event.changedKeys(); + + for (String changedKey : changedKeys) { + System.out.printf("%s = %s \n", changedKey, event.getChange(changedKey)); + } + } + +} diff --git a/spring-cloud-tencent-examples/polaris-config-data-example/src/main/java/com/tencent/cloud/polaris/config/example/PolarisConfigDataExampleApplication.java b/spring-cloud-tencent-examples/polaris-config-data-example/src/main/java/com/tencent/cloud/polaris/config/example/PolarisConfigDataExampleApplication.java new file mode 100644 index 00000000..8c4e3876 --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-config-data-example/src/main/java/com/tencent/cloud/polaris/config/example/PolarisConfigDataExampleApplication.java @@ -0,0 +1,16 @@ +package com.tencent.cloud.polaris.config.example; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +/** + * @author wlx + * @date 2022/7/6 9:15 下午 + */ +@SpringBootApplication +public class PolarisConfigDataExampleApplication { + + public static void main(String[] args) { + SpringApplication.run(PolarisConfigDataExampleApplication.class, args); + } +} diff --git a/spring-cloud-tencent-examples/polaris-config-data-example/src/main/resources/application.yml b/spring-cloud-tencent-examples/polaris-config-data-example/src/main/resources/application.yml new file mode 100644 index 00000000..cf786f71 --- /dev/null +++ b/spring-cloud-tencent-examples/polaris-config-data-example/src/main/resources/application.yml @@ -0,0 +1,26 @@ +server: + port: 48085 +spring: + application: + name: polaris-config-data-example + cloud: + polaris: + address: grpc://183.47.111.80:8091 + namespace: default + config: + auto-refresh: true # auto refresh when config file changed + groups: + - name: ${spring.application.name} # group name + files: [ "config/application.properties", "config/bootstrap.yml" ] + config: + import: + - optional:polaris + - optional:polaris:test.yml + - optional:polaris:configdataexample:test.yml + - optional:polaris:config/bootstrap.yml +management: + endpoints: + web: + exposure: + include: + - polaris-config diff --git a/spring-cloud-tencent-examples/polaris-config-example/pom.xml b/spring-cloud-tencent-examples/polaris-config-example/pom.xml index bb7ef026..23f641a0 100644 --- a/spring-cloud-tencent-examples/polaris-config-example/pom.xml +++ b/spring-cloud-tencent-examples/polaris-config-example/pom.xml @@ -30,6 +30,11 @@ spring-boot-starter-actuator + + org.springframework.cloud + spring-cloud-starter-bootstrap + + diff --git a/spring-cloud-tencent-examples/pom.xml b/spring-cloud-tencent-examples/pom.xml index 40f7b2ed..8419d244 100644 --- a/spring-cloud-tencent-examples/pom.xml +++ b/spring-cloud-tencent-examples/pom.xml @@ -24,6 +24,7 @@ polaris-router-example metadata-transfer-example polaris-router-grayrelease-example + polaris-config-data-example diff --git a/spring-cloud-tencent-polaris-context/pom.xml b/spring-cloud-tencent-polaris-context/pom.xml index 786f536b..944f04a0 100644 --- a/spring-cloud-tencent-polaris-context/pom.xml +++ b/spring-cloud-tencent-polaris-context/pom.xml @@ -21,11 +21,6 @@ - - org.springframework.cloud - spring-cloud-starter-bootstrap - - com.tencent.polaris diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/ModifyAddress.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/ModifyAddress.java index a7a1e551..806c44a7 100644 --- a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/ModifyAddress.java +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/ModifyAddress.java @@ -53,4 +53,8 @@ public class ModifyAddress implements PolarisConfigModifier { public int getOrder() { return ContextConstant.ModifierOrder.FIRST; } + + public void setProperties(PolarisContextProperties properties) { + this.properties = properties; + } } diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextAutoConfiguration.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextAutoConfiguration.java index 5b66506d..af919cab 100644 --- a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextAutoConfiguration.java +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextAutoConfiguration.java @@ -47,8 +47,11 @@ public class PolarisContextAutoConfiguration { @Bean(name = "polarisContext", initMethod = "init", destroyMethod = "destroy") @ConditionalOnMissingBean public SDKContext polarisContext(PolarisContextProperties properties, Environment environment, - List modifierList) throws PolarisException { - return SDKContext.initContextByConfig(properties.configuration(environment, modifierList)); + List modifierList) + throws PolarisException { + return SDKContext.initContextByConfig(properties.configuration(modifierList, () -> { + return environment.getProperty("spring.cloud.client.ip-address"); + })); } @Bean diff --git a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextProperties.java b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextProperties.java index 6ca48a5f..1a5b618d 100644 --- a/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextProperties.java +++ b/spring-cloud-tencent-polaris-context/src/main/java/com/tencent/cloud/polaris/context/config/PolarisContextProperties.java @@ -21,6 +21,7 @@ package com.tencent.cloud.polaris.context.config; import java.util.Collection; import java.util.Comparator; import java.util.List; +import java.util.function.Supplier; import java.util.stream.Collectors; import com.tencent.cloud.polaris.context.PolarisConfigModifier; @@ -31,7 +32,6 @@ import com.tencent.polaris.factory.config.ConfigurationImpl; import org.apache.commons.lang.StringUtils; import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.core.env.Environment; import org.springframework.util.CollectionUtils; /** @@ -67,7 +67,7 @@ public class PolarisContextProperties { */ private String service; - public Configuration configuration(Environment environment, List modifierList) { + public Configuration configuration(List modifierList, Supplier ipAddressSupplier) { // 1. Read user-defined polaris.yml configuration ConfigurationImpl configuration = (ConfigurationImpl) ConfigAPIFactory .defaultConfig(ConfigProvider.DEFAULT_CONFIG); @@ -75,7 +75,7 @@ public class PolarisContextProperties { // 2. Override user-defined polaris.yml configuration with SCT configuration String defaultHost = this.localIpAddress; if (StringUtils.isBlank(localIpAddress)) { - defaultHost = environment.getProperty("spring.cloud.client.ip-address"); + defaultHost = ipAddressSupplier.get(); } configuration.getGlobal().getAPI().setBindIP(defaultHost); @@ -101,11 +101,11 @@ public class PolarisContextProperties { this.address = address; } - String getLocalIpAddress() { + public String getLocalIpAddress() { return localIpAddress; } - void setLocalIpAddress(String localIpAddress) { + public void setLocalIpAddress(String localIpAddress) { this.localIpAddress = localIpAddress; } diff --git a/spring-cloud-tencent-polaris-loadbalancer/src/test/java/com/tencent/cloud/polaris/loadbalancer/config/PolarisRouterAutoConfigurationTest.java b/spring-cloud-tencent-polaris-loadbalancer/src/test/java/com/tencent/cloud/polaris/loadbalancer/config/PolarisRouterAutoConfigurationTest.java index 606d2cd5..a78bdcf8 100644 --- a/spring-cloud-tencent-polaris-loadbalancer/src/test/java/com/tencent/cloud/polaris/loadbalancer/config/PolarisRouterAutoConfigurationTest.java +++ b/spring-cloud-tencent-polaris-loadbalancer/src/test/java/com/tencent/cloud/polaris/loadbalancer/config/PolarisRouterAutoConfigurationTest.java @@ -30,7 +30,7 @@ import org.springframework.context.annotation.Configuration; import static org.assertj.core.api.Assertions.assertThat; /** - * Test for {@link PolarisLoadBalancerAutoConfiguration} + * Test for {@link PolarisLoadBalancerAutoConfiguration}. * * @author Haotian Zhang */