Threadsafe use of pattern parser in ParsingPathMatcher

This commit ensures that the `PathPatternParser` and the associated
cache map are used in a threadsafe fashion, since the PathMatcher
instance can be used for concurrent requests.

Issue: SPR-15246
This commit is contained in:
Brian Clozel
2017-02-13 14:12:30 +01:00
parent ef550c43d6
commit 2ac08afab5

View File

@@ -17,8 +17,9 @@
package org.springframework.web.util;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.springframework.util.PathMatcher;
import org.springframework.web.util.patterns.PathPattern;
@@ -39,13 +40,11 @@ import org.springframework.web.util.patterns.PatternComparatorConsideringPath;
*/
public class ParsingPathMatcher implements PathMatcher {
Map<String, PathPattern> cache = new HashMap<>();
private final ConcurrentMap<String, PathPattern> cache =
new ConcurrentHashMap<>(64);
PathPatternParser parser;
public ParsingPathMatcher() {
parser = new PathPatternParser();
}
private static final ThreadLocal<PathPatternParser> PARSER
= ThreadLocal.withInitial(() -> new PathPatternParser());
@Override
public boolean match(String pattern, String path) {
@@ -84,10 +83,10 @@ public class ParsingPathMatcher implements PathMatcher {
class PathPatternStringComparatorConsideringPath implements Comparator<String> {
PatternComparatorConsideringPath ppcp;
private final PatternComparatorConsideringPath ppcp;
public PathPatternStringComparatorConsideringPath(String path) {
ppcp = new PatternComparatorConsideringPath(path);
this.ppcp = new PatternComparatorConsideringPath(path);
}
@Override
@@ -100,7 +99,7 @@ public class ParsingPathMatcher implements PathMatcher {
}
PathPattern p1 = getPathPattern(o1);
PathPattern p2 = getPathPattern(o2);
return ppcp.compare(p1, p2);
return this.ppcp.compare(p1, p2);
}
}
@@ -112,10 +111,10 @@ public class ParsingPathMatcher implements PathMatcher {
}
private PathPattern getPathPattern(String pattern) {
PathPattern pathPattern = cache.get(pattern);
PathPattern pathPattern = this.cache.get(pattern);
if (pathPattern == null) {
pathPattern = parser.parse(pattern);
cache.put(pattern, pathPattern);
pathPattern = PARSER.get().parse(pattern);
this.cache.put(pattern, pathPattern);
}
return pathPattern;
}