Merge branch '1.3.x'

Test failure in spring-cloud-commons seems unrelated.
This commit is contained in:
Dave Syer
2017-12-15 16:06:56 +00:00
17 changed files with 266 additions and 79 deletions

View File

@@ -16,8 +16,6 @@
package org.springframework.cloud.autoconfigure;
import java.util.Collections;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@@ -25,7 +23,6 @@ import org.springframework.boot.autoconfigure.condition.SearchStrategy;
import org.springframework.boot.context.properties.ConfigurationBeanFactoryMetaData;
import org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor;
import org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessorRegistrar;
import org.springframework.cloud.context.environment.EnvironmentChangeEvent;
import org.springframework.cloud.context.properties.ConfigurationPropertiesBeans;
import org.springframework.cloud.context.properties.ConfigurationPropertiesRebinder;
import org.springframework.context.ApplicationContext;
@@ -65,16 +62,26 @@ public class ConfigurationPropertiesRebinderAutoConfiguration
@ConditionalOnMissingBean(search = SearchStrategy.CURRENT)
public ConfigurationPropertiesRebinder configurationPropertiesRebinder(
ConfigurationPropertiesBeans beans) {
ConfigurationPropertiesRebinder rebinder = new ConfigurationPropertiesRebinder(beans);
ConfigurationPropertiesRebinder rebinder = new ConfigurationPropertiesRebinder(
beans);
return rebinder;
}
@Override
public void afterSingletonsInstantiated() {
// After all beans are initialized send a pre-emptive EnvironmentChangeEvent
// so that anything that needs to rebind gets a chance now (especially for
// beans in the parent context)
this.context.publishEvent(
new EnvironmentChangeEvent(Collections.<String> emptySet()));
// After all beans are initialized explicitly rebind beans from the parent
// so that changes during the initialization of the current context are
// reflected. In particular this can be important when low level services like
// decryption are bootstrapped in the parent, but need to change their
// configuration before the child context is processed.
if (this.context.getParent() != null) {
// TODO: make this optional? (E.g. when creating child contexts that prefer to
// be isolated.)
ConfigurationPropertiesRebinder rebinder = context
.getBean(ConfigurationPropertiesRebinder.class);
for (String name : context.getParent().getBeanDefinitionNames()) {
rebinder.rebind(name);
}
}
}
}

View File

@@ -108,7 +108,7 @@ public class PropertySourceBootstrapConfiguration implements
}
insertPropertySources(propertySources, composite);
reinitializeLoggingSystem(environment, logConfig, logFile);
setLogLevels(environment);
setLogLevels(applicationContext, environment);
handleIncludedProfiles(environment);
}
}
@@ -140,13 +140,14 @@ public class PropertySourceBootstrapConfiguration implements
}
}
private void setLogLevels(ConfigurableEnvironment environment) {
private void setLogLevels(ConfigurableApplicationContext applicationContext,
ConfigurableEnvironment environment) {
LoggingRebinder rebinder = new LoggingRebinder();
rebinder.setEnvironment(environment);
// We can't fire the event in the ApplicationContext here (too early), but we can
// create our own listener and poke it (it doesn't need the key changes)
rebinder.onApplicationEvent(
new EnvironmentChangeEvent(Collections.<String> emptySet()));
rebinder.onApplicationEvent(new EnvironmentChangeEvent(applicationContext,
Collections.<String>emptySet()));
}
private void insertPropertySources(MutablePropertySources propertySources,

View File

@@ -116,7 +116,7 @@ public class EnvironmentDecryptApplicationInitializer implements
// The parent is actually the bootstrap context, and it is fully
// initialized, so we can fire an EnvironmentChangeEvent there to rebind
// @ConfigurationProperties, in case they were encrypted.
parent.publishEvent(new EnvironmentChangeEvent(found));
parent.publishEvent(new EnvironmentChangeEvent(parent, found));
}
}

View File

@@ -32,10 +32,15 @@ public class EnvironmentChangeEvent extends ApplicationEvent {
private Set<String> keys;
public EnvironmentChangeEvent(Set<String> keys) {
super(keys);
// Backwards compatible constructor with less utility (practically no use at all)
this(keys, keys);
}
public EnvironmentChangeEvent(Object context, Set<String> keys) {
super(context);
this.keys = keys;
}
/**
* @return the keys
*/

View File

@@ -68,7 +68,7 @@ public class EnvironmentManager implements ApplicationEventPublisherAware {
Map<String, Object> result = new LinkedHashMap<String, Object>(map);
if (!map.isEmpty()) {
map.clear();
publish(new EnvironmentChangeEvent(result.keySet()));
publish(new EnvironmentChangeEvent(publisher, result.keySet()));
}
return result;
}
@@ -88,7 +88,7 @@ public class EnvironmentManager implements ApplicationEventPublisherAware {
if (!value.equals(environment.getProperty(name))) {
map.put(name, value);
publish(new EnvironmentChangeEvent(Collections.singleton(name)));
publish(new EnvironmentChangeEvent(publisher, Collections.singleton(name)));
}
}

View File

@@ -129,7 +129,11 @@ public class ConfigurationPropertiesRebinder
@Override
public void onApplicationEvent(EnvironmentChangeEvent event) {
rebind();
if (this.applicationContext.equals(event.getSource())
// Backwards compatible
|| event.getKeys().equals(event.getSource())) {
rebind();
}
}
}

View File

@@ -35,9 +35,15 @@ public class ContextRefresher {
private static final String REFRESH_ARGS_PROPERTY_SOURCE = "refreshArgs";
private static final String[] DEFAULT_PROPERTY_SOURCES = new String[] { //order matters, cli args aren't first, things get messy
private static final String[] DEFAULT_PROPERTY_SOURCES = new String[] { // order
// matters,
// cli args
// aren't
// first,
// things get
// messy
CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME,
"defaultProperties"};
"defaultProperties" };
private Set<String> standardSources = new HashSet<>(
Arrays.asList(StandardEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME,
@@ -61,7 +67,7 @@ public class ContextRefresher {
addConfigFilesToEnvironment();
Set<String> keys = changes(before,
extract(this.context.getEnvironment().getPropertySources())).keySet();
this.context.publishEvent(new EnvironmentChangeEvent(keys));
this.context.publishEvent(new EnvironmentChangeEvent(context, keys));
this.scope.refreshAll();
return keys;
}

View File

@@ -15,13 +15,13 @@
*/
package org.springframework.cloud.context.properties;
import static org.junit.Assert.assertEquals;
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;
@@ -35,15 +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...
TestPropertyValues.of("message:Foo").applyTo(this.environment);
// ...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...
TestPropertyValues.of("config.name=foo").applyTo(this.environment);
// ...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...
TestPropertyValues.of("message:Foo").applyTo(this.environment);
// ...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...
TestPropertyValues.of("message:Foo").applyTo(this.environment);
// ...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

@@ -55,14 +55,14 @@ public class ConfigurationPropertiesRebinderLifecycleIntegrationTests {
@Test
@DirtiesContext
public void testRefresh() throws Exception {
assertEquals(1, this.properties.getCount());
assertEquals(0, this.properties.getCount());
assertEquals("Hello scope!", this.properties.getMessage());
// Change the dynamic property source...
TestPropertyValues.of("message:Foo").applyTo(this.environment);
// ...and then refresh, so the bean is re-initialized:
this.rebinder.rebind();
assertEquals("Foo", this.properties.getMessage());
assertEquals(2, this.properties.getCount());
assertEquals(1, this.properties.getCount());
}
@Configuration

View File

@@ -24,6 +24,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.TestPropertyValues;
@@ -52,7 +53,7 @@ public class LoggingRebinderTests {
TestPropertyValues.of("logging.level.org.springframework.web=TRACE")
.applyTo(environment);
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 {
TestPropertyValues.of("logging.level.org.springframework.web=trace")
.applyTo(environment);
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());
}

View File

@@ -0,0 +1 @@
config.name: main

View File

@@ -0,0 +1,2 @@
spring.main.sources: org.springframework.cloud.context.properties.ConfigurationPropertiesRebinderIntegrationTests.ConfigProperties
config.name: parent