Skip to content

Commit e8952fc

Browse files
authored
Updates ContextRefresher to maintain property source ordering. (#705)
Updates the targetName so that property sources maintain ordering from the bootstrap environment where they were refreshed. Fixes gh-704
1 parent 38fdd36 commit e8952fc

File tree

3 files changed

+131
-0
lines changed

3 files changed

+131
-0
lines changed

spring-cloud-context/src/main/java/org/springframework/cloud/context/refresh/ContextRefresher.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,8 @@ public synchronized Set<String> refreshEnvironment() {
129129
else {
130130
if (targetName != null) {
131131
target.addAfter(targetName, source);
132+
// update targetName to preserve ordering
133+
targetName = name;
132134
}
133135
else {
134136
// targetName was null so we are at the start of the list

spring-cloud-context/src/test/java/org/springframework/cloud/AdhocTestSuite.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
org.springframework.cloud.context.properties.ConfigurationPropertiesRebinderListIntegrationTests.class,
5151
org.springframework.cloud.context.properties.ConfigurationPropertiesRebinderLifecycleIntegrationTests.class,
5252
org.springframework.cloud.context.named.NamedContextFactoryTests.class,
53+
org.springframework.cloud.context.refresh.ContextRefresherOrderingIntegrationTests.class,
5354
org.springframework.cloud.context.refresh.ContextRefresherIntegrationTests.class,
5455
org.springframework.cloud.context.refresh.ContextRefresherTests.class,
5556
org.springframework.cloud.context.environment.EnvironmentManagerTest.class,
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/*
2+
* Copyright 2013-2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.cloud.context.refresh;
18+
19+
import java.util.ArrayList;
20+
import java.util.Collection;
21+
import java.util.Collections;
22+
import java.util.concurrent.atomic.AtomicBoolean;
23+
24+
import org.junit.AfterClass;
25+
import org.junit.BeforeClass;
26+
import org.junit.Test;
27+
import org.junit.runner.RunWith;
28+
29+
import org.springframework.beans.factory.annotation.Autowired;
30+
import org.springframework.boot.SpringBootConfiguration;
31+
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
32+
import org.springframework.boot.test.context.SpringBootTest;
33+
import org.springframework.cloud.bootstrap.config.PropertySourceLocator;
34+
import org.springframework.context.annotation.Configuration;
35+
import org.springframework.core.env.ConfigurableEnvironment;
36+
import org.springframework.core.env.Environment;
37+
import org.springframework.core.env.MapPropertySource;
38+
import org.springframework.core.env.MutablePropertySources;
39+
import org.springframework.core.env.PropertySource;
40+
import org.springframework.test.annotation.DirtiesContext;
41+
import org.springframework.test.context.junit4.SpringRunner;
42+
43+
import static java.util.Collections.singletonMap;
44+
import static org.assertj.core.api.Assertions.assertThat;
45+
46+
@RunWith(SpringRunner.class)
47+
@SpringBootTest
48+
@DirtiesContext
49+
public class ContextRefresherOrderingIntegrationTests {
50+
51+
@Autowired
52+
private ConfigurableEnvironment environment;
53+
54+
@Autowired
55+
private ContextRefresher refresher;
56+
57+
private static String original;
58+
59+
@BeforeClass
60+
public static void beforeClass() {
61+
original = System.getProperty("spring.cloud.bootstrap.sources");
62+
System.setProperty("spring.cloud.bootstrap.sources",
63+
"org.springframework.cloud.context.refresh.ContextRefresherOrderingIntegrationTests.PropertySourceConfiguration");
64+
}
65+
66+
@AfterClass
67+
public static void afterClass() {
68+
if (original != null) {
69+
System.setProperty("spring.cloud.bootstrap.sources", original);
70+
}
71+
else {
72+
System.clearProperty("spring.cloud.bootstrap.sources");
73+
}
74+
}
75+
76+
@Test
77+
public void orderingIsCorrect() {
78+
refresher.refresh();
79+
MutablePropertySources propertySources = environment.getPropertySources();
80+
PropertySource<?> test1 = propertySources
81+
.get("bootstrapProperties-testContextRefresherOrdering1");
82+
PropertySource<?> test2 = propertySources
83+
.get("bootstrapProperties-testContextRefresherOrdering2");
84+
PropertySource<?> test3 = propertySources
85+
.get("bootstrapProperties-testContextRefresherOrdering3");
86+
int index1 = propertySources.precedenceOf(test1);
87+
int index2 = propertySources.precedenceOf(test2);
88+
int index3 = propertySources.precedenceOf(test3);
89+
assertThat(index1).as("source1 index not less then source2").isLessThan(index2);
90+
assertThat(index2).as("source2 index not less then source3").isLessThan(index3);
91+
}
92+
93+
@SpringBootConfiguration
94+
@EnableAutoConfiguration
95+
protected static class Application {
96+
97+
}
98+
99+
@Configuration(proxyBeanMethods = false)
100+
// This is added to bootstrap context as a source in
101+
// contextrefresherordering.properties
102+
protected static class PropertySourceConfiguration implements PropertySourceLocator {
103+
104+
private static AtomicBoolean first = new AtomicBoolean(true);
105+
106+
@Override
107+
public PropertySource<?> locate(Environment environment) {
108+
throw new UnsupportedOperationException();
109+
}
110+
111+
@Override
112+
public Collection<PropertySource<?>> locateCollection(Environment environment) {
113+
if (first.compareAndSet(true, false)) {
114+
return Collections.emptyList();
115+
}
116+
ArrayList<PropertySource<?>> sources = new ArrayList<>();
117+
sources.add(new MapPropertySource("testContextRefresherOrdering1",
118+
singletonMap("key1", "value1")));
119+
sources.add(new MapPropertySource("testContextRefresherOrdering2",
120+
singletonMap("key2", "value2")));
121+
sources.add(new MapPropertySource("testContextRefresherOrdering3",
122+
singletonMap("key3", "value3")));
123+
return sources;
124+
}
125+
126+
}
127+
128+
}

0 commit comments

Comments
 (0)