diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/annotation/ApolloJsonValueProcessor.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/annotation/ApolloJsonValueProcessor.java index e04bf2d1c2dad38437c77cdd5fde627695cf5c87..79b370f543fe88bd56007642e91467704c45aec7 100644 --- a/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/annotation/ApolloJsonValueProcessor.java +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/annotation/ApolloJsonValueProcessor.java @@ -65,7 +65,7 @@ public class ApolloJsonValueProcessor extends ApolloProcessor implements BeanFac Set keys = placeholderHelper.extractPlaceholderKeys(placeholder); for (String key : keys) { SpringValue springValue = new SpringValue(key, placeholder, bean, beanName, field, true); - springValueRegistry.register(key, springValue); + springValueRegistry.register(beanFactory, key, springValue); logger.debug("Monitoring {}", springValue); } } @@ -102,7 +102,7 @@ public class ApolloJsonValueProcessor extends ApolloProcessor implements BeanFac for (String key : keys) { SpringValue springValue = new SpringValue(key, apolloJsonValue.value(), bean, beanName, method, true); - springValueRegistry.register(key, springValue); + springValueRegistry.register(beanFactory, key, springValue); logger.debug("Monitoring {}", springValue); } } diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/annotation/SpringValueProcessor.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/annotation/SpringValueProcessor.java index bc6d8b7f33bc60e130bf4a053938aba9123ca522..7931faf64fc673f6bc04b7466635b3a395b6292d 100644 --- a/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/annotation/SpringValueProcessor.java +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/annotation/SpringValueProcessor.java @@ -19,9 +19,12 @@ 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; /** @@ -30,7 +33,7 @@ import org.springframework.context.annotation.Bean; * @author github.com/zhegexiaohuozi seimimaster@gmail.com * @since 2017/12/20. */ -public class SpringValueProcessor extends ApolloProcessor implements BeanFactoryPostProcessor { +public class SpringValueProcessor extends ApolloProcessor implements BeanFactoryPostProcessor, BeanFactoryAware { private static final Logger logger = LoggerFactory.getLogger(SpringValueProcessor.class); @@ -38,21 +41,22 @@ public class SpringValueProcessor extends ApolloProcessor implements BeanFactory private final PlaceholderHelper placeholderHelper; private final SpringValueRegistry springValueRegistry; - private static Multimap beanName2SpringValueDefinitions = - LinkedListMultimap.create(); + private BeanFactory beanFactory; + private Multimap beanName2SpringValueDefinitions; public SpringValueProcessor() { configUtil = ApolloInjector.getInstance(ConfigUtil.class); placeholderHelper = SpringInjector.getInstance(PlaceholderHelper.class); springValueRegistry = SpringInjector.getInstance(SpringValueRegistry.class); + beanName2SpringValueDefinitions = LinkedListMultimap.create(); } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { - if (configUtil.isAutoUpdateInjectedSpringPropertiesEnabled()) { + if (configUtil.isAutoUpdateInjectedSpringPropertiesEnabled() && beanFactory instanceof BeanDefinitionRegistry) { beanName2SpringValueDefinitions = SpringValueDefinitionProcessor - .getBeanName2SpringValueDefinitions(); + .getBeanName2SpringValueDefinitions((BeanDefinitionRegistry) beanFactory); } } @@ -82,7 +86,7 @@ public class SpringValueProcessor extends ApolloProcessor implements BeanFactory for (String key : keys) { SpringValue springValue = new SpringValue(key, value.value(), bean, beanName, field, false); - springValueRegistry.register(key, springValue); + springValueRegistry.register(beanFactory, key, springValue); logger.debug("Monitoring {}", springValue); } } @@ -112,7 +116,7 @@ public class SpringValueProcessor extends ApolloProcessor implements BeanFactory for (String key : keys) { SpringValue springValue = new SpringValue(key, value.value(), bean, beanName, method, false); - springValueRegistry.register(key, springValue); + springValueRegistry.register(beanFactory, key, springValue); logger.info("Monitoring {}", springValue); } } @@ -135,7 +139,7 @@ public class SpringValueProcessor extends ApolloProcessor implements BeanFactory } SpringValue springValue = new SpringValue(definition.getKey(), definition.getPlaceholder(), bean, beanName, method, false); - springValueRegistry.register(definition.getKey(), springValue); + springValueRegistry.register(beanFactory, definition.getKey(), springValue); logger.debug("Monitoring {}", springValue); } catch (Throwable ex) { logger.error("Failed to enable auto update feature for {}.{}", bean.getClass(), @@ -147,4 +151,8 @@ public class SpringValueProcessor extends ApolloProcessor implements BeanFactory beanName2SpringValueDefinitions.removeAll(beanName); } + @Override + public void setBeanFactory(BeanFactory beanFactory) throws BeansException { + this.beanFactory = beanFactory; + } } diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/config/PropertySourcesProcessor.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/config/PropertySourcesProcessor.java index f6bfb4f412a149c8518e81aa1295630453eda87d..268c2b6715d347860a99fd8c5e0e7197c4b8e2bd 100644 --- a/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/config/PropertySourcesProcessor.java +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/config/PropertySourcesProcessor.java @@ -11,9 +11,11 @@ import com.google.common.collect.Multimap; import com.ctrip.framework.apollo.Config; import com.ctrip.framework.apollo.ConfigService; +import com.google.common.collect.Sets; import java.util.List; -import java.util.concurrent.atomic.AtomicBoolean; +import java.util.Set; import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.context.EnvironmentAware; @@ -40,7 +42,7 @@ import org.springframework.core.env.PropertySource; */ public class PropertySourcesProcessor implements BeanFactoryPostProcessor, EnvironmentAware, PriorityOrdered { private static final Multimap NAMESPACE_NAMES = LinkedHashMultimap.create(); - private static final AtomicBoolean INITIALIZED = new AtomicBoolean(false); + private static final Set AUTO_UPDATE_INITIALIZED_BEAN_FACTORIES = Sets.newConcurrentHashSet(); private final ConfigPropertySourceFactory configPropertySourceFactory = SpringInjector .getInstance(ConfigPropertySourceFactory.class); @@ -53,11 +55,8 @@ public class PropertySourcesProcessor implements BeanFactoryPostProcessor, Envir @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { - if (INITIALIZED.compareAndSet(false, true)) { - initializePropertySources(); - - initializeAutoUpdatePropertiesFeature(beanFactory); - } + initializePropertySources(); + initializeAutoUpdatePropertiesFeature(beanFactory); } private void initializePropertySources() { @@ -80,6 +79,9 @@ public class PropertySourcesProcessor implements BeanFactoryPostProcessor, Envir } } + // clean up + NAMESPACE_NAMES.clear(); + // add after the bootstrap property source or to the first if (environment.getPropertySources() .contains(PropertySourcesConstants.APOLLO_BOOTSTRAP_PROPERTY_SOURCE_NAME)) { @@ -110,7 +112,8 @@ public class PropertySourcesProcessor implements BeanFactoryPostProcessor, Envir } private void initializeAutoUpdatePropertiesFeature(ConfigurableListableBeanFactory beanFactory) { - if (!configUtil.isAutoUpdateInjectedSpringPropertiesEnabled()) { + if (!configUtil.isAutoUpdateInjectedSpringPropertiesEnabled() || + !AUTO_UPDATE_INITIALIZED_BEAN_FACTORIES.add(beanFactory)) { return; } @@ -129,12 +132,6 @@ public class PropertySourcesProcessor implements BeanFactoryPostProcessor, Envir this.environment = (ConfigurableEnvironment) environment; } - //only for test - private static void reset() { - NAMESPACE_NAMES.clear(); - INITIALIZED.set(false); - } - @Override public int getOrder() { //make it as early as possible diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/property/AutoUpdateConfigChangeListener.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/property/AutoUpdateConfigChangeListener.java index e10ef1720067c0f6f042a5a526564d589ac582d3..95fb8009122d286b7fe51d23e2f9e1902df6e947 100644 --- a/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/property/AutoUpdateConfigChangeListener.java +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/property/AutoUpdateConfigChangeListener.java @@ -51,7 +51,7 @@ public class AutoUpdateConfigChangeListener implements ConfigChangeListener{ } for (String key : keys) { // 1. check whether the changed key is relevant - Collection targetValues = springValueRegistry.get(key); + Collection targetValues = springValueRegistry.get(beanFactory, key); if (targetValues == null || targetValues.isEmpty()) { continue; } diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/property/SpringValueDefinitionProcessor.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/property/SpringValueDefinitionProcessor.java index b1ce51abc8bfa826732ea25b07c25bba96015d3d..75ff878db46e0f2436228d46fb3942ba7fec07ca 100644 --- a/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/property/SpringValueDefinitionProcessor.java +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/property/SpringValueDefinitionProcessor.java @@ -1,10 +1,12 @@ package com.ctrip.framework.apollo.spring.property; import com.ctrip.framework.apollo.spring.util.SpringInjector; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; import java.util.List; +import java.util.Map; import java.util.Set; -import java.util.concurrent.atomic.AtomicBoolean; import org.springframework.beans.BeansException; import org.springframework.beans.MutablePropertyValues; import org.springframework.beans.PropertyValue; @@ -30,9 +32,9 @@ import com.google.common.collect.Multimap; * */ public class SpringValueDefinitionProcessor implements BeanDefinitionRegistryPostProcessor { - private static final Multimap beanName2SpringValueDefinitions = - LinkedListMultimap.create(); - private static final AtomicBoolean initialized = new AtomicBoolean(false); + private static final Map> beanName2SpringValueDefinitions = + Maps.newConcurrentMap(); + private static final Set PROPERTY_VALUES_PROCESSED_BEAN_FACTORIES = Sets.newConcurrentHashSet(); private final ConfigUtil configUtil; private final PlaceholderHelper placeholderHelper; @@ -54,16 +56,27 @@ public class SpringValueDefinitionProcessor implements BeanDefinitionRegistryPos } - public static Multimap getBeanName2SpringValueDefinitions() { - return beanName2SpringValueDefinitions; + 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 (!initialized.compareAndSet(false, true)) { + 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); @@ -82,16 +95,9 @@ public class SpringValueDefinitionProcessor implements BeanDefinitionRegistryPos } for (String key : keys) { - beanName2SpringValueDefinitions.put(beanName, - new SpringValueDefinition(key, placeholder, propertyValue.getName())); + springValueDefinitions.put(beanName, new SpringValueDefinition(key, placeholder, propertyValue.getName())); } } } } - - //only for test - private static void reset() { - initialized.set(false); - beanName2SpringValueDefinitions.clear(); - } } diff --git a/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/property/SpringValueRegistry.java b/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/property/SpringValueRegistry.java index db55b8bed5ba3886d51609708688c9ae91e107ec..aeb8f8201b5c96d0363084c676a697b697cf63a9 100644 --- a/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/property/SpringValueRegistry.java +++ b/apollo-client/src/main/java/com/ctrip/framework/apollo/spring/property/SpringValueRegistry.java @@ -1,17 +1,34 @@ package com.ctrip.framework.apollo.spring.property; import com.google.common.collect.LinkedListMultimap; +import com.google.common.collect.Maps; import com.google.common.collect.Multimap; import java.util.Collection; +import java.util.Map; +import org.springframework.beans.factory.BeanFactory; public class SpringValueRegistry { - private final Multimap registry = LinkedListMultimap.create(); - public void register(String key, SpringValue springValue) { - registry.put(key, springValue); + private final Map> registry = Maps.newConcurrentMap(); + 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, LinkedListMultimap.create()); + } + } + } + + registry.get(beanFactory).put(key, springValue); } - public Collection get(String key) { - return registry.get(key); + public Collection get(BeanFactory beanFactory, String key) { + Multimap beanFactorySpringValues = registry.get(beanFactory); + if (beanFactorySpringValues == null) { + return null; + } + return beanFactorySpringValues.get(key); } } diff --git a/apollo-client/src/test/java/com/ctrip/framework/apollo/spring/AbstractSpringIntegrationTest.java b/apollo-client/src/test/java/com/ctrip/framework/apollo/spring/AbstractSpringIntegrationTest.java index f8904b81b2937ade8113fd2074f89ec9cff4f3e5..1ee6432b0d9841b29e4bca2fb628b9bdb1290084 100644 --- a/apollo-client/src/test/java/com/ctrip/framework/apollo/spring/AbstractSpringIntegrationTest.java +++ b/apollo-client/src/test/java/com/ctrip/framework/apollo/spring/AbstractSpringIntegrationTest.java @@ -33,16 +33,10 @@ import com.google.common.collect.Maps; */ public abstract class AbstractSpringIntegrationTest { private static final Map CONFIG_REGISTRY = Maps.newHashMap(); - private static Method PROPERTY_SOURCES_PROCESSOR_CLEAR; - private static Method SPRING_VALUE_DEFINITION_PROCESS_CLEAR; private static Method CONFIG_SERVICE_RESET; static { try { - PROPERTY_SOURCES_PROCESSOR_CLEAR = PropertySourcesProcessor.class.getDeclaredMethod("reset"); - ReflectionUtils.makeAccessible(PROPERTY_SOURCES_PROCESSOR_CLEAR); - SPRING_VALUE_DEFINITION_PROCESS_CLEAR = SpringValueDefinitionProcessor.class.getDeclaredMethod("reset"); - ReflectionUtils.makeAccessible(SPRING_VALUE_DEFINITION_PROCESS_CLEAR); CONFIG_SERVICE_RESET = ConfigService.class.getDeclaredMethod("reset"); ReflectionUtils.makeAccessible(CONFIG_SERVICE_RESET); } catch (NoSuchMethodException e) { @@ -112,10 +106,6 @@ public abstract class AbstractSpringIntegrationTest { } protected static void doSetUp() { - //as PropertySourcesProcessor has some static states, so we must manually clear its state - ReflectionUtils.invokeMethod(PROPERTY_SOURCES_PROCESSOR_CLEAR, null); - //as SpringValueDefinitionProcessor has some static states, so we must manually clear its state - ReflectionUtils.invokeMethod(SPRING_VALUE_DEFINITION_PROCESS_CLEAR, null); //as ConfigService is singleton, so we must manually clear its container ReflectionUtils.invokeMethod(CONFIG_SERVICE_RESET, null); MockInjector.reset(); diff --git a/apollo-mockserver/src/main/java/com/ctrip/framework/apollo/mockserver/EmbeddedApollo.java b/apollo-mockserver/src/main/java/com/ctrip/framework/apollo/mockserver/EmbeddedApollo.java index c616c4bb3e91dcd087a60dbd7df119674977dc2b..3c2ed099a30544ff929be7da1926b9db66b34ded 100644 --- a/apollo-mockserver/src/main/java/com/ctrip/framework/apollo/mockserver/EmbeddedApollo.java +++ b/apollo-mockserver/src/main/java/com/ctrip/framework/apollo/mockserver/EmbeddedApollo.java @@ -37,8 +37,6 @@ public class EmbeddedApollo extends ExternalResource { private static final Type notificationType = new TypeToken>() { }.getType(); - private static Method PROPERTY_SOURCES_PROCESSOR_CLEAR; - private static Method SPRING_VALUE_DEFINITION_PROCESS_CLEAR; private static Method CONFIG_SERVICE_LOCATOR_CLEAR; private static ConfigServiceLocator CONFIG_SERVICE_LOCATOR; @@ -51,10 +49,6 @@ public class EmbeddedApollo extends ExternalResource { static { try { System.setProperty("apollo.longPollingInitialDelayInMills", "0"); - PROPERTY_SOURCES_PROCESSOR_CLEAR = PropertySourcesProcessor.class.getDeclaredMethod("reset"); - PROPERTY_SOURCES_PROCESSOR_CLEAR.setAccessible(true); - SPRING_VALUE_DEFINITION_PROCESS_CLEAR = SpringValueDefinitionProcessor.class.getDeclaredMethod("reset"); - SPRING_VALUE_DEFINITION_PROCESS_CLEAR.setAccessible(true); CONFIG_SERVICE_LOCATOR = ApolloInjector.getInstance(ConfigServiceLocator.class); CONFIG_SERVICE_LOCATOR_CLEAR = ConfigServiceLocator.class.getDeclaredMethod("initConfigServices"); CONFIG_SERVICE_LOCATOR_CLEAR.setAccessible(true); @@ -105,9 +99,6 @@ public class EmbeddedApollo extends ExternalResource { private void clear() throws Exception { resetOverriddenProperties(); - // clear Apollo states - PROPERTY_SOURCES_PROCESSOR_CLEAR.invoke(null); - SPRING_VALUE_DEFINITION_PROCESS_CLEAR.invoke(null); } private void mockConfigServiceUrl(String url) throws Exception {