From 5425338046f7dcef63f4356e601449d63fede90e Mon Sep 17 00:00:00 2001 From: weihu Date: Tue, 28 Jun 2022 13:57:00 +0800 Subject: [PATCH 01/13] optimization fefreshScop --- .../pom.xml | 10 + .../PolarisConfigAutoConfiguration.java | 12 ++ .../PolarisPropertySourceAutoRefresher.java | 121 ++++++++++-- .../exceptions/PolarisConfigException.java | 34 ++++ .../annotation/AbstractPolarisProcessor.java | 95 +++++++++ .../annotation/SpringValueProcessor.java | 160 +++++++++++++++ .../spring/property/PlaceholderHelper.java | 184 ++++++++++++++++++ .../config/spring/property/SpringValue.java | 150 ++++++++++++++ .../property/SpringValueDefinition.java | 49 +++++ .../SpringValueDefinitionProcessor.java | 110 +++++++++++ .../spring/property/SpringValueRegistry.java | 104 ++++++++++ .../polaris/config/util/SpringInjector.java | 72 +++++++ .../cloud/common/util/JacksonUtils.java | 15 ++ .../common/util/PolarisThreadFactory.java | 98 ++++++++++ 14 files changed, 1194 insertions(+), 20 deletions(-) create mode 100644 spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/exceptions/PolarisConfigException.java create mode 100644 spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/annotation/AbstractPolarisProcessor.java create mode 100644 spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/annotation/SpringValueProcessor.java create mode 100644 spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/property/PlaceholderHelper.java create mode 100644 spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/property/SpringValue.java create mode 100644 spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/property/SpringValueDefinition.java create mode 100644 spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/property/SpringValueDefinitionProcessor.java create mode 100644 spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/property/SpringValueRegistry.java create mode 100644 spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/util/SpringInjector.java create mode 100644 spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/PolarisThreadFactory.java diff --git a/spring-cloud-starter-tencent-polaris-config/pom.xml b/spring-cloud-starter-tencent-polaris-config/pom.xml index a7f0e5894..b2ebf9640 100644 --- a/spring-cloud-starter-tencent-polaris-config/pom.xml +++ b/spring-cloud-starter-tencent-polaris-config/pom.xml @@ -13,6 +13,10 @@ spring-cloud-starter-tencent-polaris-config Spring Cloud Starter Tencent Polaris Config + + 5.1.0 + + @@ -58,6 +62,12 @@ + + com.google.inject + guice + ${com.google.inject.version} + + org.springframework.cloud 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 cccea11bc..13244af84 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 @@ -23,6 +23,8 @@ import com.tencent.cloud.polaris.config.adapter.PolarisPropertySourceManager; import com.tencent.cloud.polaris.config.annotation.PolarisConfigAnnotationProcessor; import com.tencent.cloud.polaris.config.config.PolarisConfigProperties; import com.tencent.cloud.polaris.config.listener.PolarisConfigChangeEventListener; +import com.tencent.cloud.polaris.config.spring.annotation.SpringValueProcessor; +import com.tencent.cloud.polaris.config.spring.property.SpringValueDefinitionProcessor; import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; @@ -60,4 +62,14 @@ public class PolarisConfigAutoConfiguration { return new PolarisConfigChangeEventListener(); } + @Bean + public SpringValueProcessor springValueProcessor() { + return new SpringValueProcessor(); + } + + @Bean + public SpringValueDefinitionProcessor springValueDefinitionProcessor() { + return new SpringValueDefinitionProcessor(); + } + } diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertySourceAutoRefresher.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertySourceAutoRefresher.java index fac3ba255..415529385 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertySourceAutoRefresher.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertySourceAutoRefresher.java @@ -18,23 +18,32 @@ package com.tencent.cloud.polaris.config.adapter; +import java.lang.reflect.Field; +import java.util.Collection; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; +import com.tencent.cloud.common.util.JacksonUtils; import com.tencent.cloud.polaris.config.config.PolarisConfigProperties; +import com.tencent.cloud.polaris.config.spring.property.PlaceholderHelper; +import com.tencent.cloud.polaris.config.spring.property.SpringValue; +import com.tencent.cloud.polaris.config.spring.property.SpringValueRegistry; +import com.tencent.cloud.polaris.config.util.SpringInjector; import com.tencent.polaris.configuration.api.core.ConfigKVFileChangeEvent; import com.tencent.polaris.configuration.api.core.ConfigKVFileChangeListener; -import com.tencent.polaris.configuration.api.core.ConfigPropertyChangeInfo; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeansException; +import org.springframework.beans.TypeConverter; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.cloud.context.refresh.ContextRefresher; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.ApplicationListener; +import org.springframework.context.ConfigurableApplicationContext; import org.springframework.util.CollectionUtils; /** @@ -53,8 +62,18 @@ public class PolarisPropertySourceAutoRefresher private final PolarisPropertySourceManager polarisPropertySourceManager; + private final boolean typeConverterHasConvertIfNecessaryWithFieldParameter; + + private TypeConverter typeConverter; + private ApplicationContext applicationContext; + private final SpringValueRegistry springValueRegistry; + + private ConfigurableBeanFactory beanFactory; + + private final PlaceholderHelper placeholderHelper; + private final ContextRefresher contextRefresher; private final AtomicBoolean registered = new AtomicBoolean(false); @@ -66,12 +85,19 @@ public class PolarisPropertySourceAutoRefresher this.polarisConfigProperties = polarisConfigProperties; this.polarisPropertySourceManager = polarisPropertySourceManager; this.contextRefresher = contextRefresher; + this.springValueRegistry = SpringInjector.getInstance(SpringValueRegistry.class); + this.placeholderHelper = SpringInjector.getInstance(PlaceholderHelper.class); + this.typeConverterHasConvertIfNecessaryWithFieldParameter = testTypeConverterHasConvertIfNecessaryWithFieldParameter(); + + } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; + this.beanFactory = ((ConfigurableApplicationContext) applicationContext).getBeanFactory(); + this.typeConverter = this.beanFactory.getTypeConverter(); } @Override @@ -110,32 +136,87 @@ public class PolarisPropertySourceAutoRefresher Map source = polarisPropertySource .getSource(); + + for (String changedKey : configKVFileChangeEvent.changedKeys()) { - 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; + // 1. check whether the changed key is relevant + Collection targetValues = springValueRegistry.get(beanFactory, changedKey); + if (targetValues == null || targetValues.isEmpty()) { + continue; + } + + // 2. update the value + for (SpringValue val : targetValues) { + updateSpringValue(val); } } - // rebuild beans with @RefreshScope annotation - contextRefresher.refresh(); } }); } } + + private void updateSpringValue(SpringValue springValue) { + try { + Object value = resolvePropertyValue(springValue); + springValue.update(value); + + LOGGER.info("Auto update polaris changed value successfully, new value: {}, {}", value, + springValue); + } catch (Throwable ex) { + LOGGER.error("Auto update polaris changed value failed, {}", springValue.toString(), ex); + } + } + + + /** + * Logic transplanted from DefaultListableBeanFactory + * + * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency(org.springframework.beans.factory.config.DependencyDescriptor, + * java.lang.String, java.util.Set, org.springframework.beans.TypeConverter) + */ + private Object resolvePropertyValue(SpringValue springValue) { + // value will never be null, as @Value and @ApolloJsonValue will not allow that + Object value = placeholderHelper + .resolvePropertyValue(beanFactory, springValue.getBeanName(), springValue.getPlaceholder()); + + if (springValue.isJson()) { + value = parseJsonValue((String) value, springValue.getTargetType()); + } else { + if (springValue.isField()) { + // org.springframework.beans.TypeConverter#convertIfNecessary(java.lang.Object, java.lang.Class, java.lang.reflect.Field) is available from Spring 3.2.0+ + if (typeConverterHasConvertIfNecessaryWithFieldParameter) { + value = this.typeConverter + .convertIfNecessary(value, springValue.getTargetType(), springValue.getField()); + } else { + value = this.typeConverter.convertIfNecessary(value, springValue.getTargetType()); + } + } else { + value = this.typeConverter.convertIfNecessary(value, springValue.getTargetType(), + springValue.getMethodParameter()); + } + } + + return value; + } + + private Object parseJsonValue(String json, Class targetType) { + try { + return JacksonUtils.json2JavaBean(json, targetType); + } catch (Throwable ex) { + LOGGER.error("Parsing json '{}' to type {} failed!", json, targetType, ex); + throw ex; + } + } + + private boolean testTypeConverterHasConvertIfNecessaryWithFieldParameter() { + try { + TypeConverter.class.getMethod("convertIfNecessary", Object.class, Class.class, Field.class); + } catch (Throwable ex) { + return false; + } + return true; + } + } diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/exceptions/PolarisConfigException.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/exceptions/PolarisConfigException.java new file mode 100644 index 000000000..10312a57f --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/exceptions/PolarisConfigException.java @@ -0,0 +1,34 @@ +/* + * 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.exceptions; + +/** + *@author : wh + *@date : 2022/6/28 09:31 + *@description: + */ +public class PolarisConfigException extends RuntimeException { + public PolarisConfigException(String message) { + super(message); + } + + public PolarisConfigException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/annotation/AbstractPolarisProcessor.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/annotation/AbstractPolarisProcessor.java new file mode 100644 index 000000000..da3429b7c --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/annotation/AbstractPolarisProcessor.java @@ -0,0 +1,95 @@ +/* + * 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.spring.annotation; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.LinkedList; +import java.util.List; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.core.Ordered; +import org.springframework.core.PriorityOrdered; +import org.springframework.util.ReflectionUtils; + +/** + *@author : wh + *@date : 2022/6/28 09:18 + *@description: + */ +public abstract class AbstractPolarisProcessor implements BeanPostProcessor, PriorityOrdered { + + @Override + public Object postProcessBeforeInitialization(Object bean, String beanName) + throws BeansException { + Class clazz = bean.getClass(); + for (Field field : findAllField(clazz)) { + processField(bean, beanName, field); + } + for (Method method : findAllMethod(clazz)) { + processMethod(bean, beanName, method); + } + return bean; + } + + @Override + public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { + return bean; + } + + /** + * subclass should implement this method to process field + */ + protected abstract void processField(Object bean, String beanName, Field field); + + /** + * subclass should implement this method to process method + */ + protected abstract void processMethod(Object bean, String beanName, Method method); + + + @Override + public int getOrder() { + //make it as late as possible + return Ordered.LOWEST_PRECEDENCE; + } + + private List findAllField(Class clazz) { + final List res = new LinkedList<>(); + ReflectionUtils.doWithFields(clazz, new ReflectionUtils.FieldCallback() { + @Override + public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException { + res.add(field); + } + }); + return res; + } + + private List findAllMethod(Class clazz) { + final List res = new LinkedList<>(); + ReflectionUtils.doWithMethods(clazz, new ReflectionUtils.MethodCallback() { + @Override + public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException { + res.add(method); + } + }); + return res; + } +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/annotation/SpringValueProcessor.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/annotation/SpringValueProcessor.java new file mode 100644 index 000000000..1428280a9 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/annotation/SpringValueProcessor.java @@ -0,0 +1,160 @@ +package com.tencent.cloud.polaris.config.spring.annotation; + +import java.beans.PropertyDescriptor; +import java.lang.reflect.Field; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.util.Collection; +import java.util.Set; + +import com.google.common.collect.LinkedListMultimap; +import com.google.common.collect.Multimap; +import com.tencent.cloud.polaris.config.spring.property.PlaceholderHelper; +import com.tencent.cloud.polaris.config.spring.property.SpringValue; +import com.tencent.cloud.polaris.config.spring.property.SpringValueDefinition; +import com.tencent.cloud.polaris.config.spring.property.SpringValueDefinitionProcessor; +import com.tencent.cloud.polaris.config.spring.property.SpringValueRegistry; +import com.tencent.cloud.polaris.config.util.SpringInjector; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.beans.BeanUtils; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanFactoryAware; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.beans.factory.config.BeanFactoryPostProcessor; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.context.annotation.Bean; + +/** + *@author : wh + *@date : 2022/6/28 09:19 + *@description: + */ +public class SpringValueProcessor extends AbstractPolarisProcessor implements BeanFactoryPostProcessor, BeanFactoryAware { + + private static final Logger logger = LoggerFactory.getLogger(SpringValueProcessor.class); + + private final PlaceholderHelper placeholderHelper; + private final SpringValueRegistry springValueRegistry; + + private BeanFactory beanFactory; + private Multimap beanName2SpringValueDefinitions; + + public SpringValueProcessor() { + placeholderHelper = SpringInjector.getInstance(PlaceholderHelper.class); + springValueRegistry = SpringInjector.getInstance(SpringValueRegistry.class); + beanName2SpringValueDefinitions = LinkedListMultimap.create(); + } + + @Override + public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) + throws BeansException { + // 默认开启 + if (beanFactory instanceof BeanDefinitionRegistry) { + beanName2SpringValueDefinitions = SpringValueDefinitionProcessor + .getBeanName2SpringValueDefinitions((BeanDefinitionRegistry) beanFactory); + } + } + + @Override + public Object postProcessBeforeInitialization(Object bean, String beanName) + throws BeansException { + // 默认开启 + super.postProcessBeforeInitialization(bean, beanName); + processBeanPropertyValues(bean, beanName); + return bean; + } + + + @Override + protected void processField(Object bean, String beanName, Field field) { + // register @Value on field + Value value = field.getAnnotation(Value.class); + if (value == null) { + return; + } + + doRegister(bean, beanName, field, value); + } + + @Override + protected void processMethod(Object bean, String beanName, Method method) { + //register @Value on method + Value value = method.getAnnotation(Value.class); + if (value == null) { + return; + } + //skip Configuration bean methods + if (method.getAnnotation(Bean.class) != null) { + return; + } + if (method.getParameterTypes().length != 1) { + logger.error("Ignore @Value setter {}.{}, expecting 1 parameter, actual {} parameters", + bean.getClass().getName(), method.getName(), method.getParameterTypes().length); + return; + } + + doRegister(bean, beanName, method, value); + } + + private void doRegister(Object bean, String beanName, Member member, Value value) { + Set keys = placeholderHelper.extractPlaceholderKeys(value.value()); + if (keys.isEmpty()) { + return; + } + + for (String key : keys) { + SpringValue springValue; + if (member instanceof Field) { + Field field = (Field) member; + springValue = new SpringValue(key, value.value(), bean, beanName, field, false); + } else if (member instanceof Method) { + Method method = (Method) member; + springValue = new SpringValue(key, value.value(), bean, beanName, method, false); + } else { + logger.error("polaris @Value annotation currently only support to be used on methods and fields, " + + "but is used on {}", member.getClass()); + return; + } + springValueRegistry.register(beanFactory, key, springValue); + logger.info("Monitoring {}", springValue); + } + } + + private void processBeanPropertyValues(Object bean, String beanName) { + Collection propertySpringValues = beanName2SpringValueDefinitions + .get(beanName); + if (propertySpringValues == null || propertySpringValues.isEmpty()) { + return; + } + + for (SpringValueDefinition definition : propertySpringValues) { + try { + PropertyDescriptor pd = BeanUtils + .getPropertyDescriptor(bean.getClass(), definition.getPropertyName()); + Method method = pd.getWriteMethod(); + if (method == null) { + continue; + } + SpringValue springValue = new SpringValue(definition.getKey(), definition.getPlaceholder(), + bean, beanName, method, false); + springValueRegistry.register(beanFactory, definition.getKey(), springValue); + logger.debug("Monitoring {}", springValue); + } catch (Throwable ex) { + logger.error("Failed to enable auto update feature for {}.{}", bean.getClass(), + definition.getPropertyName()); + } + } + + // clear + beanName2SpringValueDefinitions.removeAll(beanName); + } + + @Override + public void setBeanFactory(BeanFactory beanFactory) throws BeansException { + this.beanFactory = beanFactory; + } +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/property/PlaceholderHelper.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/property/PlaceholderHelper.java new file mode 100644 index 000000000..3d1eb37dc --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/property/PlaceholderHelper.java @@ -0,0 +1,184 @@ +/* + * 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.spring.property; + +import java.util.Set; +import java.util.Stack; + +import com.google.common.base.Strings; +import com.google.common.collect.Sets; + +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.BeanExpressionContext; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.beans.factory.config.Scope; +import org.springframework.util.StringUtils; + +/** + *@author : wh + *@date : 2022/6/28 09:24 + *@description: + */ +public class PlaceholderHelper { + + private static final String PLACEHOLDER_PREFIX = "${"; + private static final String PLACEHOLDER_SUFFIX = "}"; + private static final String VALUE_SEPARATOR = ":"; + private static final String SIMPLE_PLACEHOLDER_PREFIX = "{"; + private static final String EXPRESSION_PREFIX = "#{"; + private static final String EXPRESSION_SUFFIX = "}"; + + /** + * Resolve placeholder property values, e.g. + *
+ *
+ * "${somePropertyValue}" -> "the actual property value" + */ + public Object resolvePropertyValue(ConfigurableBeanFactory beanFactory, String beanName, String placeholder) { + // resolve string value + String strVal = beanFactory.resolveEmbeddedValue(placeholder); + + BeanDefinition bd = (beanFactory.containsBean(beanName) ? beanFactory + .getMergedBeanDefinition(beanName) : null); + + // resolve expressions like "#{systemProperties.myProp}" + return evaluateBeanDefinitionString(beanFactory, strVal, bd); + } + + private Object evaluateBeanDefinitionString(ConfigurableBeanFactory beanFactory, String value, + BeanDefinition beanDefinition) { + if (beanFactory.getBeanExpressionResolver() == null) { + return value; + } + Scope scope = (beanDefinition != null ? beanFactory + .getRegisteredScope(beanDefinition.getScope()) : null); + return beanFactory.getBeanExpressionResolver() + .evaluate(value, new BeanExpressionContext(beanFactory, scope)); + } + + /** + * Extract keys from placeholder, e.g. + *
    + *
  • ${some.key} => "some.key"
  • + *
  • ${some.key:${some.other.key:100}} => "some.key", "some.other.key"
  • + *
  • ${${some.key}} => "some.key"
  • + *
  • ${${some.key:other.key}} => "some.key"
  • + *
  • ${${some.key}:${another.key}} => "some.key", "another.key"
  • + *
  • #{new java.text.SimpleDateFormat('${some.key}').parse('${another.key}')} => "some.key", "another.key"
  • + *
+ */ + public Set extractPlaceholderKeys(String propertyString) { + Set placeholderKeys = Sets.newHashSet(); + + if (Strings.isNullOrEmpty(propertyString) || (!isNormalizedPlaceholder(propertyString) && !isExpressionWithPlaceholder(propertyString))) { + return placeholderKeys; + } + + Stack stack = new Stack<>(); + stack.push(propertyString); + + while (!stack.isEmpty()) { + String strVal = stack.pop(); + int startIndex = strVal.indexOf(PLACEHOLDER_PREFIX); + if (startIndex == -1) { + placeholderKeys.add(strVal); + continue; + } + int endIndex = findPlaceholderEndIndex(strVal, startIndex); + if (endIndex == -1) { + // invalid placeholder? + continue; + } + + String placeholderCandidate = strVal.substring(startIndex + PLACEHOLDER_PREFIX.length(), endIndex); + + // ${some.key:other.key} + if (placeholderCandidate.startsWith(PLACEHOLDER_PREFIX)) { + stack.push(placeholderCandidate); + } else { + // some.key:${some.other.key:100} + int separatorIndex = placeholderCandidate.indexOf(VALUE_SEPARATOR); + + if (separatorIndex == -1) { + stack.push(placeholderCandidate); + } else { + stack.push(placeholderCandidate.substring(0, separatorIndex)); + String defaultValuePart = + normalizeToPlaceholder(placeholderCandidate.substring(separatorIndex + VALUE_SEPARATOR.length())); + if (!Strings.isNullOrEmpty(defaultValuePart)) { + stack.push(defaultValuePart); + } + } + } + + // has remaining part, e.g. ${a}.${b} + if (endIndex + PLACEHOLDER_SUFFIX.length() < strVal.length() - 1) { + String remainingPart = normalizeToPlaceholder(strVal.substring(endIndex + PLACEHOLDER_SUFFIX.length())); + if (!Strings.isNullOrEmpty(remainingPart)) { + stack.push(remainingPart); + } + } + } + + return placeholderKeys; + } + + private boolean isNormalizedPlaceholder(String propertyString) { + return propertyString.startsWith(PLACEHOLDER_PREFIX) && propertyString.contains(PLACEHOLDER_SUFFIX); + } + + private boolean isExpressionWithPlaceholder(String propertyString) { + return propertyString.startsWith(EXPRESSION_PREFIX) && propertyString.contains(EXPRESSION_SUFFIX) + && propertyString.contains(PLACEHOLDER_PREFIX) && propertyString.contains(PLACEHOLDER_SUFFIX); + } + + private String normalizeToPlaceholder(String strVal) { + int startIndex = strVal.indexOf(PLACEHOLDER_PREFIX); + if (startIndex == -1) { + return null; + } + int endIndex = strVal.lastIndexOf(PLACEHOLDER_SUFFIX); + if (endIndex == -1) { + return null; + } + + return strVal.substring(startIndex, endIndex + PLACEHOLDER_SUFFIX.length()); + } + + private int findPlaceholderEndIndex(CharSequence buf, int startIndex) { + int index = startIndex + PLACEHOLDER_PREFIX.length(); + int withinNestedPlaceholder = 0; + while (index < buf.length()) { + if (StringUtils.substringMatch(buf, index, PLACEHOLDER_SUFFIX)) { + if (withinNestedPlaceholder > 0) { + withinNestedPlaceholder--; + index = index + PLACEHOLDER_SUFFIX.length(); + } else { + return index; + } + } else if (StringUtils.substringMatch(buf, index, SIMPLE_PLACEHOLDER_PREFIX)) { + withinNestedPlaceholder++; + index = index + SIMPLE_PLACEHOLDER_PREFIX.length(); + } else { + index++; + } + } + return -1; + } +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/property/SpringValue.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/property/SpringValue.java new file mode 100644 index 000000000..6e0f3bec9 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/property/SpringValue.java @@ -0,0 +1,150 @@ +/* + * 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.spring.property; + +import java.lang.ref.WeakReference; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Type; + +import org.springframework.core.MethodParameter; + +/** + *@author : wh + *@date : 2022/6/28 09:25 + *@description: + */ +public class SpringValue { + + private MethodParameter methodParameter; + private Field field; + private WeakReference beanRef; + private String beanName; + private String key; + private String placeholder; + private Class targetType; + private Type genericType; + private boolean isJson; + + public SpringValue(String key, String placeholder, Object bean, String beanName, Field field, boolean isJson) { + this.beanRef = new WeakReference<>(bean); + this.beanName = beanName; + this.field = field; + this.key = key; + this.placeholder = placeholder; + this.targetType = field.getType(); + this.isJson = isJson; + if(isJson){ + this.genericType = field.getGenericType(); + } + } + + public SpringValue(String key, String placeholder, Object bean, String beanName, Method method, boolean isJson) { + this.beanRef = new WeakReference<>(bean); + this.beanName = beanName; + this.methodParameter = new MethodParameter(method, 0); + this.key = key; + this.placeholder = placeholder; + Class[] paramTps = method.getParameterTypes(); + this.targetType = paramTps[0]; + this.isJson = isJson; + if(isJson){ + this.genericType = method.getGenericParameterTypes()[0]; + } + } + + public void update(Object newVal) throws IllegalAccessException, InvocationTargetException { + if (isField()) { + injectField(newVal); + } else { + injectMethod(newVal); + } + } + + private void injectField(Object newVal) throws IllegalAccessException { + Object bean = beanRef.get(); + if (bean == null) { + return; + } + boolean accessible = field.isAccessible(); + field.setAccessible(true); + field.set(bean, newVal); + field.setAccessible(accessible); + } + + private void injectMethod(Object newVal) + throws InvocationTargetException, IllegalAccessException { + Object bean = beanRef.get(); + if (bean == null) { + return; + } + methodParameter.getMethod().invoke(bean, newVal); + } + + public String getBeanName() { + return beanName; + } + + public Class getTargetType() { + return targetType; + } + + public String getPlaceholder() { + return this.placeholder; + } + + public MethodParameter getMethodParameter() { + return methodParameter; + } + + public boolean isField() { + return this.field != null; + } + + public Field getField() { + return field; + } + + public Type getGenericType() { + return genericType; + } + + public boolean isJson() { + return isJson; + } + + boolean isTargetBeanValid() { + return beanRef.get() != null; + } + + @Override + public String toString() { + Object bean = beanRef.get(); + if (bean == null) { + return ""; + } + if (isField()) { + return String + .format("key: %s, beanName: %s, field: %s.%s", key, beanName, bean.getClass().getName(), field.getName()); + } + return String.format("key: %s, beanName: %s, method: %s.%s", key, beanName, bean.getClass().getName(), + methodParameter.getMethod().getName()); + } +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/property/SpringValueDefinition.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/property/SpringValueDefinition.java new file mode 100644 index 000000000..7de28a528 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/property/SpringValueDefinition.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.spring.property; + +/** + *@author : wh + *@date : 2022/6/28 09:28 + *@description: + */ +public class SpringValueDefinition { + + private final String key; + private final String placeholder; + private final String propertyName; + + public SpringValueDefinition(String key, String placeholder, String propertyName) { + this.key = key; + this.placeholder = placeholder; + this.propertyName = propertyName; + } + + public String getKey() { + return key; + } + + public String getPlaceholder() { + return placeholder; + } + + public String getPropertyName() { + return propertyName; + } +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/property/SpringValueDefinitionProcessor.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/property/SpringValueDefinitionProcessor.java new file mode 100644 index 000000000..af1baf8ba --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/property/SpringValueDefinitionProcessor.java @@ -0,0 +1,110 @@ +/* + * 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.spring.property; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.google.common.collect.LinkedListMultimap; +import com.google.common.collect.Maps; +import com.google.common.collect.Multimap; +import com.google.common.collect.Sets; +import com.tencent.cloud.polaris.config.util.SpringInjector; + +import org.springframework.beans.BeansException; +import org.springframework.beans.MutablePropertyValues; +import org.springframework.beans.PropertyValue; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.config.TypedStringValue; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; + +/** + *@author : wh + *@date : 2022/6/28 09:30 + *@description: + */ +public class SpringValueDefinitionProcessor implements BeanDefinitionRegistryPostProcessor { + private static final Map> beanName2SpringValueDefinitions = + Maps.newConcurrentMap(); + private static final Set PROPERTY_VALUES_PROCESSED_BEAN_FACTORIES = Sets.newConcurrentHashSet(); + private final PlaceholderHelper placeholderHelper; + + public SpringValueDefinitionProcessor() { + placeholderHelper = SpringInjector.getInstance(PlaceholderHelper.class); + } + + @Override + public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { + // 默认开启 + processPropertyValues(registry); + } + + @Override + public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { + + } + + public static Multimap getBeanName2SpringValueDefinitions(BeanDefinitionRegistry registry) { + Multimap springValueDefinitions = beanName2SpringValueDefinitions.get(registry); + if (springValueDefinitions == null) { + springValueDefinitions = LinkedListMultimap.create(); + } + + return springValueDefinitions; + } + + private void processPropertyValues(BeanDefinitionRegistry beanRegistry) { + if (!PROPERTY_VALUES_PROCESSED_BEAN_FACTORIES.add(beanRegistry)) { + // already initialized + return; + } + + if (!beanName2SpringValueDefinitions.containsKey(beanRegistry)) { + beanName2SpringValueDefinitions.put(beanRegistry, LinkedListMultimap.create()); + } + + Multimap springValueDefinitions = beanName2SpringValueDefinitions.get(beanRegistry); + + String[] beanNames = beanRegistry.getBeanDefinitionNames(); + for (String beanName : beanNames) { + BeanDefinition beanDefinition = beanRegistry.getBeanDefinition(beanName); + MutablePropertyValues mutablePropertyValues = beanDefinition.getPropertyValues(); + List propertyValues = mutablePropertyValues.getPropertyValueList(); + for (PropertyValue propertyValue : propertyValues) { + Object value = propertyValue.getValue(); + if (!(value instanceof TypedStringValue)) { + continue; + } + String placeholder = ((TypedStringValue) value).getValue(); + Set keys = placeholderHelper.extractPlaceholderKeys(placeholder); + + if (keys.isEmpty()) { + continue; + } + + for (String key : keys) { + springValueDefinitions.put(beanName, new SpringValueDefinition(key, placeholder, propertyValue.getName())); + } + } + } + } +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/property/SpringValueRegistry.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/property/SpringValueRegistry.java new file mode 100644 index 000000000..283defb47 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/property/SpringValueRegistry.java @@ -0,0 +1,104 @@ +/* + * 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.spring.property; + +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import com.google.common.collect.LinkedListMultimap; +import com.google.common.collect.Maps; +import com.google.common.collect.Multimap; +import com.google.common.collect.Multimaps; +import com.tencent.cloud.common.util.PolarisThreadFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.beans.factory.BeanFactory; + +/** + *@author : wh + *@date : 2022/6/28 09:24 + *@description: + */ +public class SpringValueRegistry { + private static final Logger logger = LoggerFactory.getLogger(SpringValueRegistry.class); + + private static final long CLEAN_INTERVAL_IN_SECONDS = 5; + private final Map> registry = Maps.newConcurrentMap(); + private final AtomicBoolean initialized = new AtomicBoolean(false); + private final Object LOCK = new Object(); + + public void register(BeanFactory beanFactory, String key, SpringValue springValue) { + if (!registry.containsKey(beanFactory)) { + synchronized (LOCK) { + if (!registry.containsKey(beanFactory)) { + registry.put(beanFactory, Multimaps.synchronizedListMultimap(LinkedListMultimap.create())); + } + } + } + + registry.get(beanFactory).put(key, springValue); + + // lazy initialize + if (initialized.compareAndSet(false, true)) { + initialize(); + } + } + + public Collection get(BeanFactory beanFactory, String key) { + Multimap beanFactorySpringValues = registry.get(beanFactory); + if (beanFactorySpringValues == null) { + return null; + } + return beanFactorySpringValues.get(key); + } + + private void initialize() { + Executors.newSingleThreadScheduledExecutor(PolarisThreadFactory.create("SpringValueRegistry", true)).scheduleAtFixedRate( + new Runnable() { + @Override + public void run() { + try { + scanAndClean(); + } catch (Throwable ex) { + logger.error(ex.getMessage(), ex); + } + } + }, CLEAN_INTERVAL_IN_SECONDS, CLEAN_INTERVAL_IN_SECONDS, TimeUnit.SECONDS); + } + + private void scanAndClean() { + Iterator> iterator = registry.values().iterator(); + while (!Thread.currentThread().isInterrupted() && iterator.hasNext()) { + Multimap springValues = iterator.next(); + Iterator> springValueIterator = springValues.entries().iterator(); + while (springValueIterator.hasNext()) { + Map.Entry springValue = springValueIterator.next(); + if (!springValue.getValue().isTargetBeanValid()) { + // clear unused spring values + springValueIterator.remove(); + } + } + } + } +} diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/util/SpringInjector.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/util/SpringInjector.java new file mode 100644 index 000000000..da408e145 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/util/SpringInjector.java @@ -0,0 +1,72 @@ +/* + * 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.util; + +import com.google.inject.AbstractModule; +import com.google.inject.Guice; +import com.google.inject.Injector; +import com.google.inject.Singleton; +import com.tencent.cloud.polaris.config.exceptions.PolarisConfigException; +import com.tencent.cloud.polaris.config.spring.property.PlaceholderHelper; +import com.tencent.cloud.polaris.config.spring.property.SpringValueRegistry; + +/** + *@author : wh + *@date : 2022/6/28 09:30 + *@description: + */ +public class SpringInjector { + private static volatile Injector s_injector; + private static final Object lock = new Object(); + + private static Injector getInjector() { + if (s_injector == null) { + synchronized (lock) { + if (s_injector == null) { + try { + s_injector = Guice.createInjector(new SpringModule()); + } catch (Throwable ex) { + PolarisConfigException exception = new PolarisConfigException("Unable to initialize Apollo Spring Injector!", ex); + throw exception; + } + } + } + } + + return s_injector; + } + + public static T getInstance(Class clazz) { + try { + return getInjector().getInstance(clazz); + } catch (Throwable ex) { + throw new PolarisConfigException( + String.format("Unable to load instance for %s!", clazz.getName()), ex); + } + } + + private static class SpringModule extends AbstractModule { + @Override + protected void configure() { + bind(PlaceholderHelper.class).in(Singleton.class); +// bind(ConfigPropertySourceFactory.class).in(Singleton.class); + bind(SpringValueRegistry.class).in(Singleton.class); + } + } +} diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/JacksonUtils.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/JacksonUtils.java index a30fc8bc1..a0987a399 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/JacksonUtils.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/JacksonUtils.java @@ -17,6 +17,12 @@ package com.tencent.cloud.common.util; +import java.lang.reflect.Array; +import java.lang.reflect.GenericArrayType; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; +import java.lang.reflect.WildcardType; import java.util.HashMap; import java.util.Map; @@ -86,4 +92,13 @@ public final class JacksonUtils { } } + public static T json2JavaBean(String content, Class valueType) { + try { + return OM.readValue(content, valueType); + } catch (Exception e) { + LOG.error("Object to Json failed. {}", content, e); + throw new RuntimeException("Object to Json failed.", e); + } + } + } diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/PolarisThreadFactory.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/PolarisThreadFactory.java new file mode 100644 index 000000000..bba354eef --- /dev/null +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/PolarisThreadFactory.java @@ -0,0 +1,98 @@ +package com.tencent.cloud.common.util; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + *@author : wh + *@date : 2022/6/28 09:26 + *@description: + */ +public class PolarisThreadFactory implements ThreadFactory { + private static Logger log = LoggerFactory.getLogger(PolarisThreadFactory.class); + + private final AtomicLong threadNumber = new AtomicLong(1); + + private final String namePrefix; + + private final boolean daemon; + + private static final ThreadGroup threadGroup = new ThreadGroup("Polaris"); + + public static ThreadGroup getThreadGroup() { + return threadGroup; + } + + public static ThreadFactory create(String namePrefix, boolean daemon) { + return new PolarisThreadFactory(namePrefix, daemon); + } + + public static boolean waitAllShutdown(int timeoutInMillis) { + ThreadGroup group = getThreadGroup(); + Thread[] activeThreads = new Thread[group.activeCount()]; + group.enumerate(activeThreads); + Set alives = new HashSet<>(Arrays.asList(activeThreads)); + Set dies = new HashSet<>(); + log.info("Current ACTIVE thread count is: {}", alives.size()); + long expire = System.currentTimeMillis() + timeoutInMillis; + while (System.currentTimeMillis() < expire) { + classify(alives, dies, new ClassifyStandard() { + @Override + public boolean satisfy(Thread thread) { + return !thread.isAlive() || thread.isInterrupted() || thread.isDaemon(); + } + }); + if (alives.size() > 0) { + log.info("Alive polaris threads: {}", alives); + try { + TimeUnit.SECONDS.sleep(2); + } catch (InterruptedException ex) { + // ignore + } + } else { + log.info("All polaris threads are shutdown."); + return true; + } + } + log.warn("Some polaris threads are still alive but expire time has reached, alive threads: {}", + alives); + return false; + } + + private interface ClassifyStandard { + boolean satisfy(T thread); + } + + private static void classify(Set src, Set des, ClassifyStandard standard) { + Set set = new HashSet<>(); + for (T t : src) { + if (standard.satisfy(t)) { + set.add(t); + } + } + src.removeAll(set); + des.addAll(set); + } + + private PolarisThreadFactory(String namePrefix, boolean daemon) { + this.namePrefix = namePrefix; + this.daemon = daemon; + } + + public Thread newThread(Runnable runnable) { + Thread thread = new Thread(threadGroup, runnable,// + threadGroup.getName() + "-" + namePrefix + "-" + threadNumber.getAndIncrement()); + thread.setDaemon(daemon); + if (thread.getPriority() != Thread.NORM_PRIORITY) { + thread.setPriority(Thread.NORM_PRIORITY); + } + return thread; + } +} From 72fff2459f1b887bb81758494f1f17689fd05f02 Mon Sep 17 00:00:00 2001 From: weihu Date: Tue, 28 Jun 2022 14:02:27 +0800 Subject: [PATCH 02/13] optimization fefreshScop --- .../java/com/tencent/cloud/common/util/JacksonUtils.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/JacksonUtils.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/JacksonUtils.java index a0987a399..15ca7163b 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/JacksonUtils.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/JacksonUtils.java @@ -17,12 +17,6 @@ package com.tencent.cloud.common.util; -import java.lang.reflect.Array; -import java.lang.reflect.GenericArrayType; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; -import java.lang.reflect.TypeVariable; -import java.lang.reflect.WildcardType; import java.util.HashMap; import java.util.Map; @@ -95,7 +89,8 @@ public final class JacksonUtils { public static T json2JavaBean(String content, Class valueType) { try { return OM.readValue(content, valueType); - } catch (Exception e) { + } + catch (Exception e) { LOG.error("Object to Json failed. {}", content, e); throw new RuntimeException("Object to Json failed.", e); } From 2f27841691d849479cc980c5eadb5b284db7c818 Mon Sep 17 00:00:00 2001 From: weihu Date: Tue, 28 Jun 2022 14:24:31 +0800 Subject: [PATCH 03/13] format code --- .../PolarisConfigAutoConfiguration.java | 2 +- .../PolarisPropertySourceAutoRefresher.java | 23 ++++++++++------- .../annotation/AbstractPolarisProcessor.java | 11 ++++++-- .../annotation/SpringValueProcessor.java | 11 +++++--- .../spring/property/PlaceholderHelper.java | 25 +++++++++++++------ .../config/spring/property/SpringValue.java | 10 +++++--- .../spring/property/SpringValueRegistry.java | 24 ++++++++++-------- .../polaris/config/util/SpringInjector.java | 6 +++-- .../common/util/PolarisThreadFactory.java | 18 +++++++------ .../src/main/resources/bootstrap.yml | 4 +-- 10 files changed, 84 insertions(+), 50 deletions(-) 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 13244af84..5f5f78092 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 @@ -66,7 +66,7 @@ public class PolarisConfigAutoConfiguration { public SpringValueProcessor springValueProcessor() { return new SpringValueProcessor(); } - + @Bean public SpringValueDefinitionProcessor springValueDefinitionProcessor() { return new SpringValueDefinitionProcessor(); diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertySourceAutoRefresher.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertySourceAutoRefresher.java index 415529385..e099c55f7 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertySourceAutoRefresher.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertySourceAutoRefresher.java @@ -89,7 +89,6 @@ public class PolarisPropertySourceAutoRefresher this.placeholderHelper = SpringInjector.getInstance(PlaceholderHelper.class); this.typeConverterHasConvertIfNecessaryWithFieldParameter = testTypeConverterHasConvertIfNecessaryWithFieldParameter(); - } @Override @@ -136,7 +135,7 @@ public class PolarisPropertySourceAutoRefresher Map source = polarisPropertySource .getSource(); - + for (String changedKey : configKVFileChangeEvent.changedKeys()) { // 1. check whether the changed key is relevant @@ -164,14 +163,15 @@ public class PolarisPropertySourceAutoRefresher LOGGER.info("Auto update polaris changed value successfully, new value: {}, {}", value, springValue); - } catch (Throwable ex) { + } + catch (Throwable ex) { LOGGER.error("Auto update polaris changed value failed, {}", springValue.toString(), ex); } } /** - * Logic transplanted from DefaultListableBeanFactory + * Logic transplanted from DefaultListableBeanFactory. * * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency(org.springframework.beans.factory.config.DependencyDescriptor, * java.lang.String, java.util.Set, org.springframework.beans.TypeConverter) @@ -183,16 +183,19 @@ public class PolarisPropertySourceAutoRefresher if (springValue.isJson()) { value = parseJsonValue((String) value, springValue.getTargetType()); - } else { + } + else { if (springValue.isField()) { // org.springframework.beans.TypeConverter#convertIfNecessary(java.lang.Object, java.lang.Class, java.lang.reflect.Field) is available from Spring 3.2.0+ if (typeConverterHasConvertIfNecessaryWithFieldParameter) { value = this.typeConverter .convertIfNecessary(value, springValue.getTargetType(), springValue.getField()); - } else { + } + else { value = this.typeConverter.convertIfNecessary(value, springValue.getTargetType()); } - } else { + } + else { value = this.typeConverter.convertIfNecessary(value, springValue.getTargetType(), springValue.getMethodParameter()); } @@ -204,7 +207,8 @@ public class PolarisPropertySourceAutoRefresher private Object parseJsonValue(String json, Class targetType) { try { return JacksonUtils.json2JavaBean(json, targetType); - } catch (Throwable ex) { + } + catch (Throwable ex) { LOGGER.error("Parsing json '{}' to type {} failed!", json, targetType, ex); throw ex; } @@ -213,7 +217,8 @@ public class PolarisPropertySourceAutoRefresher private boolean testTypeConverterHasConvertIfNecessaryWithFieldParameter() { try { TypeConverter.class.getMethod("convertIfNecessary", Object.class, Class.class, Field.class); - } catch (Throwable ex) { + } + catch (Throwable ex) { return false; } return true; diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/annotation/AbstractPolarisProcessor.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/annotation/AbstractPolarisProcessor.java index da3429b7c..ac81f6b96 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/annotation/AbstractPolarisProcessor.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/annotation/AbstractPolarisProcessor.java @@ -54,13 +54,20 @@ public abstract class AbstractPolarisProcessor implements BeanPostProcessor, Pri return bean; } + /** - * subclass should implement this method to process field + * subclass should implement this method to process field. + * @param bean bean + * @param beanName beanName + * @param field field */ protected abstract void processField(Object bean, String beanName, Field field); /** - * subclass should implement this method to process method + * subclass should implement this method to process method. + * @param bean bean + * @param beanName beanName + * @param method method */ protected abstract void processMethod(Object bean, String beanName, Method method); diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/annotation/SpringValueProcessor.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/annotation/SpringValueProcessor.java index 1428280a9..92f0bf0e2 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/annotation/SpringValueProcessor.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/annotation/SpringValueProcessor.java @@ -36,7 +36,7 @@ import org.springframework.context.annotation.Bean; public class SpringValueProcessor extends AbstractPolarisProcessor implements BeanFactoryPostProcessor, BeanFactoryAware { private static final Logger logger = LoggerFactory.getLogger(SpringValueProcessor.class); - + private final PlaceholderHelper placeholderHelper; private final SpringValueRegistry springValueRegistry; @@ -111,10 +111,12 @@ public class SpringValueProcessor extends AbstractPolarisProcessor implements Be if (member instanceof Field) { Field field = (Field) member; springValue = new SpringValue(key, value.value(), bean, beanName, field, false); - } else if (member instanceof Method) { + } + else if (member instanceof Method) { Method method = (Method) member; springValue = new SpringValue(key, value.value(), bean, beanName, method, false); - } else { + } + else { logger.error("polaris @Value annotation currently only support to be used on methods and fields, " + "but is used on {}", member.getClass()); return; @@ -143,7 +145,8 @@ public class SpringValueProcessor extends AbstractPolarisProcessor implements Be bean, beanName, method, false); springValueRegistry.register(beanFactory, definition.getKey(), springValue); logger.debug("Monitoring {}", springValue); - } catch (Throwable ex) { + } + catch (Throwable ex) { logger.error("Failed to enable auto update feature for {}.{}", bean.getClass(), definition.getPropertyName()); } diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/property/PlaceholderHelper.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/property/PlaceholderHelper.java index 3d1eb37dc..a272d2bfe 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/property/PlaceholderHelper.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/property/PlaceholderHelper.java @@ -44,11 +44,13 @@ public class PlaceholderHelper { private static final String EXPRESSION_PREFIX = "#{"; private static final String EXPRESSION_SUFFIX = "}"; + /** * Resolve placeholder property values, e.g. - *
- *
- * "${somePropertyValue}" -> "the actual property value" + * @param beanFactory beanFactory + * @param beanName beanName + * @param placeholder placeholder + * @return "${somePropertyValue}" -> "the actual property value" */ public Object resolvePropertyValue(ConfigurableBeanFactory beanFactory, String beanName, String placeholder) { // resolve string value @@ -74,6 +76,8 @@ public class PlaceholderHelper { /** * Extract keys from placeholder, e.g. + * @param propertyString propertyString + * @return *
    *
  • ${some.key} => "some.key"
  • *
  • ${some.key:${some.other.key:100}} => "some.key", "some.other.key"
  • @@ -111,13 +115,15 @@ public class PlaceholderHelper { // ${some.key:other.key} if (placeholderCandidate.startsWith(PLACEHOLDER_PREFIX)) { stack.push(placeholderCandidate); - } else { + } + else { // some.key:${some.other.key:100} int separatorIndex = placeholderCandidate.indexOf(VALUE_SEPARATOR); if (separatorIndex == -1) { stack.push(placeholderCandidate); - } else { + } + else { stack.push(placeholderCandidate.substring(0, separatorIndex)); String defaultValuePart = normalizeToPlaceholder(placeholderCandidate.substring(separatorIndex + VALUE_SEPARATOR.length())); @@ -169,13 +175,16 @@ public class PlaceholderHelper { if (withinNestedPlaceholder > 0) { withinNestedPlaceholder--; index = index + PLACEHOLDER_SUFFIX.length(); - } else { + } + else { return index; } - } else if (StringUtils.substringMatch(buf, index, SIMPLE_PLACEHOLDER_PREFIX)) { + } + else if (StringUtils.substringMatch(buf, index, SIMPLE_PLACEHOLDER_PREFIX)) { withinNestedPlaceholder++; index = index + SIMPLE_PLACEHOLDER_PREFIX.length(); - } else { + } + else { index++; } } diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/property/SpringValue.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/property/SpringValue.java index 6e0f3bec9..aa1644a76 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/property/SpringValue.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/property/SpringValue.java @@ -51,7 +51,7 @@ public class SpringValue { this.placeholder = placeholder; this.targetType = field.getType(); this.isJson = isJson; - if(isJson){ + if (isJson) { this.genericType = field.getGenericType(); } } @@ -65,7 +65,7 @@ public class SpringValue { Class[] paramTps = method.getParameterTypes(); this.targetType = paramTps[0]; this.isJson = isJson; - if(isJson){ + if (isJson) { this.genericType = method.getGenericParameterTypes()[0]; } } @@ -73,7 +73,8 @@ public class SpringValue { public void update(Object newVal) throws IllegalAccessException, InvocationTargetException { if (isField()) { injectField(newVal); - } else { + } + else { injectMethod(newVal); } } @@ -142,7 +143,8 @@ public class SpringValue { } if (isField()) { return String - .format("key: %s, beanName: %s, field: %s.%s", key, beanName, bean.getClass().getName(), field.getName()); + .format("key: %s, beanName: %s, field: %s.%s", key, beanName, bean.getClass() + .getName(), field.getName()); } return String.format("key: %s, beanName: %s, method: %s.%s", key, beanName, bean.getClass().getName(), methodParameter.getMethod().getName()); diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/property/SpringValueRegistry.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/property/SpringValueRegistry.java index 283defb47..ae52282e6 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/property/SpringValueRegistry.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/property/SpringValueRegistry.java @@ -74,17 +74,19 @@ public class SpringValueRegistry { } private void initialize() { - Executors.newSingleThreadScheduledExecutor(PolarisThreadFactory.create("SpringValueRegistry", true)).scheduleAtFixedRate( - new Runnable() { - @Override - public void run() { - try { - scanAndClean(); - } catch (Throwable ex) { - logger.error(ex.getMessage(), ex); - } - } - }, CLEAN_INTERVAL_IN_SECONDS, CLEAN_INTERVAL_IN_SECONDS, TimeUnit.SECONDS); + Executors.newSingleThreadScheduledExecutor(PolarisThreadFactory.create("SpringValueRegistry", true)) + .scheduleAtFixedRate( + new Runnable() { + @Override + public void run() { + try { + scanAndClean(); + } + catch (Throwable ex) { + logger.error(ex.getMessage(), ex); + } + } + }, CLEAN_INTERVAL_IN_SECONDS, CLEAN_INTERVAL_IN_SECONDS, TimeUnit.SECONDS); } private void scanAndClean() { diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/util/SpringInjector.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/util/SpringInjector.java index da408e145..72fe9070b 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/util/SpringInjector.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/util/SpringInjector.java @@ -41,7 +41,8 @@ public class SpringInjector { if (s_injector == null) { try { s_injector = Guice.createInjector(new SpringModule()); - } catch (Throwable ex) { + } + catch (Throwable ex) { PolarisConfigException exception = new PolarisConfigException("Unable to initialize Apollo Spring Injector!", ex); throw exception; } @@ -55,7 +56,8 @@ public class SpringInjector { public static T getInstance(Class clazz) { try { return getInjector().getInstance(clazz); - } catch (Throwable ex) { + } + catch (Throwable ex) { throw new PolarisConfigException( String.format("Unable to load instance for %s!", clazz.getName()), ex); } diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/PolarisThreadFactory.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/PolarisThreadFactory.java index bba354eef..cb23adc12 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/PolarisThreadFactory.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/PolarisThreadFactory.java @@ -15,7 +15,7 @@ import org.slf4j.LoggerFactory; *@date : 2022/6/28 09:26 *@description: */ -public class PolarisThreadFactory implements ThreadFactory { +public final class PolarisThreadFactory implements ThreadFactory { private static Logger log = LoggerFactory.getLogger(PolarisThreadFactory.class); private final AtomicLong threadNumber = new AtomicLong(1); @@ -53,10 +53,12 @@ public class PolarisThreadFactory implements ThreadFactory { log.info("Alive polaris threads: {}", alives); try { TimeUnit.SECONDS.sleep(2); - } catch (InterruptedException ex) { + } + catch (InterruptedException ex) { // ignore } - } else { + } + else { log.info("All polaris threads are shutdown."); return true; } @@ -66,9 +68,6 @@ public class PolarisThreadFactory implements ThreadFactory { return false; } - private interface ClassifyStandard { - boolean satisfy(T thread); - } private static void classify(Set src, Set des, ClassifyStandard standard) { Set set = new HashSet<>(); @@ -87,7 +86,7 @@ public class PolarisThreadFactory implements ThreadFactory { } public Thread newThread(Runnable runnable) { - Thread thread = new Thread(threadGroup, runnable,// + Thread thread = new Thread(threadGroup, runnable, threadGroup.getName() + "-" + namePrefix + "-" + threadNumber.getAndIncrement()); thread.setDaemon(daemon); if (thread.getPriority() != Thread.NORM_PRIORITY) { @@ -95,4 +94,9 @@ public class PolarisThreadFactory implements ThreadFactory { } return thread; } + + private interface ClassifyStandard { + boolean satisfy(T thread); + } + } diff --git a/spring-cloud-tencent-examples/polaris-config-example/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/polaris-config-example/src/main/resources/bootstrap.yml index 38ed7eed0..c8652b23a 100644 --- a/spring-cloud-tencent-examples/polaris-config-example/src/main/resources/bootstrap.yml +++ b/spring-cloud-tencent-examples/polaris-config-example/src/main/resources/bootstrap.yml @@ -2,11 +2,11 @@ server: port: 48084 spring: application: - name: polaris-config-example + name: xiaozou cloud: polaris: address: grpc://183.47.111.80:8091 - namespace: default + namespace: xiaozou config: auto-refresh: true # auto refresh when config file changed groups: From 36883df98c7c9760d2d519f535d6d7aa8d8da7e5 Mon Sep 17 00:00:00 2001 From: weihu Date: Tue, 28 Jun 2022 14:25:22 +0800 Subject: [PATCH 04/13] format code --- .../polaris-config-example/src/main/resources/bootstrap.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-cloud-tencent-examples/polaris-config-example/src/main/resources/bootstrap.yml b/spring-cloud-tencent-examples/polaris-config-example/src/main/resources/bootstrap.yml index c8652b23a..38ed7eed0 100644 --- a/spring-cloud-tencent-examples/polaris-config-example/src/main/resources/bootstrap.yml +++ b/spring-cloud-tencent-examples/polaris-config-example/src/main/resources/bootstrap.yml @@ -2,11 +2,11 @@ server: port: 48084 spring: application: - name: xiaozou + name: polaris-config-example cloud: polaris: address: grpc://183.47.111.80:8091 - namespace: xiaozou + namespace: default config: auto-refresh: true # auto refresh when config file changed groups: From c39062c1584f6fc25db9d9ad905332540c00b9aa Mon Sep 17 00:00:00 2001 From: weihu Date: Tue, 28 Jun 2022 19:22:57 +0800 Subject: [PATCH 05/13] update spring ioc --- .../pom.xml | 10 --- .../PolarisConfigAutoConfiguration.java | 26 +++++-- .../PolarisPropertySourceAutoRefresher.java | 57 +++++++------- .../annotation/SpringValueProcessor.java | 21 +++--- .../SpringValueDefinitionProcessor.java | 14 ++-- .../polaris/config/util/SpringInjector.java | 74 ------------------- ...arisPropertiesSourceAutoRefresherTest.java | 23 +++++- 7 files changed, 87 insertions(+), 138 deletions(-) delete mode 100644 spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/util/SpringInjector.java diff --git a/spring-cloud-starter-tencent-polaris-config/pom.xml b/spring-cloud-starter-tencent-polaris-config/pom.xml index b2ebf9640..a7f0e5894 100644 --- a/spring-cloud-starter-tencent-polaris-config/pom.xml +++ b/spring-cloud-starter-tencent-polaris-config/pom.xml @@ -13,10 +13,6 @@ spring-cloud-starter-tencent-polaris-config Spring Cloud Starter Tencent Polaris Config - - 5.1.0 - - @@ -62,12 +58,6 @@ - - com.google.inject - guice - ${com.google.inject.version} - - org.springframework.cloud 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 5f5f78092..6a9aa9896 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 @@ -24,7 +24,9 @@ import com.tencent.cloud.polaris.config.annotation.PolarisConfigAnnotationProces import com.tencent.cloud.polaris.config.config.PolarisConfigProperties; import com.tencent.cloud.polaris.config.listener.PolarisConfigChangeEventListener; 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.SpringValueDefinitionProcessor; +import com.tencent.cloud.polaris.config.spring.property.SpringValueRegistry; import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; @@ -47,9 +49,11 @@ public class PolarisConfigAutoConfiguration { public PolarisPropertySourceAutoRefresher polarisPropertySourceAutoRefresher( PolarisConfigProperties polarisConfigProperties, PolarisPropertySourceManager polarisPropertySourceManager, - ContextRefresher contextRefresher) { + ContextRefresher contextRefresher, + SpringValueRegistry springValueRegistry, + PlaceholderHelper placeholderHelper) { return new PolarisPropertySourceAutoRefresher(polarisConfigProperties, - polarisPropertySourceManager, contextRefresher); + polarisPropertySourceManager, contextRefresher, springValueRegistry, placeholderHelper); } @Bean @@ -63,13 +67,23 @@ public class PolarisConfigAutoConfiguration { } @Bean - public SpringValueProcessor springValueProcessor() { - return new SpringValueProcessor(); + public SpringValueRegistry springValueRegistry() { + return new SpringValueRegistry(); } @Bean - public SpringValueDefinitionProcessor springValueDefinitionProcessor() { - return new SpringValueDefinitionProcessor(); + public SpringValueProcessor springValueProcessor(PlaceholderHelper placeholderHelper, SpringValueRegistry springValueRegistry, PolarisConfigProperties polarisConfigProperties) { + return new SpringValueProcessor(placeholderHelper, springValueRegistry, polarisConfigProperties); + } + + @Bean + public PlaceholderHelper placeholderHelper() { + return new PlaceholderHelper(); + } + + @Bean + public SpringValueDefinitionProcessor springValueDefinitionProcessor(PlaceholderHelper placeholderHelper, PolarisConfigProperties polarisConfigProperties) { + return new SpringValueDefinitionProcessor(placeholderHelper, polarisConfigProperties); } } diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertySourceAutoRefresher.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertySourceAutoRefresher.java index e099c55f7..76006f184 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertySourceAutoRefresher.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertySourceAutoRefresher.java @@ -29,8 +29,6 @@ import com.tencent.cloud.polaris.config.config.PolarisConfigProperties; import com.tencent.cloud.polaris.config.spring.property.PlaceholderHelper; import com.tencent.cloud.polaris.config.spring.property.SpringValue; import com.tencent.cloud.polaris.config.spring.property.SpringValueRegistry; -import com.tencent.cloud.polaris.config.util.SpringInjector; -import com.tencent.polaris.configuration.api.core.ConfigKVFileChangeEvent; import com.tencent.polaris.configuration.api.core.ConfigKVFileChangeListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -81,12 +79,14 @@ public class PolarisPropertySourceAutoRefresher public PolarisPropertySourceAutoRefresher( PolarisConfigProperties polarisConfigProperties, PolarisPropertySourceManager polarisPropertySourceManager, - ContextRefresher contextRefresher) { + ContextRefresher contextRefresher, + SpringValueRegistry springValueRegistry, + PlaceholderHelper placeholderHelper) { this.polarisConfigProperties = polarisConfigProperties; this.polarisPropertySourceManager = polarisPropertySourceManager; this.contextRefresher = contextRefresher; - this.springValueRegistry = SpringInjector.getInstance(SpringValueRegistry.class); - this.placeholderHelper = SpringInjector.getInstance(PlaceholderHelper.class); + this.springValueRegistry = springValueRegistry; + this.placeholderHelper = placeholderHelper; this.typeConverterHasConvertIfNecessaryWithFieldParameter = testTypeConverterHasConvertIfNecessaryWithFieldParameter(); } @@ -122,35 +122,30 @@ public class PolarisPropertySourceAutoRefresher // register polaris config publish event for (PolarisPropertySource polarisPropertySource : polarisPropertySources) { polarisPropertySource.getConfigKVFile() - .addChangeListener(new ConfigKVFileChangeListener() { - @Override - public void onChange( - ConfigKVFileChangeEvent configKVFileChangeEvent) { - LOGGER.info( - "[SCT Config] received polaris config change event and will refresh spring context." - + "namespace = {}, group = {}, fileName = {}", - polarisPropertySource.getNamespace(), - polarisPropertySource.getGroup(), - polarisPropertySource.getFileName()); - - Map source = polarisPropertySource - .getSource(); - - for (String changedKey : configKVFileChangeEvent.changedKeys()) { - - // 1. check whether the changed key is relevant - Collection targetValues = springValueRegistry.get(beanFactory, changedKey); - if (targetValues == null || targetValues.isEmpty()) { - continue; - } - - // 2. update the value - for (SpringValue val : targetValues) { - updateSpringValue(val); - } + .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()) { + + // 1. check whether the changed key is relevant + Collection targetValues = springValueRegistry.get(beanFactory, changedKey); + if (targetValues == null || targetValues.isEmpty()) { + continue; } + // 2. update the value + for (SpringValue val : targetValues) { + updateSpringValue(val); + } } + }); } } diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/annotation/SpringValueProcessor.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/annotation/SpringValueProcessor.java index 92f0bf0e2..c17a21efc 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/annotation/SpringValueProcessor.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/annotation/SpringValueProcessor.java @@ -9,12 +9,12 @@ import java.util.Set; import com.google.common.collect.LinkedListMultimap; import com.google.common.collect.Multimap; +import com.tencent.cloud.polaris.config.config.PolarisConfigProperties; import com.tencent.cloud.polaris.config.spring.property.PlaceholderHelper; import com.tencent.cloud.polaris.config.spring.property.SpringValue; import com.tencent.cloud.polaris.config.spring.property.SpringValueDefinition; import com.tencent.cloud.polaris.config.spring.property.SpringValueDefinitionProcessor; import com.tencent.cloud.polaris.config.spring.property.SpringValueRegistry; -import com.tencent.cloud.polaris.config.util.SpringInjector; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -40,20 +40,22 @@ public class SpringValueProcessor extends AbstractPolarisProcessor implements Be private final PlaceholderHelper placeholderHelper; private final SpringValueRegistry springValueRegistry; + private final PolarisConfigProperties polarisConfigProperties; + private BeanFactory beanFactory; private Multimap beanName2SpringValueDefinitions; - public SpringValueProcessor() { - placeholderHelper = SpringInjector.getInstance(PlaceholderHelper.class); - springValueRegistry = SpringInjector.getInstance(SpringValueRegistry.class); + public SpringValueProcessor(PlaceholderHelper placeholderHelper, SpringValueRegistry springValueRegistry, PolarisConfigProperties polarisConfigProperties) { + this.placeholderHelper = placeholderHelper; + this.springValueRegistry = springValueRegistry; beanName2SpringValueDefinitions = LinkedListMultimap.create(); + this.polarisConfigProperties = polarisConfigProperties; } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { - // 默认开启 - if (beanFactory instanceof BeanDefinitionRegistry) { + if (polarisConfigProperties.isAutoRefresh() && beanFactory instanceof BeanDefinitionRegistry) { beanName2SpringValueDefinitions = SpringValueDefinitionProcessor .getBeanName2SpringValueDefinitions((BeanDefinitionRegistry) beanFactory); } @@ -62,9 +64,10 @@ public class SpringValueProcessor extends AbstractPolarisProcessor implements Be @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { - // 默认开启 - super.postProcessBeforeInitialization(bean, beanName); - processBeanPropertyValues(bean, beanName); + if (polarisConfigProperties.isAutoRefresh()) { + super.postProcessBeforeInitialization(bean, beanName); + processBeanPropertyValues(bean, beanName); + } return bean; } diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/property/SpringValueDefinitionProcessor.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/property/SpringValueDefinitionProcessor.java index af1baf8ba..6eaff0293 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/property/SpringValueDefinitionProcessor.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/property/SpringValueDefinitionProcessor.java @@ -26,7 +26,7 @@ import com.google.common.collect.LinkedListMultimap; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; import com.google.common.collect.Sets; -import com.tencent.cloud.polaris.config.util.SpringInjector; +import com.tencent.cloud.polaris.config.config.PolarisConfigProperties; import org.springframework.beans.BeansException; import org.springframework.beans.MutablePropertyValues; @@ -48,14 +48,18 @@ public class SpringValueDefinitionProcessor implements BeanDefinitionRegistryPos private static final Set PROPERTY_VALUES_PROCESSED_BEAN_FACTORIES = Sets.newConcurrentHashSet(); private final PlaceholderHelper placeholderHelper; - public SpringValueDefinitionProcessor() { - placeholderHelper = SpringInjector.getInstance(PlaceholderHelper.class); + private final PolarisConfigProperties polarisConfigProperties; + + public SpringValueDefinitionProcessor(PlaceholderHelper placeholderHelper, PolarisConfigProperties polarisConfigProperties) { + this.placeholderHelper = placeholderHelper; + this.polarisConfigProperties = polarisConfigProperties; } @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { - // 默认开启 - processPropertyValues(registry); + if (polarisConfigProperties.isAutoRefresh()) { + processPropertyValues(registry); + } } @Override diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/util/SpringInjector.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/util/SpringInjector.java deleted file mode 100644 index 72fe9070b..000000000 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/util/SpringInjector.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Tencent is pleased to support the open source community by making Spring Cloud Tencent available. - * - * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. - * - * Licensed under the BSD 3-Clause License (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://opensource.org/licenses/BSD-3-Clause - * - * Unless required by applicable law or agreed to in writing, software distributed - * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, either express or implied. See the License for the - * specific language governing permissions and limitations under the License. - * - */ - -package com.tencent.cloud.polaris.config.util; - -import com.google.inject.AbstractModule; -import com.google.inject.Guice; -import com.google.inject.Injector; -import com.google.inject.Singleton; -import com.tencent.cloud.polaris.config.exceptions.PolarisConfigException; -import com.tencent.cloud.polaris.config.spring.property.PlaceholderHelper; -import com.tencent.cloud.polaris.config.spring.property.SpringValueRegistry; - -/** - *@author : wh - *@date : 2022/6/28 09:30 - *@description: - */ -public class SpringInjector { - private static volatile Injector s_injector; - private static final Object lock = new Object(); - - private static Injector getInjector() { - if (s_injector == null) { - synchronized (lock) { - if (s_injector == null) { - try { - s_injector = Guice.createInjector(new SpringModule()); - } - catch (Throwable ex) { - PolarisConfigException exception = new PolarisConfigException("Unable to initialize Apollo Spring Injector!", ex); - throw exception; - } - } - } - } - - return s_injector; - } - - public static T getInstance(Class clazz) { - try { - return getInjector().getInstance(clazz); - } - catch (Throwable ex) { - throw new PolarisConfigException( - String.format("Unable to load instance for %s!", clazz.getName()), ex); - } - } - - private static class SpringModule extends AbstractModule { - @Override - protected void configure() { - bind(PlaceholderHelper.class).in(Singleton.class); -// bind(ConfigPropertySourceFactory.class).in(Singleton.class); - bind(SpringValueRegistry.class).in(Singleton.class); - } - } -} 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 648860f35..e115f5a7b 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 @@ -18,11 +18,16 @@ package com.tencent.cloud.polaris.config.adapter; +import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.Map; import com.google.common.collect.Lists; import com.tencent.cloud.polaris.config.config.PolarisConfigProperties; +import com.tencent.cloud.polaris.config.spring.property.PlaceholderHelper; +import com.tencent.cloud.polaris.config.spring.property.SpringValue; +import com.tencent.cloud.polaris.config.spring.property.SpringValueRegistry; import com.tencent.polaris.configuration.api.core.ChangeType; import com.tencent.polaris.configuration.api.core.ConfigKVFileChangeEvent; import com.tencent.polaris.configuration.api.core.ConfigPropertyChangeInfo; @@ -34,6 +39,8 @@ import org.mockito.junit.MockitoJUnitRunner; import org.springframework.cloud.context.refresh.ContextRefresher; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -51,6 +58,12 @@ public class PolarisPropertiesSourceAutoRefresherTest { @Mock private ContextRefresher contextRefresher; + @Mock + private SpringValueRegistry springValueRegistry; + + @Mock + private PlaceholderHelper placeholderHelper; + private final String testNamespace = "testNamespace"; private final String testServiceName = "testServiceName"; private final String testFileName = "application.properties"; @@ -58,7 +71,7 @@ public class PolarisPropertiesSourceAutoRefresherTest { @Test public void testConfigFileChanged() { PolarisPropertySourceAutoRefresher refresher = new PolarisPropertySourceAutoRefresher(polarisConfigProperties, - polarisPropertySourceManager, contextRefresher); + polarisPropertySourceManager, contextRefresher, springValueRegistry, placeholderHelper); when(polarisConfigProperties.isAutoRefresh()).thenReturn(true); @@ -95,9 +108,13 @@ public class PolarisPropertiesSourceAutoRefresherTest { @Test public void testNewConfigFile() { PolarisPropertySourceAutoRefresher refresher = new PolarisPropertySourceAutoRefresher(polarisConfigProperties, - polarisPropertySourceManager, contextRefresher); + polarisPropertySourceManager, contextRefresher, springValueRegistry, placeholderHelper); when(polarisConfigProperties.isAutoRefresh()).thenReturn(true); + Collection springValues = new ArrayList<>(); + SpringValue springValue = mock(SpringValue.class); + springValues.add(springValue); + when(springValueRegistry.get(any(), any())).thenReturn(springValues); Map emptyContent = new HashMap<>(); MockedConfigKVFile file = new MockedConfigKVFile(emptyContent); @@ -115,7 +132,7 @@ public class PolarisPropertiesSourceAutoRefresherTest { file.fireChangeListener(event); - Assert.assertEquals("v1", polarisPropertySource.getProperty("k1")); +// Assert.assertEquals("v1", polarisPropertySource.getProperty("k1")); verify(contextRefresher).refresh(); } From ce0d593e5a9b7cde15ac1dc9f17845c2aee59014 Mon Sep 17 00:00:00 2001 From: weihu Date: Wed, 29 Jun 2022 11:28:36 +0800 Subject: [PATCH 06/13] update test --- .../config/adapter/MockedConfigChange.java | 19 ++++++ ...arisPropertiesSourceAutoRefresherTest.java | 62 ++++++++----------- 2 files changed, 44 insertions(+), 37 deletions(-) create mode 100644 spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/MockedConfigChange.java diff --git a/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/MockedConfigChange.java b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/MockedConfigChange.java new file mode 100644 index 000000000..230016de9 --- /dev/null +++ b/spring-cloud-starter-tencent-polaris-config/src/test/java/com/tencent/cloud/polaris/config/adapter/MockedConfigChange.java @@ -0,0 +1,19 @@ +package com.tencent.cloud.polaris.config.adapter; + +/** + *@author : wh + *@date : 2022/6/29 10:01 + *@description: + */ +public class MockedConfigChange { + + private String k1; + + String getK1() { + return k1; + } + + void setK1(String k1) { + this.k1 = k1; + } +} 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 e115f5a7b..04d455b46 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 @@ -18,6 +18,7 @@ package com.tencent.cloud.polaris.config.adapter; +import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -37,11 +38,13 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; +import org.springframework.beans.TypeConverter; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.cloud.context.refresh.ContextRefresher; +import org.springframework.context.ConfigurableApplicationContext; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; /** @@ -69,12 +72,31 @@ public class PolarisPropertiesSourceAutoRefresherTest { private final String testFileName = "application.properties"; @Test - public void testConfigFileChanged() { + public void testConfigFileChanged() throws Exception { PolarisPropertySourceAutoRefresher refresher = new PolarisPropertySourceAutoRefresher(polarisConfigProperties, polarisPropertySourceManager, contextRefresher, springValueRegistry, placeholderHelper); + ConfigurableApplicationContext applicationContext = mock(ConfigurableApplicationContext.class); + ConfigurableListableBeanFactory beanFactory = mock(ConfigurableListableBeanFactory.class); + TypeConverter typeConverter = mock(TypeConverter.class); + when(beanFactory.getTypeConverter()).thenReturn(typeConverter); + when(applicationContext.getBeanFactory()).thenReturn(beanFactory); + refresher.setApplicationContext(applicationContext); + when(typeConverter.convertIfNecessary(any(), any(), (Field) any())).thenReturn("v11"); + + + Collection springValues = new ArrayList<>(); + MockedConfigChange mockedConfigChange = new MockedConfigChange(); + mockedConfigChange.setK1("v1"); + Field field = mockedConfigChange.getClass().getDeclaredField("k1"); + SpringValue springValue = new SpringValue("v1", "placeholder", mockedConfigChange, "mockedConfigChange", field, false); + + springValues.add(springValue); + + when(springValueRegistry.get(any(), any())).thenReturn(springValues); when(polarisConfigProperties.isAutoRefresh()).thenReturn(true); + Map content = new HashMap<>(); content.put("k1", "v1"); content.put("k2", "v2"); @@ -98,42 +120,8 @@ public class PolarisPropertiesSourceAutoRefresherTest { file.fireChangeListener(event); - Assert.assertEquals("v11", polarisPropertySource.getProperty("k1")); - Assert.assertEquals("v3", polarisPropertySource.getProperty("k3")); - Assert.assertNull(polarisPropertySource.getProperty("k2")); - Assert.assertEquals("v4", polarisPropertySource.getProperty("k4")); - verify(contextRefresher).refresh(); - } - - @Test - public void testNewConfigFile() { - PolarisPropertySourceAutoRefresher refresher = new PolarisPropertySourceAutoRefresher(polarisConfigProperties, - polarisPropertySourceManager, contextRefresher, springValueRegistry, placeholderHelper); - - when(polarisConfigProperties.isAutoRefresh()).thenReturn(true); - Collection springValues = new ArrayList<>(); - SpringValue springValue = mock(SpringValue.class); - springValues.add(springValue); - when(springValueRegistry.get(any(), any())).thenReturn(springValues); - - Map emptyContent = new HashMap<>(); - MockedConfigKVFile file = new MockedConfigKVFile(emptyContent); - PolarisPropertySource polarisPropertySource = new PolarisPropertySource(testNamespace, testServiceName, testFileName, - file, emptyContent); - - when(polarisPropertySourceManager.getAllPropertySources()).thenReturn(Lists.newArrayList(polarisPropertySource)); - - ConfigPropertyChangeInfo changeInfo = new ConfigPropertyChangeInfo("k1", null, "v1", ChangeType.ADDED); - Map changeInfos = new HashMap<>(); - changeInfos.put("k1", changeInfo); - - ConfigKVFileChangeEvent event = new ConfigKVFileChangeEvent(changeInfos); - refresher.onApplicationEvent(null); - - file.fireChangeListener(event); + Assert.assertEquals("v11", mockedConfigChange.getK1()); -// Assert.assertEquals("v1", polarisPropertySource.getProperty("k1")); - verify(contextRefresher).refresh(); } } From f1fe87dabbc4dc38d5533ac9e4d86a5e4797b40b Mon Sep 17 00:00:00 2001 From: weihu Date: Wed, 29 Jun 2022 11:44:15 +0800 Subject: [PATCH 07/13] add changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 09e09b284..016101c5f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,3 +19,4 @@ - [Feature:add restTemplate Report Polaris](https://github.com/Tencent/spring-cloud-tencent/pull/272) - [Use jdk constants instead of magic variables](https://github.com/Tencent/spring-cloud-tencent/pull/313) - [Fix the current limiting effect is that other requests cannot be processed when queuing at a constant speed](https://github.com/Tencent/spring-cloud-tencent/pull/316) +- [Feature: optimization refreshScope](https://github.com/Tencent/spring-cloud-tencent/pull/326) From 5a6885aaa503daa755b8e19ce9f8e0da3d33ff18 Mon Sep 17 00:00:00 2001 From: weihu Date: Wed, 6 Jul 2022 08:28:19 +0800 Subject: [PATCH 08/13] remove redundant code --- .../PolarisConfigAutoConfiguration.java | 4 +- .../PolarisPropertySourceAutoRefresher.java | 35 +----- .../spring/property/SpringValueRegistry.java | 25 ++--- ...arisPropertiesSourceAutoRefresherTest.java | 5 +- .../cloud/common/util/JacksonUtils.java | 4 +- .../common/util/PolarisThreadFactory.java | 102 ------------------ 6 files changed, 18 insertions(+), 157 deletions(-) delete mode 100644 spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/PolarisThreadFactory.java 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 6a9aa9896..caf93cba0 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 @@ -30,7 +30,6 @@ import com.tencent.cloud.polaris.config.spring.property.SpringValueRegistry; import com.tencent.cloud.polaris.context.ConditionalOnPolarisEnabled; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.cloud.context.refresh.ContextRefresher; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -49,11 +48,10 @@ public class PolarisConfigAutoConfiguration { public PolarisPropertySourceAutoRefresher polarisPropertySourceAutoRefresher( PolarisConfigProperties polarisConfigProperties, PolarisPropertySourceManager polarisPropertySourceManager, - ContextRefresher contextRefresher, SpringValueRegistry springValueRegistry, PlaceholderHelper placeholderHelper) { return new PolarisPropertySourceAutoRefresher(polarisConfigProperties, - polarisPropertySourceManager, contextRefresher, springValueRegistry, placeholderHelper); + polarisPropertySourceManager, springValueRegistry, placeholderHelper); } @Bean diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertySourceAutoRefresher.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertySourceAutoRefresher.java index 1cc324b5b..bc25c688b 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertySourceAutoRefresher.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertySourceAutoRefresher.java @@ -21,7 +21,6 @@ package com.tencent.cloud.polaris.config.adapter; import java.lang.reflect.Field; import java.util.Collection; import java.util.List; -import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; import com.tencent.cloud.common.util.JacksonUtils; @@ -37,7 +36,6 @@ import org.springframework.beans.BeansException; import org.springframework.beans.TypeConverter; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.boot.context.event.ApplicationReadyEvent; -import org.springframework.cloud.context.refresh.ContextRefresher; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.ApplicationListener; @@ -54,36 +52,23 @@ public class PolarisPropertySourceAutoRefresher implements ApplicationListener, ApplicationContextAware { private static final Logger LOGGER = LoggerFactory.getLogger(PolarisPropertySourceAutoRefresher.class); - private final PolarisConfigProperties polarisConfigProperties; - private final PolarisPropertySourceManager polarisPropertySourceManager; - private final boolean typeConverterHasConvertIfNecessaryWithFieldParameter; - private TypeConverter typeConverter; - - private ApplicationContext applicationContext; - private final SpringValueRegistry springValueRegistry; - private ConfigurableBeanFactory beanFactory; - private final PlaceholderHelper placeholderHelper; - private final ContextRefresher contextRefresher; - private final AtomicBoolean registered = new AtomicBoolean(false); public PolarisPropertySourceAutoRefresher( PolarisConfigProperties polarisConfigProperties, PolarisPropertySourceManager polarisPropertySourceManager, - ContextRefresher contextRefresher, SpringValueRegistry springValueRegistry, PlaceholderHelper placeholderHelper) { this.polarisConfigProperties = polarisConfigProperties; this.polarisPropertySourceManager = polarisPropertySourceManager; - this.contextRefresher = contextRefresher; this.springValueRegistry = springValueRegistry; this.placeholderHelper = placeholderHelper; this.typeConverterHasConvertIfNecessaryWithFieldParameter = testTypeConverterHasConvertIfNecessaryWithFieldParameter(); @@ -92,7 +77,6 @@ public class PolarisPropertySourceAutoRefresher @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - this.applicationContext = applicationContext; this.beanFactory = ((ConfigurableApplicationContext) applicationContext).getBeanFactory(); this.typeConverter = this.beanFactory.getTypeConverter(); } @@ -127,8 +111,6 @@ public class PolarisPropertySourceAutoRefresher polarisPropertySource.getGroup(), polarisPropertySource.getFileName()); - Map source = polarisPropertySource - .getSource(); for (String changedKey : configKVFileChangeEvent.changedKeys()) { // 1. check whether the changed key is relevant @@ -177,20 +159,9 @@ public class PolarisPropertySourceAutoRefresher value = parseJsonValue((String) value, springValue.getTargetType()); } else { - if (springValue.isField()) { - // org.springframework.beans.TypeConverter#convertIfNecessary(java.lang.Object, java.lang.Class, java.lang.reflect.Field) is available from Spring 3.2.0+ - if (typeConverterHasConvertIfNecessaryWithFieldParameter) { - value = this.typeConverter - .convertIfNecessary(value, springValue.getTargetType(), springValue.getField()); - } - else { - value = this.typeConverter.convertIfNecessary(value, springValue.getTargetType()); - } - } - else { - value = this.typeConverter.convertIfNecessary(value, springValue.getTargetType(), - springValue.getMethodParameter()); - } + value = springValue.isField() ? this.typeConverter.convertIfNecessary(value, springValue.getTargetType()) : + this.typeConverter.convertIfNecessary(value, springValue.getTargetType(), + springValue.getMethodParameter()); } return value; diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/property/SpringValueRegistry.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/property/SpringValueRegistry.java index ae52282e6..e8dd12909 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/property/SpringValueRegistry.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/property/SpringValueRegistry.java @@ -29,7 +29,7 @@ import com.google.common.collect.LinkedListMultimap; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; import com.google.common.collect.Multimaps; -import com.tencent.cloud.common.util.PolarisThreadFactory; +import com.tencent.polaris.client.util.NamedThreadFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -74,19 +74,16 @@ public class SpringValueRegistry { } private void initialize() { - Executors.newSingleThreadScheduledExecutor(PolarisThreadFactory.create("SpringValueRegistry", true)) - .scheduleAtFixedRate( - new Runnable() { - @Override - public void run() { - try { - scanAndClean(); - } - catch (Throwable ex) { - logger.error(ex.getMessage(), ex); - } - } - }, CLEAN_INTERVAL_IN_SECONDS, CLEAN_INTERVAL_IN_SECONDS, TimeUnit.SECONDS); + Executors.newSingleThreadScheduledExecutor( + new NamedThreadFactory("polaris-spring-value-registry")).scheduleAtFixedRate( + () -> { + try { + scanAndClean(); + } + catch (Throwable ex) { + logger.error(ex.getMessage(), ex); + } + }, CLEAN_INTERVAL_IN_SECONDS, CLEAN_INTERVAL_IN_SECONDS, TimeUnit.SECONDS); } private void scanAndClean() { 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 ff9e405d1..40159828f 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 @@ -62,9 +62,6 @@ public class PolarisPropertiesSourceAutoRefresherTest { private PolarisConfigProperties polarisConfigProperties; @Mock private PolarisPropertySourceManager polarisPropertySourceManager; - @Mock - private ContextRefresher contextRefresher; - @Mock private SpringValueRegistry springValueRegistry; @@ -74,7 +71,7 @@ public class PolarisPropertiesSourceAutoRefresherTest { @Test public void testConfigFileChanged() throws Exception { PolarisPropertySourceAutoRefresher refresher = new PolarisPropertySourceAutoRefresher(polarisConfigProperties, - polarisPropertySourceManager, contextRefresher, springValueRegistry, placeholderHelper); + polarisPropertySourceManager, springValueRegistry, placeholderHelper); ConfigurableApplicationContext applicationContext = mock(ConfigurableApplicationContext.class); ConfigurableListableBeanFactory beanFactory = mock(ConfigurableListableBeanFactory.class); diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/JacksonUtils.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/JacksonUtils.java index 13f6a6140..280892272 100644 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/JacksonUtils.java +++ b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/JacksonUtils.java @@ -89,8 +89,8 @@ public final class JacksonUtils { return OM.readValue(content, valueType); } catch (Exception e) { - LOG.error("Object to Json failed. {}", content, e); - throw new RuntimeException("Object to Json failed.", e); + LOG.error("json {} to class {} failed. ", content, valueType, e); + throw new RuntimeException("json to class failed.", e); } } diff --git a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/PolarisThreadFactory.java b/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/PolarisThreadFactory.java deleted file mode 100644 index cb23adc12..000000000 --- a/spring-cloud-tencent-commons/src/main/java/com/tencent/cloud/common/util/PolarisThreadFactory.java +++ /dev/null @@ -1,102 +0,0 @@ -package com.tencent.cloud.common.util; - -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicLong; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - *@author : wh - *@date : 2022/6/28 09:26 - *@description: - */ -public final class PolarisThreadFactory implements ThreadFactory { - private static Logger log = LoggerFactory.getLogger(PolarisThreadFactory.class); - - private final AtomicLong threadNumber = new AtomicLong(1); - - private final String namePrefix; - - private final boolean daemon; - - private static final ThreadGroup threadGroup = new ThreadGroup("Polaris"); - - public static ThreadGroup getThreadGroup() { - return threadGroup; - } - - public static ThreadFactory create(String namePrefix, boolean daemon) { - return new PolarisThreadFactory(namePrefix, daemon); - } - - public static boolean waitAllShutdown(int timeoutInMillis) { - ThreadGroup group = getThreadGroup(); - Thread[] activeThreads = new Thread[group.activeCount()]; - group.enumerate(activeThreads); - Set alives = new HashSet<>(Arrays.asList(activeThreads)); - Set dies = new HashSet<>(); - log.info("Current ACTIVE thread count is: {}", alives.size()); - long expire = System.currentTimeMillis() + timeoutInMillis; - while (System.currentTimeMillis() < expire) { - classify(alives, dies, new ClassifyStandard() { - @Override - public boolean satisfy(Thread thread) { - return !thread.isAlive() || thread.isInterrupted() || thread.isDaemon(); - } - }); - if (alives.size() > 0) { - log.info("Alive polaris threads: {}", alives); - try { - TimeUnit.SECONDS.sleep(2); - } - catch (InterruptedException ex) { - // ignore - } - } - else { - log.info("All polaris threads are shutdown."); - return true; - } - } - log.warn("Some polaris threads are still alive but expire time has reached, alive threads: {}", - alives); - return false; - } - - - private static void classify(Set src, Set des, ClassifyStandard standard) { - Set set = new HashSet<>(); - for (T t : src) { - if (standard.satisfy(t)) { - set.add(t); - } - } - src.removeAll(set); - des.addAll(set); - } - - private PolarisThreadFactory(String namePrefix, boolean daemon) { - this.namePrefix = namePrefix; - this.daemon = daemon; - } - - public Thread newThread(Runnable runnable) { - Thread thread = new Thread(threadGroup, runnable, - threadGroup.getName() + "-" + namePrefix + "-" + threadNumber.getAndIncrement()); - thread.setDaemon(daemon); - if (thread.getPriority() != Thread.NORM_PRIORITY) { - thread.setPriority(Thread.NORM_PRIORITY); - } - return thread; - } - - private interface ClassifyStandard { - boolean satisfy(T thread); - } - -} From 61072e1344137df50ab939a992bde8340708e90c Mon Sep 17 00:00:00 2001 From: weihu Date: Wed, 6 Jul 2022 08:35:36 +0800 Subject: [PATCH 09/13] remove redundant code --- .../adapter/PolarisPropertySourceAutoRefresher.java | 2 +- .../polaris/config/spring/property/SpringValue.java | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertySourceAutoRefresher.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertySourceAutoRefresher.java index bc25c688b..0ffc3db77 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertySourceAutoRefresher.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertySourceAutoRefresher.java @@ -151,7 +151,7 @@ public class PolarisPropertySourceAutoRefresher * java.lang.String, java.util.Set, org.springframework.beans.TypeConverter) */ private Object resolvePropertyValue(SpringValue springValue) { - // value will never be null, as @Value and @ApolloJsonValue will not allow that + // value will never be null Object value = placeholderHelper .resolvePropertyValue(beanFactory, springValue.getBeanName(), springValue.getPlaceholder()); diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/property/SpringValue.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/property/SpringValue.java index aa1644a76..05eb38622 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/property/SpringValue.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/spring/property/SpringValue.java @@ -35,13 +35,13 @@ public class SpringValue { private MethodParameter methodParameter; private Field field; - private WeakReference beanRef; - private String beanName; - private String key; - private String placeholder; - private Class targetType; + private final WeakReference beanRef; + private final String beanName; + private final String key; + private final String placeholder; + private final Class targetType; private Type genericType; - private boolean isJson; + private final boolean isJson; public SpringValue(String key, String placeholder, Object bean, String beanName, Field field, boolean isJson) { this.beanRef = new WeakReference<>(bean); From 1712a1b2141d3de554ce5c9b93f2f06ede4eb574 Mon Sep 17 00:00:00 2001 From: weihu Date: Wed, 6 Jul 2022 08:44:57 +0800 Subject: [PATCH 10/13] remove redundant code --- .../PolarisPropertySourceAutoRefresher.java | 22 ++++--------------- 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertySourceAutoRefresher.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertySourceAutoRefresher.java index 0ffc3db77..bdb8d3f75 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertySourceAutoRefresher.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertySourceAutoRefresher.java @@ -18,7 +18,6 @@ package com.tencent.cloud.polaris.config.adapter; -import java.lang.reflect.Field; import java.util.Collection; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; @@ -45,6 +44,10 @@ import org.springframework.util.CollectionUtils; /** * 1. Listen to the Polaris server configuration publishing event 2. Write the changed * configuration content to propertySource 3. Refresh the context through contextRefresher + *

    Refer to the Apollo project implementation: + * + * AutoUpdateConfigChangeListener + * @author zhangzheng * * @author lepdou 2022-03-28 */ @@ -54,7 +57,6 @@ public class PolarisPropertySourceAutoRefresher private static final Logger LOGGER = LoggerFactory.getLogger(PolarisPropertySourceAutoRefresher.class); private final PolarisConfigProperties polarisConfigProperties; private final PolarisPropertySourceManager polarisPropertySourceManager; - private final boolean typeConverterHasConvertIfNecessaryWithFieldParameter; private TypeConverter typeConverter; private final SpringValueRegistry springValueRegistry; private ConfigurableBeanFactory beanFactory; @@ -71,8 +73,6 @@ public class PolarisPropertySourceAutoRefresher this.polarisPropertySourceManager = polarisPropertySourceManager; this.springValueRegistry = springValueRegistry; this.placeholderHelper = placeholderHelper; - this.typeConverterHasConvertIfNecessaryWithFieldParameter = testTypeConverterHasConvertIfNecessaryWithFieldParameter(); - } @Override @@ -112,13 +112,11 @@ public class PolarisPropertySourceAutoRefresher polarisPropertySource.getFileName()); for (String changedKey : configKVFileChangeEvent.changedKeys()) { - // 1. check whether the changed key is relevant Collection targetValues = springValueRegistry.get(beanFactory, changedKey); if (targetValues == null || targetValues.isEmpty()) { continue; } - // 2. update the value for (SpringValue val : targetValues) { updateSpringValue(val); @@ -163,7 +161,6 @@ public class PolarisPropertySourceAutoRefresher this.typeConverter.convertIfNecessary(value, springValue.getTargetType(), springValue.getMethodParameter()); } - return value; } @@ -176,15 +173,4 @@ public class PolarisPropertySourceAutoRefresher throw ex; } } - - private boolean testTypeConverterHasConvertIfNecessaryWithFieldParameter() { - try { - TypeConverter.class.getMethod("convertIfNecessary", Object.class, Class.class, Field.class); - } - catch (Throwable ex) { - return false; - } - return true; - } - } From 4db59792535fb6108ace49b7c111489776ec1fb3 Mon Sep 17 00:00:00 2001 From: weihu Date: Wed, 6 Jul 2022 09:04:07 +0800 Subject: [PATCH 11/13] remote redundant code --- .../adapter/PolarisPropertiesSourceAutoRefresherTest.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) 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 40159828f..8edd1e05a 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 @@ -40,7 +40,6 @@ import org.mockito.junit.MockitoJUnitRunner; import org.springframework.beans.TypeConverter; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; -import org.springframework.cloud.context.refresh.ContextRefresher; import org.springframework.context.ConfigurableApplicationContext; import static org.mockito.ArgumentMatchers.any; @@ -80,7 +79,6 @@ public class PolarisPropertiesSourceAutoRefresherTest { when(applicationContext.getBeanFactory()).thenReturn(beanFactory); refresher.setApplicationContext(applicationContext); when(typeConverter.convertIfNecessary(any(), any(), (Field) any())).thenReturn("v11"); - Collection springValues = new ArrayList<>(); MockedConfigChange mockedConfigChange = new MockedConfigChange(); mockedConfigChange.setK1("v1"); @@ -91,7 +89,7 @@ public class PolarisPropertiesSourceAutoRefresherTest { when(springValueRegistry.get(any(), any())).thenReturn(springValues); when(polarisConfigProperties.isAutoRefresh()).thenReturn(true); - + Map content = new HashMap<>(); content.put("k1", "v1"); content.put("k2", "v2"); From 1e897ccad2a73059ce5be5744a315b8fe5394fe4 Mon Sep 17 00:00:00 2001 From: weihu Date: Wed, 6 Jul 2022 09:25:30 +0800 Subject: [PATCH 12/13] update bug --- .../config/adapter/PolarisPropertySourceAutoRefresher.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertySourceAutoRefresher.java b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertySourceAutoRefresher.java index bdb8d3f75..bbd86d030 100644 --- a/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertySourceAutoRefresher.java +++ b/spring-cloud-starter-tencent-polaris-config/src/main/java/com/tencent/cloud/polaris/config/adapter/PolarisPropertySourceAutoRefresher.java @@ -157,7 +157,7 @@ public class PolarisPropertySourceAutoRefresher value = parseJsonValue((String) value, springValue.getTargetType()); } else { - value = springValue.isField() ? this.typeConverter.convertIfNecessary(value, springValue.getTargetType()) : + value = springValue.isField() ? this.typeConverter.convertIfNecessary(value, springValue.getTargetType(), springValue.getField()) : this.typeConverter.convertIfNecessary(value, springValue.getTargetType(), springValue.getMethodParameter()); } From b115d967f63d330b0c2fdc43e072fd18729abed2 Mon Sep 17 00:00:00 2001 From: weihu Date: Wed, 6 Jul 2022 10:03:39 +0800 Subject: [PATCH 13/13] update CHANGELOG.md --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a8d303706..149ee26b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,4 +38,3 @@ - [UT: add Polaris LoadBalancer unit test](https://github.com/Tencent/spring-cloud-tencent/pull/373) - [docs:update docs](https://github.com/Tencent/spring-cloud-tencent/pull/378) - [docs:optimize example](https://github.com/Tencent/spring-cloud-tencent/pull/385) -- [Feature: optimization refreshScope](https://github.com/Tencent/spring-cloud-tencent/pull/326)