Skip to content

Commit 983af78

Browse files
committed
Configurable limit on HandlerMappingIntrospector
Closes gh-34918
1 parent 67ed64a commit 983af78

File tree

2 files changed

+34
-9
lines changed

2 files changed

+34
-9
lines changed

spring-webmvc/src/main/java/org/springframework/web/servlet/handler/HandlerMappingIntrospector.java

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2024 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -99,6 +99,8 @@ public class HandlerMappingIntrospector
9999
private static final String CACHED_RESULT_ATTRIBUTE =
100100
HandlerMappingIntrospector.class.getName() + ".CachedResult";
101101

102+
private static final int DEFAULT_CACHE_LIMIT = 2048;
103+
102104

103105
@Nullable
104106
private ApplicationContext applicationContext;
@@ -108,9 +110,30 @@ public class HandlerMappingIntrospector
108110

109111
private Map<HandlerMapping, PathPatternMatchableHandlerMapping> pathPatternMappings = Collections.emptyMap();
110112

113+
private int patternCacheLimit = DEFAULT_CACHE_LIMIT;
114+
111115
private final CacheResultLogHelper cacheLogHelper = new CacheResultLogHelper();
112116

113117

118+
/**
119+
* Set a limit on the maximum number of security patterns passed into
120+
* {@link MatchableHandlerMapping#match} at runtime to cache.
121+
* <p>By default, this is set to 2048.
122+
* @param patternCacheLimit the limit to use
123+
* @since 6.2.8
124+
*/
125+
public void setPatternCacheLimit(int patternCacheLimit) {
126+
this.patternCacheLimit = patternCacheLimit;
127+
}
128+
129+
/**
130+
* Return the configured limit on security patterns to cache.
131+
* @since 6.2.8
132+
*/
133+
public int getPatternCacheLimit() {
134+
return this.patternCacheLimit;
135+
}
136+
114137
@Override
115138
public void setApplicationContext(ApplicationContext applicationContext) {
116139
this.applicationContext = applicationContext;
@@ -124,8 +147,9 @@ public void afterPropertiesSet() {
124147

125148
this.pathPatternMappings = this.handlerMappings.stream()
126149
.filter(m -> m instanceof MatchableHandlerMapping hm && hm.getPatternParser() != null)
127-
.map(mapping -> (MatchableHandlerMapping) mapping)
128-
.collect(Collectors.toMap(mapping -> mapping, PathPatternMatchableHandlerMapping::new));
150+
.map(hm -> (MatchableHandlerMapping) hm)
151+
.collect(Collectors.toMap(hm -> hm, (MatchableHandlerMapping delegate) ->
152+
new PathPatternMatchableHandlerMapping(delegate, getPatternCacheLimit())));
129153
}
130154
}
131155

spring-webmvc/src/main/java/org/springframework/web/servlet/handler/PathPatternMatchableHandlerMapping.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 the original author or authors.
2+
* Copyright 2002-2025 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -39,28 +39,29 @@
3939
*/
4040
class PathPatternMatchableHandlerMapping implements MatchableHandlerMapping {
4141

42-
private static final int MAX_PATTERNS = 1024;
43-
44-
4542
private final MatchableHandlerMapping delegate;
4643

4744
private final PathPatternParser parser;
4845

4946
private final Map<String, PathPattern> pathPatternCache = new ConcurrentHashMap<>();
5047

48+
private final int cacheLimit;
5149

52-
public PathPatternMatchableHandlerMapping(MatchableHandlerMapping delegate) {
50+
51+
public PathPatternMatchableHandlerMapping(MatchableHandlerMapping delegate, int cacheLimit) {
5352
Assert.notNull(delegate, "HandlerMapping to delegate to is required.");
5453
Assert.notNull(delegate.getPatternParser(), "Expected HandlerMapping configured to use PatternParser.");
5554
this.delegate = delegate;
5655
this.parser = delegate.getPatternParser();
56+
this.cacheLimit = cacheLimit;
5757
}
5858

59+
5960
@Nullable
6061
@Override
6162
public RequestMatchResult match(HttpServletRequest request, String pattern) {
6263
PathPattern pathPattern = this.pathPatternCache.computeIfAbsent(pattern, value -> {
63-
Assert.state(this.pathPatternCache.size() < MAX_PATTERNS, "Max size for pattern cache exceeded.");
64+
Assert.state(this.pathPatternCache.size() < this.cacheLimit, "Max size for pattern cache exceeded.");
6465
return this.parser.parse(pattern);
6566
});
6667
PathContainer path = ServletRequestPathUtils.getParsedRequestPath(request).pathWithinApplication();

0 commit comments

Comments
 (0)