Added cache for path pattern tokenization

Issue: SPR-11258
This commit is contained in:
Juergen Hoeller 2014-01-03 17:33:46 +01:00
parent 240819f955
commit ff26dfdd28
1 changed files with 55 additions and 11 deletions

View File

@ -50,13 +50,13 @@ import java.util.regex.Pattern;
*/ */
public class AntPathMatcher implements PathMatcher { public class AntPathMatcher implements PathMatcher {
/** Default path separator: "/" */
public static final String DEFAULT_PATH_SEPARATOR = "/";
private static final int CACHE_TURNOFF_THRESHOLD = 65536; private static final int CACHE_TURNOFF_THRESHOLD = 65536;
private static final Pattern VARIABLE_PATTERN = Pattern.compile("\\{[^/]+?\\}"); private static final Pattern VARIABLE_PATTERN = Pattern.compile("\\{[^/]+?\\}");
/** Default path separator: "/" */
public static final String DEFAULT_PATH_SEPARATOR = "/";
private String pathSeparator = DEFAULT_PATH_SEPARATOR; private String pathSeparator = DEFAULT_PATH_SEPARATOR;
@ -64,8 +64,9 @@ public class AntPathMatcher implements PathMatcher {
private volatile Boolean cachePatterns; private volatile Boolean cachePatterns;
final Map<String, AntPathStringMatcher> stringMatcherCache = private final Map<String, String[]> tokenizedPatternCache = new ConcurrentHashMap<String, String[]>(256);
new ConcurrentHashMap<String, AntPathStringMatcher>(256);
final Map<String, AntPathStringMatcher> stringMatcherCache = new ConcurrentHashMap<String, AntPathStringMatcher>(256);
/** /**
@ -99,6 +100,12 @@ public class AntPathMatcher implements PathMatcher {
this.cachePatterns = cachePatterns; this.cachePatterns = cachePatterns;
} }
private void deactivatePatternCache() {
this.cachePatterns = false;
this.tokenizedPatternCache.clear();
this.stringMatcherCache.clear();
}
@Override @Override
public boolean isPattern(String path) { public boolean isPattern(String path) {
@ -128,8 +135,8 @@ public class AntPathMatcher implements PathMatcher {
return false; return false;
} }
String[] pattDirs = StringUtils.tokenizeToStringArray(pattern, this.pathSeparator, this.trimTokens, true); String[] pattDirs = tokenizePattern(pattern);
String[] pathDirs = StringUtils.tokenizeToStringArray(path, this.pathSeparator, this.trimTokens, true); String[] pathDirs = tokenizePath(path);
int pattIdxStart = 0; int pattIdxStart = 0;
int pattIdxEnd = pattDirs.length - 1; int pattIdxEnd = pattDirs.length - 1;
@ -248,6 +255,44 @@ public class AntPathMatcher implements PathMatcher {
return true; return true;
} }
/**
* Tokenize the given path pattern into parts, based on this matcher's settings.
* <p>Performs caching based on {@link #setCachePatterns}, delegating to
* {@link #tokenizePath(String)} for the actual tokenization algorithm.
* @param pattern the pattern to tokenize
* @return the tokenized pattern parts
*/
protected String[] tokenizePattern(String pattern) {
String[] tokenized = null;
Boolean cachePatterns = this.cachePatterns;
if (cachePatterns == null || cachePatterns.booleanValue()) {
tokenized = this.tokenizedPatternCache.get(pattern);
}
if (tokenized == null) {
tokenized = tokenizePath(pattern);
if (cachePatterns == null && this.tokenizedPatternCache.size() >= CACHE_TURNOFF_THRESHOLD) {
// Try to adapt to the runtime situation that we're encountering:
// There are obviously too many different patterns coming in here...
// So let's turn off the cache since the patterns are unlikely to be reoccurring.
deactivatePatternCache();
return tokenized;
}
if (cachePatterns == null || cachePatterns.booleanValue()) {
this.tokenizedPatternCache.put(pattern, tokenized);
}
}
return tokenized;
}
/**
* Tokenize the given path String into parts, based on this matcher's settings.
* @param path the path to tokenize
* @return the tokenized path parts
*/
protected String[] tokenizePath(String path) {
return StringUtils.tokenizeToStringArray(path, this.pathSeparator, this.trimTokens, true);
}
/** /**
* Tests whether or not a string matches against a pattern. * Tests whether or not a string matches against a pattern.
* @param pattern the pattern to match against (never {@code null}) * @param pattern the pattern to match against (never {@code null})
@ -281,10 +326,9 @@ public class AntPathMatcher implements PathMatcher {
matcher = new AntPathStringMatcher(pattern); matcher = new AntPathStringMatcher(pattern);
if (cachePatterns == null && this.stringMatcherCache.size() >= CACHE_TURNOFF_THRESHOLD) { if (cachePatterns == null && this.stringMatcherCache.size() >= CACHE_TURNOFF_THRESHOLD) {
// Try to adapt to the runtime situation that we're encountering: // Try to adapt to the runtime situation that we're encountering:
// There are obviously too many different paths coming in here... // There are obviously too many different patterns coming in here...
// So let's turn off the cache since the patterns are unlikely to be reoccurring. // So let's turn off the cache since the patterns are unlikely to be reoccurring.
this.cachePatterns = false; deactivatePatternCache();
this.stringMatcherCache.clear();
return matcher; return matcher;
} }
if (cachePatterns == null || cachePatterns.booleanValue()) { if (cachePatterns == null || cachePatterns.booleanValue()) {