Refactor ConfigurationPropertiesRebinder a bit

It's not super expensive, but it all adds up, and rebinding beans
that don't need to be rebound is wasteful. This change should improve
things in three places:

The ConfigurationPropertiesRebinder
has always done a pre-emptive re-bind on startup, which was a bit
of a blunt instrument, since all we really wanted as to rebind the
beans in the parent context (to the current context's Environment).

The rebinding always happened twice for every bean because we
explicitly called into the ConfigurationPropertiesPostProcessor
directly as well as indirectly through the initialization callbacks.

Rebinding in response to an EnvironmentChangeEvent was not able to
distinguish between events published locally and by child contexts.
The child context always binds the parent's beans anyway, so you
don't need to do it twice.
This commit is contained in:
Dave Syer
2017-12-15 14:13:41 +00:00
parent 20798377df
commit c5382ccfd6
11 changed files with 101 additions and 47 deletions

View File

@@ -19,7 +19,9 @@ import javax.annotation.PostConstruct;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
@@ -33,17 +35,22 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
import static org.junit.Assert.assertEquals;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = TestConfiguration.class)
@ActiveProfiles("config")
public class ConfigurationPropertiesRebinderIntegrationTests {
@Autowired
private TestProperties properties;
@Autowired
private ConfigProperties config;
@Autowired
private ConfigurationPropertiesRebinder rebinder;
@@ -54,44 +61,55 @@ public class ConfigurationPropertiesRebinderIntegrationTests {
@DirtiesContext
public void testSimpleProperties() throws Exception {
assertEquals("Hello scope!", this.properties.getMessage());
assertEquals(2, this.properties.getCount());
assertEquals(1, this.properties.getCount());
// Change the dynamic property source...
EnvironmentTestUtils.addEnvironment(this.environment, "message:Foo");
// ...but don't refresh, so the bean stays the same:
assertEquals("Hello scope!", this.properties.getMessage());
assertEquals(2, this.properties.getCount());
assertEquals(1, this.properties.getCount());
}
@Test
@DirtiesContext
public void testRefreshInParent() throws Exception {
assertEquals("main", this.config.getName());
// Change the dynamic property source...
EnvironmentTestUtils.addEnvironment(this.environment, "config.name=foo");
// ...and then refresh, so the bean is re-initialized:
this.rebinder.rebind();
assertEquals("foo", this.config.getName());
}
@Test
@DirtiesContext
public void testRefresh() throws Exception {
assertEquals(2, this.properties.getCount());
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();
assertEquals("Foo", this.properties.getMessage());
assertEquals(3, this.properties.getCount());
assertEquals(2, this.properties.getCount());
}
@Test
@DirtiesContext
public void testRefreshByName() throws Exception {
assertEquals(2, this.properties.getCount());
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(3, this.properties.getCount());
assertEquals(2, this.properties.getCount());
}
@Configuration
@EnableConfigurationProperties
@Import({ RefreshConfiguration.RebinderConfiguration.class,
PropertyPlaceholderAutoConfiguration.class })
PropertyPlaceholderAutoConfiguration.class })
protected static class TestConfiguration {
@Bean
@@ -104,8 +122,8 @@ public class ConfigurationPropertiesRebinderIntegrationTests {
// Hack out a protected inner class for testing
protected static class RefreshConfiguration extends RefreshAutoConfiguration {
@Configuration
protected static class RebinderConfiguration extends
ConfigurationPropertiesRebinderAutoConfiguration {
protected static class RebinderConfiguration
extends ConfigurationPropertiesRebinderAutoConfiguration {
}
}
@@ -142,4 +160,17 @@ public class ConfigurationPropertiesRebinderIntegrationTests {
}
}
@ConfigurationProperties("config")
@ConditionalOnMissingBean(ConfigProperties.class)
public static class ConfigProperties {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}

View File

@@ -21,6 +21,7 @@ import org.junit.After;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.logging.LogLevel;
import org.springframework.boot.logging.LoggingSystem;
import org.springframework.boot.test.util.EnvironmentTestUtils;
@@ -52,7 +53,7 @@ public class LoggingRebinderTests {
EnvironmentTestUtils.addEnvironment(environment,
"logging.level.org.springframework.web=TRACE");
this.rebinder.setEnvironment(environment);
this.rebinder.onApplicationEvent(new EnvironmentChangeEvent(
this.rebinder.onApplicationEvent(new EnvironmentChangeEvent(environment,
Collections.singleton("logging.level.org.springframework.web")));
assertTrue(this.logger.isTraceEnabled());
}
@@ -64,7 +65,7 @@ public class LoggingRebinderTests {
EnvironmentTestUtils.addEnvironment(environment,
"logging.level.org.springframework.web=trace");
this.rebinder.setEnvironment(environment);
this.rebinder.onApplicationEvent(new EnvironmentChangeEvent(
this.rebinder.onApplicationEvent(new EnvironmentChangeEvent(environment,
Collections.singleton("logging.level.org.springframework.web")));
assertTrue(this.logger.isTraceEnabled());
}