Skip to content

Commit 5687207

Browse files
committed
Optimize CacheKey handling in SpringIterableConfigurationPropertySource
See spring-projectsgh-16401
1 parent 5aeb317 commit 5687207

File tree

2 files changed

+45
-7
lines changed

2 files changed

+45
-7
lines changed

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

+28-6
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.util.Set;
2525
import java.util.stream.Stream;
2626

27+
import org.springframework.boot.env.OriginTrackedMapPropertySource;
2728
import org.springframework.core.env.EnumerablePropertySource;
2829
import org.springframework.core.env.MapPropertySource;
2930
import org.springframework.core.env.PropertySource;
@@ -44,7 +45,7 @@
4445
class SpringIterableConfigurationPropertySource extends SpringConfigurationPropertySource
4546
implements IterableConfigurationPropertySource {
4647

47-
private volatile Object cacheKey;
48+
private volatile CacheKey cacheKey;
4849

4950
private volatile Cache cache;
5051

@@ -173,21 +174,37 @@ private static final class CacheKey {
173174

174175
private final Object key;
175176

176-
private CacheKey(Object key) {
177+
private final int size;
178+
179+
private final boolean unmodifiableKey;
180+
181+
private CacheKey(Object key, boolean unmodifiableKey) {
177182
this.key = key;
183+
this.size = calculateSize(key);
184+
this.unmodifiableKey = unmodifiableKey;
178185
}
179186

180187
public CacheKey copy() {
181-
return new CacheKey(copyKey(this.key));
188+
return new CacheKey(copyKey(this.key), this.unmodifiableKey);
182189
}
183190

184191
private Object copyKey(Object key) {
192+
if (this.unmodifiableKey) {
193+
return key;
194+
}
185195
if (key instanceof Set) {
186196
return new HashSet<Object>((Set<?>) key);
187197
}
188198
return ((String[]) key).clone();
189199
}
190200

201+
private int calculateSize(Object key) {
202+
if (key instanceof Set) {
203+
return ((Set<?>) key).size();
204+
}
205+
return ((String[]) key).length;
206+
}
207+
191208
@Override
192209
public boolean equals(Object obj) {
193210
if (this == obj) {
@@ -196,7 +213,11 @@ public boolean equals(Object obj) {
196213
if (obj == null || getClass() != obj.getClass()) {
197214
return false;
198215
}
199-
return ObjectUtils.nullSafeEquals(this.key, ((CacheKey) obj).key);
216+
CacheKey otherCacheKey = (CacheKey) obj;
217+
if (this.size != otherCacheKey.size) {
218+
return false;
219+
}
220+
return ObjectUtils.nullSafeEquals(this.key, otherCacheKey.key);
200221
}
201222

202223
@Override
@@ -206,9 +227,10 @@ public int hashCode() {
206227

207228
public static CacheKey get(EnumerablePropertySource<?> source) {
208229
if (source instanceof MapPropertySource) {
209-
return new CacheKey(((MapPropertySource) source).getSource().keySet());
230+
return new CacheKey(((MapPropertySource) source).getSource().keySet(),
231+
source instanceof OriginTrackedMapPropertySource);
210232
}
211-
return new CacheKey(source.getPropertyNames());
233+
return new CacheKey(source.getPropertyNames(), false);
212234
}
213235

214236
}

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

+17-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
import org.junit.Test;
2323

24+
import org.springframework.boot.env.OriginTrackedMapPropertySource;
2425
import org.springframework.boot.origin.Origin;
2526
import org.springframework.boot.origin.OriginLookup;
2627
import org.springframework.core.env.EnumerablePropertySource;
@@ -156,7 +157,7 @@ public void containsDescendantOfShouldCheckSourceNames() {
156157
}
157158

158159
@Test
159-
public void propertySourceKeyDataChangeInvalidatesCache() {
160+
public void simpleMapPropertySourceKeyDataChangeInvalidatesCache() {
160161
// gh-13344
161162
Map<String, Object> map = new LinkedHashMap<>();
162163
map.put("key1", "value1");
@@ -169,6 +170,21 @@ public void propertySourceKeyDataChangeInvalidatesCache() {
169170
assertThat(adapter.stream().count()).isEqualTo(3);
170171
}
171172

173+
@Test
174+
public void originTrackedMapPropertySourceKeyAdditionInvalidatesCache() {
175+
// gh-13344
176+
Map<String, Object> map = new LinkedHashMap<>();
177+
map.put("key1", "value1");
178+
map.put("key2", "value2");
179+
EnumerablePropertySource<?> source = new OriginTrackedMapPropertySource("test",
180+
map);
181+
SpringIterableConfigurationPropertySource adapter = new SpringIterableConfigurationPropertySource(
182+
source, DefaultPropertyMapper.INSTANCE);
183+
assertThat(adapter.stream().count()).isEqualTo(2);
184+
map.put("key3", "value3");
185+
assertThat(adapter.stream().count()).isEqualTo(3);
186+
}
187+
172188
/**
173189
* Test {@link PropertySource} that's also an {@link OriginLookup}.
174190
*/

0 commit comments

Comments
 (0)