Skip to content

Commit 44d8321

Browse files
dreis2211philwebb
authored andcommitted
Optimize CacheKey handling for immutable sources
Update `SpringIterableConfigurationPropertySource` so that cache keys do not need to be checked if property sources are immutable. See gh-16717
1 parent 071410c commit 44d8321

File tree

2 files changed

+41
-6
lines changed

2 files changed

+41
-6
lines changed

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

+27-5
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import java.util.Set;
2626
import java.util.stream.Stream;
2727

28+
import org.springframework.boot.env.OriginTrackedMapPropertySource;
2829
import org.springframework.core.env.EnumerablePropertySource;
2930
import org.springframework.core.env.MapPropertySource;
3031
import org.springframework.core.env.PropertySource;
@@ -192,21 +193,37 @@ private static final class CacheKey {
192193

193194
private final Object key;
194195

195-
private CacheKey(Object key) {
196+
private final int size;
197+
198+
private final boolean unmodifiableKey;
199+
200+
private CacheKey(Object key, boolean unmodifiableKey) {
196201
this.key = key;
202+
this.size = calculateSize(key);
203+
this.unmodifiableKey = unmodifiableKey;
197204
}
198205

199206
public CacheKey copy() {
200-
return new CacheKey(copyKey(this.key));
207+
return new CacheKey(copyKey(this.key), this.unmodifiableKey);
201208
}
202209

203210
private Object copyKey(Object key) {
211+
if (this.unmodifiableKey) {
212+
return key;
213+
}
204214
if (key instanceof Set) {
205215
return new HashSet<Object>((Set<?>) key);
206216
}
207217
return ((String[]) key).clone();
208218
}
209219

220+
private int calculateSize(Object key) {
221+
if (key instanceof Set) {
222+
return ((Set<?>) key).size();
223+
}
224+
return ((String[]) key).length;
225+
}
226+
210227
@Override
211228
public boolean equals(Object obj) {
212229
if (this == obj) {
@@ -215,7 +232,11 @@ public boolean equals(Object obj) {
215232
if (obj == null || getClass() != obj.getClass()) {
216233
return false;
217234
}
218-
return ObjectUtils.nullSafeEquals(this.key, ((CacheKey) obj).key);
235+
CacheKey otherCacheKey = (CacheKey) obj;
236+
if (this.size != otherCacheKey.size) {
237+
return false;
238+
}
239+
return ObjectUtils.nullSafeEquals(this.key, otherCacheKey.key);
219240
}
220241

221242
@Override
@@ -225,9 +246,10 @@ public int hashCode() {
225246

226247
public static CacheKey get(EnumerablePropertySource<?> source) {
227248
if (source instanceof MapPropertySource) {
228-
return new CacheKey(((MapPropertySource) source).getSource().keySet());
249+
return new CacheKey(((MapPropertySource) source).getSource().keySet(),
250+
source instanceof OriginTrackedMapPropertySource);
229251
}
230-
return new CacheKey(source.getPropertyNames());
252+
return new CacheKey(source.getPropertyNames(), false);
231253
}
232254

233255
}

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

+14-1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
import org.junit.Test;
2727

28+
import org.springframework.boot.env.OriginTrackedMapPropertySource;
2829
import org.springframework.boot.origin.Origin;
2930
import org.springframework.boot.origin.OriginLookup;
3031
import org.springframework.core.env.EnumerablePropertySource;
@@ -160,7 +161,7 @@ public void containsDescendantOfShouldCheckSourceNames() {
160161
}
161162

162163
@Test
163-
public void propertySourceKeyDataChangeInvalidatesCache() {
164+
public void simpleMapPropertySourceKeyDataChangeInvalidatesCache() {
164165
// gh-13344
165166
Map<String, Object> map = new LinkedHashMap<>();
166167
map.put("key1", "value1");
@@ -184,6 +185,18 @@ public void concurrentModificationExceptionInvalidatesCache() {
184185
source, DefaultPropertyMapper.INSTANCE);
185186
assertThat(adapter.stream().count()).isEqualTo(2);
186187
map.setThrowException(true);
188+
}
189+
190+
public void originTrackedMapPropertySourceKeyAdditionInvalidatesCache() {
191+
// gh-13344
192+
Map<String, Object> map = new LinkedHashMap<>();
193+
map.put("key1", "value1");
194+
map.put("key2", "value2");
195+
EnumerablePropertySource<?> source = new OriginTrackedMapPropertySource("test",
196+
map);
197+
SpringIterableConfigurationPropertySource adapter = new SpringIterableConfigurationPropertySource(
198+
source, DefaultPropertyMapper.INSTANCE);
199+
assertThat(adapter.stream().count()).isEqualTo(2);
187200
map.put("key3", "value3");
188201
assertThat(adapter.stream().count()).isEqualTo(3);
189202
}

0 commit comments

Comments
 (0)