Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 3bfc923

Browse files
committedJun 4, 2019
Polish "Optimize CacheKey handling for immutable sources"
Make immutable properties more explicit and trust that they truly won't change. See gh-16717
1 parent 44d8321 commit 3bfc923

File tree

5 files changed

+73
-28
lines changed

5 files changed

+73
-28
lines changed
 

‎spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/source/SpringIterableConfigurationPropertySource.java

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.springframework.core.env.EnumerablePropertySource;
3030
import org.springframework.core.env.MapPropertySource;
3131
import org.springframework.core.env.PropertySource;
32+
import org.springframework.core.env.StandardEnvironment;
3233
import org.springframework.core.env.SystemEnvironmentPropertySource;
3334
import org.springframework.util.ObjectUtils;
3435

@@ -191,39 +192,29 @@ public void setMappings(PropertyMapping[] mappings) {
191192

192193
private static final class CacheKey {
193194

194-
private final Object key;
195-
196-
private final int size;
195+
private static final CacheKey IMMUTABLE_PROPERTY_SOURCE = new CacheKey(
196+
new Object[0]);
197197

198-
private final boolean unmodifiableKey;
198+
private final Object key;
199199

200-
private CacheKey(Object key, boolean unmodifiableKey) {
200+
private CacheKey(Object key) {
201201
this.key = key;
202-
this.size = calculateSize(key);
203-
this.unmodifiableKey = unmodifiableKey;
204202
}
205203

206204
public CacheKey copy() {
207-
return new CacheKey(copyKey(this.key), this.unmodifiableKey);
205+
if (this == IMMUTABLE_PROPERTY_SOURCE) {
206+
return IMMUTABLE_PROPERTY_SOURCE;
207+
}
208+
return new CacheKey(copyKey(this.key));
208209
}
209210

210211
private Object copyKey(Object key) {
211-
if (this.unmodifiableKey) {
212-
return key;
213-
}
214212
if (key instanceof Set) {
215213
return new HashSet<Object>((Set<?>) key);
216214
}
217215
return ((String[]) key).clone();
218216
}
219217

220-
private int calculateSize(Object key) {
221-
if (key instanceof Set) {
222-
return ((Set<?>) key).size();
223-
}
224-
return ((String[]) key).length;
225-
}
226-
227218
@Override
228219
public boolean equals(Object obj) {
229220
if (this == obj) {
@@ -233,9 +224,6 @@ public boolean equals(Object obj) {
233224
return false;
234225
}
235226
CacheKey otherCacheKey = (CacheKey) obj;
236-
if (this.size != otherCacheKey.size) {
237-
return false;
238-
}
239227
return ObjectUtils.nullSafeEquals(this.key, otherCacheKey.key);
240228
}
241229

@@ -245,11 +233,25 @@ public int hashCode() {
245233
}
246234

247235
public static CacheKey get(EnumerablePropertySource<?> source) {
236+
if (isImmutable(source)) {
237+
return IMMUTABLE_PROPERTY_SOURCE;
238+
}
248239
if (source instanceof MapPropertySource) {
249-
return new CacheKey(((MapPropertySource) source).getSource().keySet(),
250-
source instanceof OriginTrackedMapPropertySource);
240+
MapPropertySource mapPropertySource = (MapPropertySource) source;
241+
return new CacheKey(mapPropertySource.getSource().keySet());
242+
}
243+
return new CacheKey(source.getPropertyNames());
244+
}
245+
246+
private static boolean isImmutable(EnumerablePropertySource<?> source) {
247+
if (source instanceof OriginTrackedMapPropertySource) {
248+
return ((OriginTrackedMapPropertySource) source).isImmutable();
249+
}
250+
if (StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME
251+
.equals(source.getName())) {
252+
return source.getSource() == System.getenv();
251253
}
252-
return new CacheKey(source.getPropertyNames(), false);
254+
return false;
253255
}
254256

255257
}

‎spring-boot-project/spring-boot/src/main/java/org/springframework/boot/env/OriginTrackedMapPropertySource.java

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.springframework.boot.origin.OriginLookup;
2323
import org.springframework.boot.origin.OriginTrackedValue;
2424
import org.springframework.core.env.MapPropertySource;
25+
import org.springframework.core.env.PropertySource;
2526

2627
/**
2728
* {@link OriginLookup} backed by a {@link Map} containing {@link OriginTrackedValue
@@ -35,9 +36,28 @@
3536
public final class OriginTrackedMapPropertySource extends MapPropertySource
3637
implements OriginLookup<String> {
3738

38-
@SuppressWarnings({ "unchecked", "rawtypes" })
39+
private final boolean immutable;
40+
41+
/**
42+
* Create a new {@link OriginTrackedMapPropertySource} instance.
43+
* @param name the property source name
44+
* @param source the underlying map source
45+
*/
46+
@SuppressWarnings("rawtypes")
3947
public OriginTrackedMapPropertySource(String name, Map source) {
48+
this(name, source, false);
49+
}
50+
51+
/**
52+
* Create a new {@link OriginTrackedMapPropertySource} instance.
53+
* @param name the property source name
54+
* @param source the underlying map source
55+
* @param immutable if the underlying source is immutable and guaranteed not to change
56+
*/
57+
@SuppressWarnings({ "unchecked", "rawtypes" })
58+
public OriginTrackedMapPropertySource(String name, Map source, boolean immutable) {
4059
super(name, source);
60+
this.immutable = immutable;
4161
}
4262

4363
@Override
@@ -58,4 +78,13 @@ public Origin getOrigin(String name) {
5878
return null;
5979
}
6080

81+
/**
82+
* Return {@code true} if this {@link PropertySource} is immutable and has contents
83+
* that will never change.
84+
* @return if the property source is read only
85+
*/
86+
public boolean isImmutable() {
87+
return this.immutable;
88+
}
89+
6190
}

‎spring-boot-project/spring-boot/src/main/java/org/springframework/boot/env/PropertiesPropertySourceLoader.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ public List<PropertySource<?>> load(String name, Resource resource)
4848
if (properties.isEmpty()) {
4949
return Collections.emptyList();
5050
}
51-
return Collections
52-
.singletonList(new OriginTrackedMapPropertySource(name, properties));
51+
return Collections.singletonList(new OriginTrackedMapPropertySource(name,
52+
Collections.unmodifiableMap(properties), true));
5353
}
5454

5555
@SuppressWarnings({ "unchecked", "rawtypes" })

‎spring-boot-project/spring-boot/src/main/java/org/springframework/boot/env/YamlPropertySourceLoader.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public List<PropertySource<?>> load(String name, Resource resource)
5555
for (int i = 0; i < loaded.size(); i++) {
5656
String documentNumber = (loaded.size() != 1) ? " (document #" + i + ")" : "";
5757
propertySources.add(new OriginTrackedMapPropertySource(name + documentNumber,
58-
loaded.get(i)));
58+
Collections.unmodifiableMap(loaded.get(i)), true));
5959
}
6060
return propertySources;
6161
}

‎spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/source/SpringIterableConfigurationPropertySourceTests.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,20 @@ public void originTrackedMapPropertySourceKeyAdditionInvalidatesCache() {
201201
assertThat(adapter.stream().count()).isEqualTo(3);
202202
}
203203

204+
public void readOnlyOriginTrackedMapPropertySourceKeyAdditionDoesNotInvalidateCache() {
205+
// gh-16717
206+
Map<String, Object> map = new LinkedHashMap<>();
207+
map.put("key1", "value1");
208+
map.put("key2", "value2");
209+
EnumerablePropertySource<?> source = new OriginTrackedMapPropertySource("test",
210+
map, true);
211+
SpringIterableConfigurationPropertySource adapter = new SpringIterableConfigurationPropertySource(
212+
source, DefaultPropertyMapper.INSTANCE);
213+
assertThat(adapter.stream().count()).isEqualTo(2);
214+
map.put("key3", "value3");
215+
assertThat(adapter.stream().count()).isEqualTo(2);
216+
}
217+
204218
/**
205219
* Test {@link PropertySource} that's also an {@link OriginLookup}.
206220
*/

0 commit comments

Comments
 (0)