Skip to content

Commit bb7a137

Browse files
committed
Avoid unnecessary getMappingForMethod repeat (in particular for RequestMappingInfo)
Issue. SPR-11428 (cherry picked from commit f913940)
1 parent 7e3c722 commit bb7a137

File tree

1 file changed

+33
-31
lines changed

1 file changed

+33
-31
lines changed

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

Lines changed: 33 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2012 the original author or authors.
2+
* Copyright 2002-2014 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.
@@ -21,11 +21,11 @@
2121
import java.util.Collection;
2222
import java.util.Collections;
2323
import java.util.Comparator;
24+
import java.util.IdentityHashMap;
2425
import java.util.LinkedHashMap;
2526
import java.util.List;
2627
import java.util.Map;
2728
import java.util.Set;
28-
2929
import javax.servlet.ServletException;
3030
import javax.servlet.http.HttpServletRequest;
3131

@@ -118,32 +118,33 @@ protected void initHandlerMethods() {
118118
*/
119119
protected abstract boolean isHandler(Class<?> beanType);
120120

121-
/**
122-
* Invoked after all handler methods have been detected.
123-
* @param handlerMethods a read-only map with handler methods and mappings.
124-
*/
125-
protected void handlerMethodsInitialized(Map<T, HandlerMethod> handlerMethods) {
126-
}
127-
128121
/**
129122
* Look for handler methods in a handler.
130123
* @param handler the bean name of a handler or a handler instance
131124
*/
132125
protected void detectHandlerMethods(final Object handler) {
133-
Class<?> handlerType = (handler instanceof String) ?
134-
getApplicationContext().getType((String) handler) : handler.getClass();
126+
Class<?> handlerType =
127+
(handler instanceof String ? getApplicationContext().getType((String) handler) : handler.getClass());
135128

129+
// Avoid repeated calls to getMappingForMethod which would rebuild RequestMatchingInfo instances
130+
final Map<Method, T> mappings = new IdentityHashMap<Method, T>();
136131
final Class<?> userType = ClassUtils.getUserClass(handlerType);
137132

138133
Set<Method> methods = HandlerMethodSelector.selectMethods(userType, new MethodFilter() {
139134
public boolean matches(Method method) {
140-
return getMappingForMethod(method, userType) != null;
135+
T mapping = getMappingForMethod(method, userType);
136+
if (mapping != null) {
137+
mappings.put(method, mapping);
138+
return true;
139+
}
140+
else {
141+
return false;
142+
}
141143
}
142144
});
143145

144146
for (Method method : methods) {
145-
T mapping = getMappingForMethod(method, userType);
146-
registerHandlerMethod(handler, method, mapping);
147+
registerHandlerMethod(handler, method, mappings.get(method));
147148
}
148149
}
149150

@@ -167,11 +168,11 @@ public boolean matches(Method method) {
167168
*/
168169
protected void registerHandlerMethod(Object handler, Method method, T mapping) {
169170
HandlerMethod newHandlerMethod = createHandlerMethod(handler, method);
170-
HandlerMethod oldHandlerMethod = handlerMethods.get(mapping);
171+
HandlerMethod oldHandlerMethod = this.handlerMethods.get(mapping);
171172
if (oldHandlerMethod != null && !oldHandlerMethod.equals(newHandlerMethod)) {
172-
throw new IllegalStateException("Ambiguous mapping found. Cannot map '" + newHandlerMethod.getBean()
173-
+ "' bean method \n" + newHandlerMethod + "\nto " + mapping + ": There is already '"
174-
+ oldHandlerMethod.getBean() + "' bean method\n" + oldHandlerMethod + " mapped.");
173+
throw new IllegalStateException("Ambiguous mapping found. Cannot map '" + newHandlerMethod.getBean() +
174+
"' bean method \n" + newHandlerMethod + "\nto " + mapping + ": There is already '" +
175+
oldHandlerMethod.getBean() + "' bean method\n" + oldHandlerMethod + " mapped.");
175176
}
176177

177178
this.handlerMethods.put(mapping, newHandlerMethod);
@@ -210,6 +211,14 @@ protected HandlerMethod createHandlerMethod(Object handler, Method method) {
210211
*/
211212
protected abstract Set<String> getMappingPathPatterns(T mapping);
212213

214+
/**
215+
* Invoked after all handler methods have been detected.
216+
* @param handlerMethods a read-only map with handler methods and mappings.
217+
*/
218+
protected void handlerMethodsInitialized(Map<T, HandlerMethod> handlerMethods) {
219+
}
220+
221+
213222
/**
214223
* Look up a handler method for the given request.
215224
*/
@@ -219,9 +228,7 @@ protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Ex
219228
if (logger.isDebugEnabled()) {
220229
logger.debug("Looking up handler method for path " + lookupPath);
221230
}
222-
223231
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
224-
225232
if (logger.isDebugEnabled()) {
226233
if (handlerMethod != null) {
227234
logger.debug("Returning handler method [" + handlerMethod + "]");
@@ -230,8 +237,7 @@ protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Ex
230237
logger.debug("Did not find handler method for [" + lookupPath + "]");
231238
}
232239
}
233-
234-
return (handlerMethod != null) ? handlerMethod.createWithResolvedBean() : null;
240+
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
235241
}
236242

237243
/**
@@ -245,25 +251,21 @@ protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Ex
245251
*/
246252
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
247253
List<Match> matches = new ArrayList<Match>();
248-
249254
List<T> directPathMatches = this.urlMap.get(lookupPath);
250255
if (directPathMatches != null) {
251256
addMatchingMappings(directPathMatches, matches, request);
252257
}
253-
254258
if (matches.isEmpty()) {
255-
// No choice but to go through all mappings
259+
// No choice but to go through all mappings...
256260
addMatchingMappings(this.handlerMethods.keySet(), matches, request);
257261
}
258262

259263
if (!matches.isEmpty()) {
260264
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
261265
Collections.sort(matches, comparator);
262-
263266
if (logger.isTraceEnabled()) {
264267
logger.trace("Found " + matches.size() + " matching mapping(s) for [" + lookupPath + "] : " + matches);
265268
}
266-
267269
Match bestMatch = matches.get(0);
268270
if (matches.size() > 1) {
269271
Match secondBestMatch = matches.get(1);
@@ -275,7 +277,6 @@ protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletReques
275277
m1 + ", " + m2 + "}");
276278
}
277279
}
278-
279280
handleMatch(bestMatch.mapping, lookupPath, request);
280281
return bestMatch.handlerMethod;
281282
}
@@ -288,7 +289,7 @@ private void addMatchingMappings(Collection<T> mappings, List<Match> matches, Ht
288289
for (T mapping : mappings) {
289290
T match = getMatchingMapping(mapping, request);
290291
if (match != null) {
291-
matches.add(new Match(match, handlerMethods.get(mapping)));
292+
matches.add(new Match(match, this.handlerMethods.get(mapping)));
292293
}
293294
}
294295
}
@@ -335,15 +336,16 @@ protected HandlerMethod handleNoMatch(Set<T> mappings, String lookupPath, HttpSe
335336

336337

337338
/**
338-
* A temporary container for a mapping matched to a request.
339+
* A thin wrapper around a matched HandlerMethod and its mapping, for the purpose of
340+
* comparing the best match with a comparator in the context of the current request.
339341
*/
340342
private class Match {
341343

342344
private final T mapping;
343345

344346
private final HandlerMethod handlerMethod;
345347

346-
private Match(T mapping, HandlerMethod handlerMethod) {
348+
public Match(T mapping, HandlerMethod handlerMethod) {
347349
this.mapping = mapping;
348350
this.handlerMethod = handlerMethod;
349351
}

0 commit comments

Comments
 (0)