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
This commit is contained in:
dreis2211 2019-05-04 18:47:41 +02:00 committed by Phillip Webb
parent 071410c437
commit 44d832158a
2 changed files with 41 additions and 6 deletions

View File

@ -25,6 +25,7 @@ import java.util.List;
import java.util.Set;
import java.util.stream.Stream;
import org.springframework.boot.env.OriginTrackedMapPropertySource;
import org.springframework.core.env.EnumerablePropertySource;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.PropertySource;
@ -192,21 +193,37 @@ class SpringIterableConfigurationPropertySource extends SpringConfigurationPrope
private final Object key;
private CacheKey(Object key) {
private final int size;
private final boolean unmodifiableKey;
private CacheKey(Object key, boolean unmodifiableKey) {
this.key = key;
this.size = calculateSize(key);
this.unmodifiableKey = unmodifiableKey;
}
public CacheKey copy() {
return new CacheKey(copyKey(this.key));
return new CacheKey(copyKey(this.key), this.unmodifiableKey);
}
private Object copyKey(Object key) {
if (this.unmodifiableKey) {
return key;
}
if (key instanceof Set) {
return new HashSet<Object>((Set<?>) key);
}
return ((String[]) key).clone();
}
private int calculateSize(Object key) {
if (key instanceof Set) {
return ((Set<?>) key).size();
}
return ((String[]) key).length;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
@ -215,7 +232,11 @@ class SpringIterableConfigurationPropertySource extends SpringConfigurationPrope
if (obj == null || getClass() != obj.getClass()) {
return false;
}
return ObjectUtils.nullSafeEquals(this.key, ((CacheKey) obj).key);
CacheKey otherCacheKey = (CacheKey) obj;
if (this.size != otherCacheKey.size) {
return false;
}
return ObjectUtils.nullSafeEquals(this.key, otherCacheKey.key);
}
@Override
@ -225,9 +246,10 @@ class SpringIterableConfigurationPropertySource extends SpringConfigurationPrope
public static CacheKey get(EnumerablePropertySource<?> source) {
if (source instanceof MapPropertySource) {
return new CacheKey(((MapPropertySource) source).getSource().keySet());
return new CacheKey(((MapPropertySource) source).getSource().keySet(),
source instanceof OriginTrackedMapPropertySource);
}
return new CacheKey(source.getPropertyNames());
return new CacheKey(source.getPropertyNames(), false);
}
}

View File

@ -25,6 +25,7 @@ import java.util.Set;
import org.junit.Test;
import org.springframework.boot.env.OriginTrackedMapPropertySource;
import org.springframework.boot.origin.Origin;
import org.springframework.boot.origin.OriginLookup;
import org.springframework.core.env.EnumerablePropertySource;
@ -160,7 +161,7 @@ public class SpringIterableConfigurationPropertySourceTests {
}
@Test
public void propertySourceKeyDataChangeInvalidatesCache() {
public void simpleMapPropertySourceKeyDataChangeInvalidatesCache() {
// gh-13344
Map<String, Object> map = new LinkedHashMap<>();
map.put("key1", "value1");
@ -184,6 +185,18 @@ public class SpringIterableConfigurationPropertySourceTests {
source, DefaultPropertyMapper.INSTANCE);
assertThat(adapter.stream().count()).isEqualTo(2);
map.setThrowException(true);
}
public void originTrackedMapPropertySourceKeyAdditionInvalidatesCache() {
// gh-13344
Map<String, Object> map = new LinkedHashMap<>();
map.put("key1", "value1");
map.put("key2", "value2");
EnumerablePropertySource<?> source = new OriginTrackedMapPropertySource("test",
map);
SpringIterableConfigurationPropertySource adapter = new SpringIterableConfigurationPropertySource(
source, DefaultPropertyMapper.INSTANCE);
assertThat(adapter.stream().count()).isEqualTo(2);
map.put("key3", "value3");
assertThat(adapter.stream().count()).isEqualTo(3);
}