Skip to content

Commit

Permalink
Merge pull request #334 from trytocatch/master
Browse files Browse the repository at this point in the history
Solve: the dynamically updated property value cannot be obtained, and the concurrency problem
  • Loading branch information
ulisesbocchio authored Dec 12, 2022
2 parents 8ebc522 + 8db9926 commit f4bd311
Showing 1 changed file with 40 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@
import com.ulisesbocchio.jasyptspringboot.EncryptablePropertyFilter;
import com.ulisesbocchio.jasyptspringboot.EncryptablePropertyResolver;
import com.ulisesbocchio.jasyptspringboot.EncryptablePropertySource;
import java.util.HashMap;

import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.env.PropertySource;
import org.springframework.util.Assert;
Expand All @@ -15,7 +18,7 @@ public class CachingDelegateEncryptablePropertySource<T> extends PropertySource<
private final PropertySource<T> delegate;
private final EncryptablePropertyResolver resolver;
private final EncryptablePropertyFilter filter;
private final Map<String, Object> cache;
private final Map<String, CachedValue> cache;

public CachingDelegateEncryptablePropertySource(PropertySource<T> delegate, EncryptablePropertyResolver resolver, EncryptablePropertyFilter filter) {
super(delegate.getName(), delegate.getSource());
Expand All @@ -25,7 +28,7 @@ public CachingDelegateEncryptablePropertySource(PropertySource<T> delegate, Encr
this.delegate = delegate;
this.resolver = resolver;
this.filter = filter;
this.cache = new HashMap<>();
this.cache = new ConcurrentHashMap<>();
}

@Override
Expand All @@ -35,24 +38,48 @@ public PropertySource<T> getDelegate() {

@Override
public Object getProperty(String name) {
// Can be called recursively, so, we cannot use computeIfAbsent.
if (cache.containsKey(name)) {
return cache.get(name);
//The purpose of this cache is to reduce the cost of decryption,
// so it's not a bad idea to read the original property every time, it's generally fast.
Object originValue = delegate.getProperty(name);
if (!(originValue instanceof String)) {
//Because we read the original property every time, if it isn't a String,
// there's no point in caching it.
return originValue;
}

CachedValue cachedValue = cache.get(name);
if (cachedValue != null && Objects.equals(originValue, cachedValue.originValue)) {
// If the original property has not changed, it is safe to return the cached result.
return cachedValue.resolvedValue;
}
synchronized (name.intern()) {
if (!cache.containsKey(name)) {
Object resolved = getProperty(resolver, filter, delegate, name);
if (resolved != null) {
cache.put(name, resolved);
}

//originValue must be String here
if (filter.shouldInclude(delegate, name)) {
String originStringValue = (String) originValue;
String resolved = resolver.resolvePropertyValue(originStringValue);
CachedValue newCachedValue = new CachedValue(originStringValue, resolved);
//If the mapping relationship in the cache changes during
// the calculation process, then ignore it directly.
if (cachedValue == null) {
cache.putIfAbsent(name, newCachedValue);
} else {
cache.replace(name, cachedValue, newCachedValue);
}
return cache.get(name);
//return the result calculated this time
return resolved;
}
return originValue;
}

@Override
public void refresh() {
log.info("Property Source {} refreshed", delegate.getName());
cache.clear();
}

@AllArgsConstructor
private static class CachedValue {
private final String originValue;
private final String resolvedValue;
}
}

0 comments on commit f4bd311

Please sign in to comment.