Browse Source

Allow ConfigurationPropertiesRebinder to rebind beans by name

including ones in the parent context.
pull/50/head
Dave Syer 10 years ago
parent
commit
addeda8262
  1. 11
      spring-cloud-context/src/main/java/org/springframework/cloud/bootstrap/config/RefreshEndpoint.java
  2. 47
      spring-cloud-context/src/main/java/org/springframework/cloud/context/properties/ConfigurationPropertiesRebinder.java
  3. 13
      spring-cloud-context/src/test/java/org/springframework/cloud/context/properties/ConfigurationPropertiesRebinderIntegrationTests.java

11
spring-cloud-context/src/main/java/org/springframework/cloud/bootstrap/config/RefreshEndpoint.java

@ -107,14 +107,15 @@ public class RefreshEndpoint extends AbstractEndpoint<Collection<String>> { @@ -107,14 +107,15 @@ public class RefreshEndpoint extends AbstractEndpoint<Collection<String>> {
}
}
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;
}
}
}

47
spring-cloud-context/src/main/java/org/springframework/cloud/context/properties/ConfigurationPropertiesRebinder.java

@ -44,16 +44,16 @@ import org.springframework.stereotype.Component; @@ -44,16 +44,16 @@ import org.springframework.stereotype.Component;
* <code>@ConfigurationProperties</code>}. When these beans are re-bound and
* re-initialized the changes are available immediately to any component that is using the
* <code>@ConfigurationProperties</code> 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<EnvironmentChangeEvent>, ApplicationContextAware {
ApplicationListener<EnvironmentChangeEvent>, ApplicationContextAware {
private ConfigurationBeanFactoryMetaData metaData;
@ -100,34 +100,34 @@ public class ConfigurationPropertiesRebinder implements BeanPostProcessor, @@ -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, @@ -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<String> getBeanNames() {
return new HashSet<String>(beans.keySet());
return new HashSet<String>(this.beans.keySet());
}
@Override

13
spring-cloud-context/src/test/java/org/springframework/cloud/context/properties/ConfigurationPropertiesRebinderIntegrationTests.java

@ -73,6 +73,19 @@ public class ConfigurationPropertiesRebinderIntegrationTests { @@ -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})

Loading…
Cancel
Save