From 6a93fc1a78e2a2ccf443d9a84c702aeb6b9aa75f Mon Sep 17 00:00:00 2001 From: Haotian Zhang <928016560@qq.com> Date: Mon, 11 Sep 2023 14:54:37 +0800 Subject: [PATCH] feature: support Polaris configuration center extension plugin interface and support dynamic modification of log levels. (#1103) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: 杨镌颖 <531948963@qq.com> Co-authored-by: melodyl --- CHANGELOG.md | 1 + .../PolarisConfigAutoConfiguration.java | 7 + .../PolarisConfigCustomExtensionLayer.java | 38 ++++ .../adapter/PolarisConfigFileLocator.java | 196 ++++++++++++++++-- .../PolarisConfigPropertyAutoRefresher.java | 103 +++++---- .../config/adapter/PolarisPropertySource.java | 6 +- .../adapter/PolarisServiceLoaderUtil.java | 50 +++++ .../PolarisConfigAnnotationProcessor.java | 14 +- .../PolarisConfigKVFileChangeListener.java | 2 + .../config/PolarisConfigProperties.java | 7 +- .../PolarisConfigListenerContext.java | 15 +- ...arisConfigRefreshOptimizationListener.java | 37 ++-- .../listener/SyncConfigChangeListener.java | 24 +++ .../cloud/polaris/config/logger/Level.java | 45 ++++ ...olarisConfigLoggerApplicationListener.java | 52 +++++ .../logger/PolarisConfigLoggerContext.java | 106 ++++++++++ .../cloud/polaris/config/logger/StdLog.java | 96 +++++++++ .../listener/ConfigChangeListenerTest.java | 4 +- spring-cloud-tencent-dependencies/pom.xml | 2 +- .../example/PersonConfigChangeListener.java | 20 +- .../config/PolarisContextProperties.java | 6 + 21 files changed, 752 insertions(+), 79 deletions(-) create mode 100644 spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigCustomExtensionLayer.java create mode 100644 spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisServiceLoaderUtil.java create mode 100644 spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/SyncConfigChangeListener.java create mode 100644 spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/logger/Level.java create mode 100644 spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/logger/PolarisConfigLoggerApplicationListener.java create mode 100644 spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/logger/PolarisConfigLoggerContext.java create mode 100644 spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/logger/StdLog.java diff --git a/CHANGELOG.md b/CHANGELOG.md index c216697b8..7c2ab4c03 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,3 +27,4 @@ - [refactor:optimize discovery properties initialization.](https://github.com/Tencent/spring-cloud-tencent/pull/1077) - [fix:upgrade spring version.](https://github.com/Tencent/spring-cloud-tencent/pull/1086) - [fix:Update README-zh.md](https://github.com/Tencent/spring-cloud-tencent/pull/1090). +- [feature: support Polaris configuration center extension plugin interface and support dynamic modification of log levels.](https://github.com/Tencent/spring-cloud-tencent/pull/1103). diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/PolarisConfigAutoConfiguration.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/PolarisConfigAutoConfiguration.java index be91d2287..0d5855b86 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/PolarisConfigAutoConfiguration.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/PolarisConfigAutoConfiguration.java @@ -29,6 +29,7 @@ import com.tencent.cloud.polaris.config.condition.ConditionalOnReflectRefreshTyp import com.tencent.cloud.polaris.config.config.PolarisConfigProperties; import com.tencent.cloud.polaris.config.listener.PolarisConfigChangeEventListener; import com.tencent.cloud.polaris.config.listener.PolarisConfigRefreshOptimizationListener; +import com.tencent.cloud.polaris.config.logger.PolarisConfigLoggerApplicationListener; import com.tencent.cloud.polaris.config.spring.annotation.SpringValueProcessor; import com.tencent.cloud.polaris.config.spring.property.PlaceholderHelper; import com.tencent.cloud.polaris.config.spring.property.SpringValueRegistry; @@ -62,6 +63,12 @@ public class PolarisConfigAutoConfiguration { return new PolarisConfigChangeEventListener(); } + @Bean + public PolarisConfigLoggerApplicationListener polarisConfigLoggerApplicationListener() { + return new PolarisConfigLoggerApplicationListener(); + } + + @Bean @Primary @ConditionalOnReflectRefreshType diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigCustomExtensionLayer.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigCustomExtensionLayer.java new file mode 100644 index 000000000..2549f0773 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigCustomExtensionLayer.java @@ -0,0 +1,38 @@ +/* + * 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 com.tencent.polaris.configuration.api.core.ConfigFileService; + +import org.springframework.core.env.CompositePropertySource; +import org.springframework.core.env.Environment; + + +/** + * @Date Jul 23, 2023 2:57:49 PM + * @author juanyinyang + */ +public interface PolarisConfigCustomExtensionLayer { + void initRegisterConfig(PolarisConfigPropertyAutoRefresher polarisConfigPropertyAutoRefresher); + + void initConfigFiles(Environment environment, CompositePropertySource compositePropertySource, PolarisPropertySourceManager polarisPropertySourceManager, ConfigFileService configFileService); + + void executeAfterLocateConfigReturning(CompositePropertySource compositePropertySource); + boolean executeRegisterPublishChangeListener(PolarisPropertySource polarisPropertySource); +} 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 93ea96634..21f4f5a78 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,12 +17,24 @@ package com.tencent.cloud.polaris.config.adapter; +import java.util.ArrayList; +import java.util.Arrays; +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.apache.commons.lang.ArrayUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.cloud.bootstrap.config.PropertySourceLocator; import org.springframework.core.annotation.Order; @@ -30,6 +42,7 @@ 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. @@ -41,38 +54,185 @@ import org.springframework.util.CollectionUtils; @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 PolarisConfigFilePuller polarisConfigFilePuller; + private final PolarisContextProperties polarisContextProperties; + + private final ConfigFileService configFileService; + + private final PolarisPropertySourceManager polarisPropertySourceManager; + + private final Environment environment; + // this class provides customized logic for some customers to configure special business group files + private final PolarisConfigCustomExtensionLayer polarisConfigCustomExtensionLayer = PolarisServiceLoaderUtil.getPolarisConfigCustomExtensionLayer(); - public PolarisConfigFileLocator(PolarisConfigProperties polarisConfigProperties, - PolarisContextProperties polarisContextProperties, ConfigFileService configFileService, - PolarisPropertySourceManager polarisPropertySourceManager, Environment environment) { + public PolarisConfigFileLocator(PolarisConfigProperties polarisConfigProperties, PolarisContextProperties polarisContextProperties, ConfigFileService configFileService, PolarisPropertySourceManager polarisPropertySourceManager, Environment environment) { this.polarisConfigProperties = polarisConfigProperties; - this.polarisConfigFilePuller = PolarisConfigFilePuller.get(polarisContextProperties, configFileService, - polarisPropertySourceManager); + this.polarisContextProperties = polarisContextProperties; + this.configFileService = configFileService; + this.polarisPropertySourceManager = polarisPropertySourceManager; + this.environment = environment; } @Override public PropertySource locate(Environment environment) { - CompositePropertySource compositePropertySource = new CompositePropertySource( - POLARIS_CONFIG_PROPERTY_SOURCE_NAME); + CompositePropertySource compositePropertySource = new CompositePropertySource(POLARIS_CONFIG_PROPERTY_SOURCE_NAME); + try { + // load custom config extension files + initCustomPolarisConfigExtensionFiles(compositePropertySource); + // load spring boot default config files + initInternalConfigFiles(compositePropertySource); + // load custom config files + List configFileGroups = polarisConfigProperties.getGroups(); + if (CollectionUtils.isEmpty(configFileGroups)) { + return compositePropertySource; + } + initCustomPolarisConfigFiles(compositePropertySource, configFileGroups); + return compositePropertySource; + } + finally { + afterLocatePolarisConfigExtension(compositePropertySource); + } + } + + private void initCustomPolarisConfigExtensionFiles(CompositePropertySource compositePropertySource) { + if (polarisConfigCustomExtensionLayer == null) { + LOGGER.debug("[SCT Config] PolarisAdaptorTsfConfigExtensionLayer is not init, ignore the following execution steps"); + return; + } + polarisConfigCustomExtensionLayer.initConfigFiles(environment, compositePropertySource, polarisPropertySourceManager, configFileService); + } + + private void afterLocatePolarisConfigExtension(CompositePropertySource compositePropertySource) { + if (polarisConfigCustomExtensionLayer == null) { + LOGGER.debug("[SCT Config] PolarisAdaptorTsfConfigExtensionLayer is not init, ignore the following execution steps"); + return; + } + polarisConfigCustomExtensionLayer.executeAfterLocateConfigReturning(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); - // load spring boot default config files + 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(); String[] defaultProfiles = environment.getDefaultProfiles(); - String serviceName = environment.getProperty("spring.application.name"); - polarisConfigFilePuller.initInternalConfigFiles( - compositePropertySource, activeProfiles, defaultProfiles, serviceName); + List profileList = new ArrayList<>(); + if (ArrayUtils.isNotEmpty(activeProfiles)) { + profileList.addAll(Arrays.asList(activeProfiles)); + } + else if (ArrayUtils.isNotEmpty(defaultProfiles)) { + profileList.addAll(Arrays.asList(defaultProfiles)); + } + // build application config files + buildInternalApplicationConfigFiles(internalConfigFiles, namespace, serviceName, profileList); + // build bootstrap config files + buildInternalBootstrapConfigFiles(internalConfigFiles, namespace, serviceName, profileList); - // load custom config files - List configFileGroups = polarisConfigProperties.getGroups(); - if (CollectionUtils.isEmpty(configFileGroups)) { - return compositePropertySource; + return internalConfigFiles; + } + + private void buildInternalApplicationConfigFiles(List internalConfigFiles, String namespace, String serviceName, List profileList) { + for (String profile : profileList) { + if (!StringUtils.hasText(profile)) { + continue; + } + internalConfigFiles.add(new DefaultConfigFileMetadata(namespace, serviceName, "application-" + profile + ".properties")); + internalConfigFiles.add(new DefaultConfigFileMetadata(namespace, serviceName, "application-" + profile + ".yml")); + internalConfigFiles.add(new DefaultConfigFileMetadata(namespace, serviceName, "application-" + profile + ".yaml")); } - polarisConfigFilePuller.initCustomPolarisConfigFiles(compositePropertySource, configFileGroups); - return compositePropertySource; + // build default config properties files. + internalConfigFiles.add(new DefaultConfigFileMetadata(namespace, serviceName, "application.properties")); + internalConfigFiles.add(new DefaultConfigFileMetadata(namespace, serviceName, "application.yml")); + internalConfigFiles.add(new DefaultConfigFileMetadata(namespace, serviceName, "application.yaml")); + } + + private void buildInternalBootstrapConfigFiles(List internalConfigFiles, String namespace, String serviceName, List profileList) { + for (String profile : profileList) { + if (!StringUtils.hasText(profile)) { + continue; + } + internalConfigFiles.add(new DefaultConfigFileMetadata(namespace, serviceName, "bootstrap-" + profile + ".properties")); + internalConfigFiles.add(new DefaultConfigFileMetadata(namespace, serviceName, "bootstrap-" + profile + ".yml")); + internalConfigFiles.add(new DefaultConfigFileMetadata(namespace, serviceName, "bootstrap-" + profile + ".yaml")); + } + // build default config properties files. + internalConfigFiles.add(new DefaultConfigFileMetadata(namespace, serviceName, "bootstrap.properties")); + internalConfigFiles.add(new DefaultConfigFileMetadata(namespace, serviceName, "bootstrap.yml")); + internalConfigFiles.add(new DefaultConfigFileMetadata(namespace, serviceName, "bootstrap.yaml")); + } + + 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/PolarisConfigPropertyAutoRefresher.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigPropertyAutoRefresher.java index 2dea15ba4..bdd9e21e2 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigPropertyAutoRefresher.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisConfigPropertyAutoRefresher.java @@ -23,6 +23,7 @@ import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; import com.tencent.cloud.polaris.config.config.PolarisConfigProperties; +import com.tencent.cloud.polaris.config.logger.PolarisConfigLoggerContext; import com.tencent.polaris.configuration.api.core.ConfigKVFileChangeListener; import com.tencent.polaris.configuration.api.core.ConfigPropertyChangeInfo; import org.slf4j.Logger; @@ -39,8 +40,7 @@ import org.springframework.util.CollectionUtils; * * @author lepdou */ -public abstract class PolarisConfigPropertyAutoRefresher - implements ApplicationListener, PolarisConfigPropertyRefresher { +public abstract class PolarisConfigPropertyAutoRefresher implements ApplicationListener, PolarisConfigPropertyRefresher { private static final Logger LOGGER = LoggerFactory.getLogger(PolarisConfigPropertyAutoRefresher.class); @@ -50,9 +50,10 @@ public abstract class PolarisConfigPropertyAutoRefresher private final AtomicBoolean registered = new AtomicBoolean(false); - public PolarisConfigPropertyAutoRefresher( - PolarisConfigProperties polarisConfigProperties, - PolarisPropertySourceManager polarisPropertySourceManager) { + // this class provides customized logic for some customers to configure special business group files + private final PolarisConfigCustomExtensionLayer polarisConfigCustomExtensionLayer = PolarisServiceLoaderUtil.getPolarisConfigCustomExtensionLayer(); + + public PolarisConfigPropertyAutoRefresher(PolarisConfigProperties polarisConfigProperties, PolarisPropertySourceManager polarisPropertySourceManager) { this.polarisConfigProperties = polarisConfigProperties; this.polarisPropertySourceManager = polarisPropertySourceManager; } @@ -76,41 +77,71 @@ public abstract class PolarisConfigPropertyAutoRefresher return; } + // custom register polaris config + customInitRegisterPolarisConfig(this); + // register polaris config publish event for (PolarisPropertySource polarisPropertySource : polarisPropertySources) { - polarisPropertySource.getConfigKVFile() - .addChangeListener((ConfigKVFileChangeListener) configKVFileChangeEvent -> { - - LOGGER.info( - "[SCT Config] received polaris config change event and will refresh spring context." - + " namespace = {}, group = {}, fileName = {}", - polarisPropertySource.getNamespace(), - polarisPropertySource.getGroup(), - polarisPropertySource.getFileName()); - - Map source = polarisPropertySource.getSource(); - - for (String changedKey : configKVFileChangeEvent.changedKeys()) { - ConfigPropertyChangeInfo configPropertyChangeInfo = configKVFileChangeEvent - .getChangeInfo(changedKey); - - LOGGER.info("[SCT Config] changed property = {}", configPropertyChangeInfo); - - switch (configPropertyChangeInfo.getChangeType()) { - case MODIFIED: - case ADDED: - source.put(changedKey, configPropertyChangeInfo.getNewValue()); - break; - case DELETED: - source.remove(changedKey); - break; + registerPolarisConfigPublishChangeListener(polarisPropertySource); + customRegisterPolarisConfigPublishChangeListener(polarisPropertySource); + } + } + + private void customInitRegisterPolarisConfig(PolarisConfigPropertyAutoRefresher polarisConfigPropertyAutoRefresher) { + if (polarisConfigCustomExtensionLayer == null) { + LOGGER.debug("[SCT Config] PolarisAdaptorTsfConfigExtensionLayer is not init, ignore the following execution steps"); + return; + } + polarisConfigCustomExtensionLayer.initRegisterConfig(polarisConfigPropertyAutoRefresher); + } + + public void registerPolarisConfigPublishChangeListener(PolarisPropertySource polarisPropertySource) { + polarisPropertySource.getConfigKVFile() + .addChangeListener((ConfigKVFileChangeListener) configKVFileChangeEvent -> { + + LOGGER.info("[SCT Config] received polaris config change event and will refresh spring context." + " namespace = {}, group = {}, fileName = {}", polarisPropertySource.getNamespace(), polarisPropertySource.getGroup(), polarisPropertySource.getFileName()); + + Map source = polarisPropertySource.getSource(); + + for (String changedKey : configKVFileChangeEvent.changedKeys()) { + ConfigPropertyChangeInfo configPropertyChangeInfo = configKVFileChangeEvent.getChangeInfo(changedKey); + + LOGGER.info("[SCT Config] changed property = {}", configPropertyChangeInfo); + + // new ability to dynamically change log levels + try { + if (changedKey.startsWith("logging.level") && changedKey.length() >= 14) { + String loggerName = changedKey.substring(14); + String newValue = (String) configPropertyChangeInfo.getNewValue(); + LOGGER.info("[SCT Config] set logging.level loggerName:{}, newValue:{}", loggerName, newValue); + PolarisConfigLoggerContext.setLevel(loggerName, newValue); } - // update the attribute with @Value annotation - refreshSpringValue(changedKey); } - // update @ConfigurationProperties beans - refreshConfigurationProperties(configKVFileChangeEvent.changedKeys()); - }); + catch (Exception e) { + LOGGER.error("[SCT Config] set logging.level exception,", e); + } + switch (configPropertyChangeInfo.getChangeType()) { + case MODIFIED: + case ADDED: + source.put(changedKey, configPropertyChangeInfo.getNewValue()); + break; + case DELETED: + source.remove(changedKey); + break; + } + // update the attribute with @Value annotation + refreshSpringValue(changedKey); + } + // update @ConfigurationProperties beans + refreshConfigurationProperties(configKVFileChangeEvent.changedKeys()); + }); + } + + private void customRegisterPolarisConfigPublishChangeListener(PolarisPropertySource polarisPropertySource) { + if (polarisConfigCustomExtensionLayer == null) { + LOGGER.debug("[SCT Config] PolarisAdaptorTsfConfigExtensionLayer is not init, ignore the following execution steps"); + return; } + polarisConfigCustomExtensionLayer.executeRegisterPublishChangeListener(polarisPropertySource); } } diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertySource.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertySource.java index 5a05ce132..c1dcefa51 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertySource.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertySource.java @@ -39,8 +39,7 @@ public class PolarisPropertySource extends MapPropertySource { private final ConfigKVFile configKVFile; - public PolarisPropertySource(String namespace, String group, String fileName, ConfigKVFile configKVFile, - Map source) { + public PolarisPropertySource(String namespace, String group, String fileName, ConfigKVFile configKVFile, Map source) { super(namespace + "-" + group + "-" + fileName, source); this.namespace = namespace; @@ -71,7 +70,6 @@ public class PolarisPropertySource extends MapPropertySource { @Override public String toString() { - return "PolarisPropertySource{" + "namespace='" + namespace + '\'' + ", group='" + group + '\'' + ", fileName='" - + fileName + '\'' + '}'; + return "PolarisPropertySource{" + "namespace='" + namespace + '\'' + ", group='" + group + '\'' + ", fileName='" + fileName + '\'' + '}'; } } diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisServiceLoaderUtil.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisServiceLoaderUtil.java new file mode 100644 index 000000000..343a5b319 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisServiceLoaderUtil.java @@ -0,0 +1,50 @@ +/* + * 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.Iterator; +import java.util.ServiceLoader; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author juanyinyang + * @Date 2023年8月10日 下午4:11:05 + */ +public final class PolarisServiceLoaderUtil { + + private static final Logger LOGGER = LoggerFactory.getLogger(PolarisServiceLoaderUtil.class); + private PolarisServiceLoaderUtil() { + } + // this class provides customized logic for some customers to configure special business group files + private static PolarisConfigCustomExtensionLayer polarisConfigCustomExtensionLayer; + static { + ServiceLoader polarisConfigCustomExtensionLayerLoader = ServiceLoader.load(PolarisConfigCustomExtensionLayer.class); + Iterator polarisConfigCustomExtensionLayerIterator = polarisConfigCustomExtensionLayerLoader.iterator(); + // Generally, there is only one implementation class. If there are multiple, the last one is loaded + while (polarisConfigCustomExtensionLayerIterator.hasNext()) { + polarisConfigCustomExtensionLayer = polarisConfigCustomExtensionLayerIterator.next(); + LOGGER.info("[SCT Config] PolarisConfigFileLocator init polarisConfigCustomExtensionLayer:{}", polarisConfigCustomExtensionLayer); + } + } + + public static PolarisConfigCustomExtensionLayer getPolarisConfigCustomExtensionLayer() { + return polarisConfigCustomExtensionLayer; + } +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/annotation/PolarisConfigAnnotationProcessor.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/annotation/PolarisConfigAnnotationProcessor.java index b137c4909..ee0a3d277 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/annotation/PolarisConfigAnnotationProcessor.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/annotation/PolarisConfigAnnotationProcessor.java @@ -27,6 +27,7 @@ import com.google.common.base.Preconditions; import com.google.common.collect.Sets; import com.tencent.cloud.polaris.config.listener.ConfigChangeEvent; import com.tencent.cloud.polaris.config.listener.ConfigChangeListener; +import com.tencent.cloud.polaris.config.listener.SyncConfigChangeListener; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; @@ -90,8 +91,19 @@ public class PolarisConfigAnnotationProcessor implements BeanPostProcessor, Prio ReflectionUtils.makeAccessible(method); String[] annotatedInterestedKeys = annotation.interestedKeys(); String[] annotatedInterestedKeyPrefixes = annotation.interestedKeyPrefixes(); + boolean isAsync = annotation.async(); - ConfigChangeListener configChangeListener = changeEvent -> ReflectionUtils.invokeMethod(method, bean, changeEvent); + ConfigChangeListener configChangeListener = new SyncConfigChangeListener() { + @Override + public void onChange(ConfigChangeEvent changeEvent) { + ReflectionUtils.invokeMethod(method, bean, changeEvent); + } + + @Override + public boolean isAsync() { + return isAsync; + } + }; Set interestedKeys = annotatedInterestedKeys.length > 0 ? Sets.newHashSet(annotatedInterestedKeys) : null; diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/annotation/PolarisConfigKVFileChangeListener.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/annotation/PolarisConfigKVFileChangeListener.java index eba43e819..8517e774a 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/annotation/PolarisConfigKVFileChangeListener.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/annotation/PolarisConfigKVFileChangeListener.java @@ -54,4 +54,6 @@ public @interface PolarisConfigKVFileChangeListener { * @return interested key-prefixed in the listener */ String[] interestedKeyPrefixes() default {}; + + boolean async() default true; } 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 8786abb2a..6a014aa04 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 @@ -21,8 +21,10 @@ import java.util.List; import com.tencent.cloud.polaris.config.enums.RefreshType; +import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.context.properties.ConfigurationProperties; + /** * polaris config module bootstrap configs. * @@ -30,26 +32,29 @@ import org.springframework.boot.context.properties.ConfigurationProperties; */ @ConfigurationProperties("spring.cloud.polaris.config") public class PolarisConfigProperties { - /** * Whether to open the configuration center. */ + @Value("${spring.cloud.polaris.config.enabled:#{'true'}}") private boolean enabled = true; /** * Configuration center service address list. */ + @Value("${spring.cloud.polaris.config.address:}") private String address; /** * Polaris config grpc port. */ + @Value("${spring.cloud.polaris.config.port:#{'8093'}}") private int port = 8093; /** * Whether to automatically update to the spring context when the configuration file. * is updated */ + @Value("${spring.cloud.polaris.config.autoRefresh:#{'true'}}") private boolean autoRefresh = true; private boolean shutdownIfConnectToConfigServerFailed = true; diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/PolarisConfigListenerContext.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/PolarisConfigListenerContext.java index 07edc90e4..00f1ecb85 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/PolarisConfigListenerContext.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/PolarisConfigListenerContext.java @@ -70,11 +70,11 @@ public final class PolarisConfigListenerContext { /** * All custom interested keys defined in application . */ - private static final Map> interestedKeys = Maps.newHashMap(); + private static final Map> interestedKeys = Maps.newConcurrentMap(); /** * All custom interested key prefixes defined in application . */ - private static final Map> interestedKeyPrefixes = Maps.newHashMap(); + private static final Map> interestedKeyPrefixes = Maps.newConcurrentMap(); /** * Cache all latest configuration information for users in the application environment . */ @@ -87,7 +87,7 @@ public final class PolarisConfigListenerContext { * Get or Created new execute server . * @return execute service instance of {@link ExecutorService} */ - private static ExecutorService executor() { + public static ExecutorService executor() { if (EAR.get() == null) { synchronized (PolarisConfigListenerContext.class) { int coreThreadSize = Runtime.getRuntime().availableProcessors(); @@ -185,6 +185,15 @@ public final class PolarisConfigListenerContext { Map modifiedChanges = new HashMap<>(interestedChangedKeys.size()); interestedChangedKeys.parallelStream().forEach(key -> modifiedChanges.put(key, changes.get(key))); ConfigChangeEvent event = new ConfigChangeEvent(modifiedChanges, interestedChangedKeys); + + if (listener instanceof SyncConfigChangeListener) { + SyncConfigChangeListener l = (SyncConfigChangeListener) listener; + if (!l.isAsync()) { + listener.onChange(event); + continue; + } + } + PolarisConfigListenerContext.executor().execute(() -> listener.onChange(event)); } } diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/PolarisConfigRefreshOptimizationListener.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/PolarisConfigRefreshOptimizationListener.java index 0c93fd8ff..54f0c6246 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/PolarisConfigRefreshOptimizationListener.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/PolarisConfigRefreshOptimizationListener.java @@ -28,6 +28,7 @@ import com.tencent.cloud.polaris.config.enums.RefreshType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.ConstructorArgumentValues; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; @@ -65,17 +66,24 @@ public class PolarisConfigRefreshOptimizationListener implements ApplicationList private static final String REFRESH_CONTEXT_REFRESHER_BEAN_NAME = "polarisRefreshContextPropertySourceAutoRefresher"; + @Override public void onApplicationEvent(@NonNull ContextRefreshedEvent event) { ConfigurableApplicationContext applicationContext = (ConfigurableApplicationContext) event.getApplicationContext(); - PolarisConfigRefreshScopeAnnotationDetector detector = applicationContext - .getBean(PolarisConfigRefreshScopeAnnotationDetector.class); + PolarisConfigRefreshScopeAnnotationDetector detector = applicationContext.getBean(PolarisConfigRefreshScopeAnnotationDetector.class); boolean isRefreshScopeAnnotationUsed = detector.isRefreshScopeAnnotationUsed(); String annotatedRefreshScopeBeanName = detector.getAnnotatedRefreshScopeBeanName(); + // using System.setProperty to set spring.cloud.polaris.config.refresh-type + String value = System.getProperty("spring.cloud.polaris.config.refresh-type"); + boolean isSystemSetRefreshType = RefreshType.REFRESH_CONTEXT.toString().equalsIgnoreCase(value); // a bean is using @RefreshScope, but the config refresh type is still [reflect], switch automatically - if (isRefreshScopeAnnotationUsed) { - LOGGER.warn("Detected that the bean [{}] is using @RefreshScope annotation, but the config refresh type is still [reflect]. " - + "[SCT] will automatically switch to [refresh_context].", annotatedRefreshScopeBeanName); + if (isRefreshScopeAnnotationUsed || isSystemSetRefreshType) { + if (isRefreshScopeAnnotationUsed) { + LOGGER.warn("Detected that the bean [{}] is using @RefreshScope annotation, but the config refresh type is still [reflect]. " + "[SCT] will automatically switch to [refresh_context].", annotatedRefreshScopeBeanName); + } + if (isSystemSetRefreshType) { + LOGGER.warn("Detected that using System.setProperty to set spring.cloud.polaris.config.refresh-type = refresh_context, but the config refresh type is still [reflect]. " + "[SCT] will automatically switch to [refresh_context]."); + } switchConfigRefreshTypeProperty(applicationContext); modifyPolarisConfigPropertiesBean(applicationContext); // remove related bean of type [reflect] @@ -89,8 +97,7 @@ public class PolarisConfigRefreshOptimizationListener implements ApplicationList private void switchConfigRefreshTypeProperty(ConfigurableApplicationContext applicationContext) { MutablePropertySources propertySources = applicationContext.getEnvironment().getPropertySources(); - propertySources.addFirst(new MapPropertySource(CONFIG_REFRESH_TYPE_PROPERTY, - Collections.singletonMap(POLARIS_CONFIG_REFRESH_TYPE, RefreshType.REFRESH_CONTEXT))); + propertySources.addFirst(new MapPropertySource(CONFIG_REFRESH_TYPE_PROPERTY, Collections.singletonMap(POLARIS_CONFIG_REFRESH_TYPE, RefreshType.REFRESH_CONTEXT))); } private void modifyPolarisConfigPropertiesBean(ConfigurableApplicationContext applicationContext) { @@ -99,9 +106,15 @@ public class PolarisConfigRefreshOptimizationListener implements ApplicationList } private void removeRelatedBeansOfReflect(ConfigurableApplicationContext applicationContext) { - DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext.getBeanFactory(); - beanFactory.removeBeanDefinition(REFLECT_REFRESHER_BEAN_NAME); - beanFactory.removeBeanDefinition(REFLECT_REBINDER_BEAN_NAME); + try { + DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext.getBeanFactory(); + beanFactory.removeBeanDefinition(REFLECT_REFRESHER_BEAN_NAME); + beanFactory.removeBeanDefinition(REFLECT_REBINDER_BEAN_NAME); + } + catch (BeansException e) { + // If there is a removeBean exception in this code, do not affect the main process startup. Some user usage may cause the polarisReflectPropertySourceAutoRefresher to not load, and the removeBeanDefinition will report an error + LOGGER.debug("removeRelatedBeansOfReflect occur error:", e); + } } private void registerRefresherBeanOfRefreshContext(ConfigurableApplicationContext applicationContext) { @@ -118,9 +131,9 @@ public class PolarisConfigRefreshOptimizationListener implements ApplicationList beanFactory.registerBeanDefinition(REFRESH_CONTEXT_REFRESHER_BEAN_NAME, beanDefinition); } + private void addRefresherBeanAsListener(ConfigurableApplicationContext applicationContext) { - PolarisRefreshEntireContextRefresher refresher = (PolarisRefreshEntireContextRefresher) applicationContext - .getBean(REFRESH_CONTEXT_REFRESHER_BEAN_NAME); + PolarisRefreshEntireContextRefresher refresher = (PolarisRefreshEntireContextRefresher) applicationContext.getBean(REFRESH_CONTEXT_REFRESHER_BEAN_NAME); applicationContext.addApplicationListener(refresher); } } diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/SyncConfigChangeListener.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/SyncConfigChangeListener.java new file mode 100644 index 000000000..c98a3879f --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/listener/SyncConfigChangeListener.java @@ -0,0 +1,24 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + */ +package com.tencent.cloud.polaris.config.listener; + +public interface SyncConfigChangeListener extends ConfigChangeListener { + default boolean isAsync() { + return true; + } +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/logger/Level.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/logger/Level.java new file mode 100644 index 000000000..570a187af --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/logger/Level.java @@ -0,0 +1,45 @@ +/* + * 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.logger; + +/** + * @author juanyinyang + */ +public enum Level { + + /** log level. */ + TRACE("TRACE"), DEBUG("DEBUG"), INFO("INFO"), WARN("WARN"), ERROR("ERROR"), FATAL("FATAL"), OFF("OFF"); + + private String level; + + Level(String level) { + this.level = level; + } + public String getLevel() { + return level; + } + + public static Level levelOf(String level) { + for (Level l : Level.values()) { + if (l.level.equalsIgnoreCase(level)) { + return l; + } + } + return null; + } +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/logger/PolarisConfigLoggerApplicationListener.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/logger/PolarisConfigLoggerApplicationListener.java new file mode 100644 index 000000000..a3cb9b571 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/logger/PolarisConfigLoggerApplicationListener.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.logger; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.boot.context.event.ApplicationStartedEvent; +import org.springframework.boot.logging.LoggingSystem; +import org.springframework.context.ApplicationEvent; +import org.springframework.context.ApplicationListener; + +/** + * @author juanyinyang + */ +public class PolarisConfigLoggerApplicationListener implements ApplicationListener { + private static final Logger LOGGER = LoggerFactory.getLogger(PolarisConfigLoggerApplicationListener.class); + /** + * @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent) + */ + @Override + public void onApplicationEvent(ApplicationEvent event) { + try { + // Initialize application loggingSystem. + if (event instanceof ApplicationStartedEvent) { + ApplicationStartedEvent startedEvent = (ApplicationStartedEvent) event; + ClassLoader classLoader = startedEvent.getSpringApplication().getClassLoader(); + LoggingSystem loggingSystem = LoggingSystem.get(classLoader); + LOGGER.info("PolarisConfigLoggerApplicationListener onApplicationEvent init loggingSystem:{}", loggingSystem); + PolarisConfigLoggerContext.setLogSystem(loggingSystem); + } + } + catch (Exception e) { + LOGGER.error("PolarisConfigLoggerApplicationListener onApplicationEvent exception:", e); + } + } +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/logger/PolarisConfigLoggerContext.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/logger/PolarisConfigLoggerContext.java new file mode 100644 index 000000000..29865835a --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/logger/PolarisConfigLoggerContext.java @@ -0,0 +1,106 @@ +/* + * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. + * + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + */ + +package com.tencent.cloud.polaris.config.logger; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.boot.logging.LogLevel; +import org.springframework.boot.logging.LoggingSystem; +import org.springframework.util.Assert; + +import static org.springframework.boot.logging.LoggingSystem.ROOT_LOGGER_NAME; + +/** + * @author juanyinyang + */ +public final class PolarisConfigLoggerContext { + + private static LoggingSystem loggingSystem; + + private PolarisConfigLoggerContext() { + + } + protected static void setLogSystem(LoggingSystem logSystem) { + Assert.notNull(logSystem, "Logging System should not be null"); + PolarisConfigLoggerContext.loggingSystem = logSystem; + } + + public static void setLevel(String loggerName, String level) { + if (loggingSystem == null) { + printLog("[SCT Config] PolarisConfigLoggerContext logger: [" + loggerName + "] change to target level fail. caused by internal exception:" + level, Level.WARN); + return; + } + Level loggerLevel = Level.levelOf(level); + if (loggerLevel == null) { + printLog("[SCT Config] PolarisConfigLoggerContext logger: [" + loggerName + "] change to target level fail. caused by level is not support, level:" + level, Level.WARN); + return; + } + LogLevel logLevel = null; + switch (loggerLevel) { + case TRACE: + logLevel = LogLevel.TRACE; + break; + case DEBUG: + logLevel = LogLevel.DEBUG; + break; + case OFF: + logLevel = LogLevel.OFF; + break; + case INFO: + logLevel = LogLevel.INFO; + break; + case WARN: + logLevel = LogLevel.WARN; + break; + case ERROR: + logLevel = LogLevel.ERROR; + break; + case FATAL: + logLevel = LogLevel.FATAL; + break; + default: + printLog("[SCT Config] PolarisConfigLoggerContext logger: [" + loggerName + "] setLevel fail. caused by level is not support, level: " + level, Level.WARN); + } + loggingSystem.setLogLevel(loggerName, logLevel); + printLog("[SCT Config] PolarisConfigLoggerContext logger: [" + loggerName + "] changed to level:" + level, Level.INFO); + } + /** + * print log. + */ + private static void printLog(String message, Level level) { + Logger logger = LoggerFactory.getLogger(ROOT_LOGGER_NAME); + if (level.ordinal() <= Level.INFO.ordinal()) { + if (logger != null) { + logger.info(message); + } + else { + StdLog.info(message); + } + } + else { + if (logger != null) { + logger.warn(message); + } + else { + StdLog.warn(message); + } + } + } +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/logger/StdLog.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/logger/StdLog.java new file mode 100644 index 000000000..cef88f6f1 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/logger/StdLog.java @@ -0,0 +1,96 @@ +/* + * 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.logger; + +import java.io.PrintStream; +import java.util.Calendar; + +/** + * internal output logger. + * @author juanyinyang + */ +public final class StdLog { + + private static final String CLASS_INFO = StdLog.class.getName(); + + + protected static boolean debugEnabled = false; + + /** + * *enable info level log. + */ + protected static boolean infoEnabled = true; + + /** + * quite mode will out put nothing. + */ + protected static boolean quietMode = false; + + private static final String DEBUG_FIX = "StdLog:DEBUG: "; + + private static final String INFO_FIX = "StdLog:INFO: "; + + private static final String WARN_FIX = "StdLog:WARN: "; + + private StdLog() { + } + + public static void setQuietMode(boolean quietMode) { + StdLog.quietMode = quietMode; + } + + public static void setInfoEnabled(boolean infoEnabled) { + StdLog.infoEnabled = infoEnabled; + } + + public static void setDebugEnabled(boolean debugEnabled) { + StdLog.debugEnabled = debugEnabled; + } + + public static void debug(String msg) { + if (debugEnabled && !quietMode) { + println(System.out, DEBUG_FIX + msg); + } + } + + public static void info(String msg) { + if (infoEnabled && !quietMode) { + println(System.out, INFO_FIX + msg); + } + } + + public static void warn(String msg) { + if (infoEnabled && !quietMode) { + println(System.err, WARN_FIX + msg); + } + } + + public static void warn(String msg, Throwable t) { + if (quietMode) { + return; + } + println(System.err, WARN_FIX + msg); + if (t != null) { + t.printStackTrace(); + } + } + + private static void println(PrintStream out, String msg) { + out.println(Calendar.getInstance().getTime().toString() + " " + CLASS_INFO + " " + msg); + } +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/listener/ConfigChangeListenerTest.java b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/listener/ConfigChangeListenerTest.java index 24ad04d76..7a0bd5b60 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/listener/ConfigChangeListenerTest.java +++ b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/listener/ConfigChangeListenerTest.java @@ -104,7 +104,7 @@ public class ConfigChangeListenerTest { @PolarisConfigKVFileChangeListener(interestedKeys = {"timeout"}) public void configChangedListener(ConfigChangeEvent event) { ConfigPropertyChangeInfo changeInfo = event.getChange("timeout"); - timeout = Integer.parseInt(changeInfo.getNewValue()); + timeout = Integer.parseInt(changeInfo.getNewValue().toString()); changeCnt++; hits.countDown(); } @@ -112,7 +112,7 @@ public class ConfigChangeListenerTest { @PolarisConfigKVFileChangeListener(interestedKeyPrefixes = {"timeout"}) public void configChangedListener2(ConfigChangeEvent event) { ConfigPropertyChangeInfo changeInfo = event.getChange("timeout"); - timeout = Integer.parseInt(changeInfo.getNewValue()); + timeout = Integer.parseInt(changeInfo.getNewValue().toString()); changeCnt++; hits.countDown(); } diff --git a/spring-cloud-tencent-dependencies/pom.xml b/spring-cloud-tencent-dependencies/pom.xml index 08f17043f..ba525e015 100644 --- a/spring-cloud-tencent-dependencies/pom.xml +++ b/spring-cloud-tencent-dependencies/pom.xml @@ -73,7 +73,7 @@ 1.12.0-2021.0.8-SNAPSHOT - 1.14.0-SNAPSHOT + 1.14.0 32.0.1-jre 1.2.11 4.5.1 diff --git a/spring-cloud-tencent-examples/polaris-config-example/src/main/java/com/tencent/cloud/polaris/config/example/PersonConfigChangeListener.java b/spring-cloud-tencent-examples/polaris-config-example/src/main/java/com/tencent/cloud/polaris/config/example/PersonConfigChangeListener.java index 150e25e20..108b22038 100644 --- a/spring-cloud-tencent-examples/polaris-config-example/src/main/java/com/tencent/cloud/polaris/config/example/PersonConfigChangeListener.java +++ b/spring-cloud-tencent-examples/polaris-config-example/src/main/java/com/tencent/cloud/polaris/config/example/PersonConfigChangeListener.java @@ -42,7 +42,25 @@ public final class PersonConfigChangeListener { Set changedKeys = event.changedKeys(); for (String changedKey : changedKeys) { - System.out.printf("%s = %s \n", changedKey, event.getChange(changedKey)); + System.out.printf("%s = %s , ThreadId: %s\n", changedKey, event.getChange(changedKey), Thread.currentThread().getId()); + } + } + + @PolarisConfigKVFileChangeListener(interestedKeyPrefixes = "teacher", async = false) + public void syncListen(ConfigChangeEvent event) { + Set changedKeys = event.changedKeys(); + + for (String changedKey : changedKeys) { + System.out.printf("%s = %s , ThreadId: %s\n", changedKey, event.getChange(changedKey), Thread.currentThread().getId()); + } + } + + @PolarisConfigKVFileChangeListener(interestedKeyPrefixes = "teacher", async = false) + public void syncListen2(ConfigChangeEvent event) { + Set changedKeys = event.changedKeys(); + + for (String changedKey : changedKeys) { + System.out.printf("%s = %s , ThreadId: %s\n", changedKey, event.getChange(changedKey), Thread.currentThread().getId()); } } } 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 7bde159b3..498af60d1 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 @@ -31,6 +31,7 @@ import com.tencent.polaris.factory.ConfigAPIFactory; import com.tencent.polaris.factory.config.ConfigurationImpl; import org.apache.commons.lang.StringUtils; +import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.util.CollectionUtils; @@ -45,26 +46,31 @@ public class PolarisContextProperties { /** * polaris server address. */ + @Value("${spring.cloud.polaris.address:}") private String address; /** * current server local ip address. */ + @Value("${spring.cloud.polaris.localIpAddress:}") private String localIpAddress; /** * current server local port. */ + @Value("${spring.cloud.polaris.localPort:}") private Integer localPort; /** * If polaris enabled. */ + @Value("${spring.cloud.polaris.enabled:#{'true'}}") private Boolean enabled; /** * polaris namespace. */ + @Value("${spring.cloud.polaris.namespace:#{'default'}}") private String namespace = "default"; /**