diff --git a/spring-cloud-context/src/main/java/org/springframework/cloud/bootstrap/config/RefreshEndpoint.java b/spring-cloud-context/src/main/java/org/springframework/cloud/bootstrap/config/RefreshEndpoint.java index 5db43b35..7dbd0085 100644 --- a/spring-cloud-context/src/main/java/org/springframework/cloud/bootstrap/config/RefreshEndpoint.java +++ b/spring-cloud-context/src/main/java/org/springframework/cloud/bootstrap/config/RefreshEndpoint.java @@ -107,14 +107,15 @@ public class RefreshEndpoint extends AbstractEndpoint> { } } finally { - while (capture != null) { - capture.close(); - ApplicationContext parent = capture.getParent(); + ConfigurableApplicationContext closeable = capture; + while (closeable != null) { + closeable.close(); + ApplicationContext parent = closeable.getParent(); if (parent instanceof ConfigurableApplicationContext) { - capture = (ConfigurableApplicationContext) parent; + closeable = (ConfigurableApplicationContext) parent; } else { - capture = null; + closeable = null; } } } diff --git a/spring-cloud-context/src/main/java/org/springframework/cloud/context/properties/ConfigurationPropertiesRebinder.java b/spring-cloud-context/src/main/java/org/springframework/cloud/context/properties/ConfigurationPropertiesRebinder.java index f6d0e201..a47c6d41 100644 --- a/spring-cloud-context/src/main/java/org/springframework/cloud/context/properties/ConfigurationPropertiesRebinder.java +++ b/spring-cloud-context/src/main/java/org/springframework/cloud/context/properties/ConfigurationPropertiesRebinder.java @@ -44,16 +44,16 @@ import org.springframework.stereotype.Component; * @ConfigurationProperties}. When these beans are re-bound and * re-initialized the changes are available immediately to any component that is using the * @ConfigurationProperties bean. - * + * * @see RefreshScope for a deeper and optionally more focused refresh of bean components - * + * * @author Dave Syer * */ @Component @ManagedResource public class ConfigurationPropertiesRebinder implements BeanPostProcessor, - ApplicationListener, ApplicationContextAware { +ApplicationListener, ApplicationContextAware { private ConfigurationBeanFactoryMetaData metaData; @@ -100,34 +100,34 @@ public class ConfigurationPropertiesRebinder implements BeanPostProcessor, ConfigurationProperties annotation = AnnotationUtils.findAnnotation( bean.getClass(), ConfigurationProperties.class); if (annotation != null) { - beans.put(beanName, bean); + this.beans.put(beanName, bean); } - else if (metaData != null) { + else if (this.metaData != null) { annotation = this.metaData.findFactoryAnnotation(beanName, ConfigurationProperties.class); if (annotation != null) { - beans.put(beanName, bean); + this.beans.put(beanName, bean); } } return bean; } private boolean isRefreshScoped(String beanName) { - if (refreshScope == null && !refreshScopeInitialized) { - refreshScopeInitialized = true; - for (String scope : beanFactory.getRegisteredScopeNames()) { - if (beanFactory.getRegisteredScope(scope) instanceof org.springframework.cloud.context.scope.refresh.RefreshScope) { + if (this.refreshScope == null && !this.refreshScopeInitialized) { + this.refreshScopeInitialized = true; + for (String scope : this.beanFactory.getRegisteredScopeNames()) { + if (this.beanFactory.getRegisteredScope(scope) instanceof org.springframework.cloud.context.scope.refresh.RefreshScope) { this.refreshScope = scope; break; } } } - if (refreshScope == null) { + if (this.refreshScope == null) { return false; } - return beanFactory.containsBeanDefinition(beanName) - && refreshScope - .equals(beanFactory.getBeanDefinition(beanName).getScope()); + return this.beanFactory.containsBeanDefinition(beanName) + && this.refreshScope + .equals(this.beanFactory.getBeanDefinition(beanName).getScope()); } @Override @@ -138,23 +138,30 @@ public class ConfigurationPropertiesRebinder implements BeanPostProcessor, @ManagedOperation public void rebind() { - for (String name : beans.keySet()) { + for (String name : this.beans.keySet()) { rebind(name); } } @ManagedOperation public void rebind(String name) { - binder.postProcessBeforeInitialization(beans.get(name), name); - if (applicationContext != null) { - applicationContext.getAutowireCapableBeanFactory().initializeBean( - beans.get(name), name); + if (!this.applicationContext.containsBean(name)) { + return; + } + if (isRefreshScoped(name)) { + return; + } + Object bean = this.applicationContext.getBean(name); + this.binder.postProcessBeforeInitialization(bean, name); + if (this.applicationContext != null) { + this.applicationContext.getAutowireCapableBeanFactory().initializeBean( + bean, name); } } @ManagedAttribute public Set getBeanNames() { - return new HashSet(beans.keySet()); + return new HashSet(this.beans.keySet()); } @Override diff --git a/spring-cloud-context/src/test/java/org/springframework/cloud/context/properties/ConfigurationPropertiesRebinderIntegrationTests.java b/spring-cloud-context/src/test/java/org/springframework/cloud/context/properties/ConfigurationPropertiesRebinderIntegrationTests.java index 1931dc0a..d76cdbff 100644 --- a/spring-cloud-context/src/test/java/org/springframework/cloud/context/properties/ConfigurationPropertiesRebinderIntegrationTests.java +++ b/spring-cloud-context/src/test/java/org/springframework/cloud/context/properties/ConfigurationPropertiesRebinderIntegrationTests.java @@ -73,6 +73,19 @@ public class ConfigurationPropertiesRebinderIntegrationTests { assertEquals(2, this.properties.getCount()); } + @Test + @DirtiesContext + public void testRefreshByName() throws Exception { + assertEquals(1, this.properties.getCount()); + assertEquals("Hello scope!", this.properties.getMessage()); + // Change the dynamic property source... + EnvironmentTestUtils.addEnvironment(this.environment, "message:Foo"); + // ...and then refresh, so the bean is re-initialized: + this.rebinder.rebind("properties"); + assertEquals("Foo", this.properties.getMessage()); + assertEquals(2, this.properties.getCount()); + } + @Configuration @EnableConfigurationProperties @Import({RefreshConfiguration.RebinderConfiguration.class, PropertyPlaceholderAutoConfiguration.class})