Browse Source

Avoid unnecessary getMappingForMethod repeat (in particular for RequestMappingInfo)

Issue. SPR-11428
(cherry picked from commit f913940)
pull/465/head
Juergen Hoeller 12 years ago
parent
commit
bb7a1372c0
  1. 64
      spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMethodMapping.java

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

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2012 the original author or authors. * Copyright 2002-2014 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -21,11 +21,11 @@ import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.IdentityHashMap;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@ -118,32 +118,33 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
*/ */
protected abstract boolean isHandler(Class<?> beanType); protected abstract boolean isHandler(Class<?> beanType);
/**
* Invoked after all handler methods have been detected.
* @param handlerMethods a read-only map with handler methods and mappings.
*/
protected void handlerMethodsInitialized(Map<T, HandlerMethod> handlerMethods) {
}
/** /**
* Look for handler methods in a handler. * Look for handler methods in a handler.
* @param handler the bean name of a handler or a handler instance * @param handler the bean name of a handler or a handler instance
*/ */
protected void detectHandlerMethods(final Object handler) { protected void detectHandlerMethods(final Object handler) {
Class<?> handlerType = (handler instanceof String) ? Class<?> handlerType =
getApplicationContext().getType((String) handler) : handler.getClass(); (handler instanceof String ? getApplicationContext().getType((String) handler) : handler.getClass());
// Avoid repeated calls to getMappingForMethod which would rebuild RequestMatchingInfo instances
final Map<Method, T> mappings = new IdentityHashMap<Method, T>();
final Class<?> userType = ClassUtils.getUserClass(handlerType); final Class<?> userType = ClassUtils.getUserClass(handlerType);
Set<Method> methods = HandlerMethodSelector.selectMethods(userType, new MethodFilter() { Set<Method> methods = HandlerMethodSelector.selectMethods(userType, new MethodFilter() {
public boolean matches(Method method) { public boolean matches(Method method) {
return getMappingForMethod(method, userType) != null; T mapping = getMappingForMethod(method, userType);
if (mapping != null) {
mappings.put(method, mapping);
return true;
}
else {
return false;
}
} }
}); });
for (Method method : methods) { for (Method method : methods) {
T mapping = getMappingForMethod(method, userType); registerHandlerMethod(handler, method, mappings.get(method));
registerHandlerMethod(handler, method, mapping);
} }
} }
@ -167,11 +168,11 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
*/ */
protected void registerHandlerMethod(Object handler, Method method, T mapping) { protected void registerHandlerMethod(Object handler, Method method, T mapping) {
HandlerMethod newHandlerMethod = createHandlerMethod(handler, method); HandlerMethod newHandlerMethod = createHandlerMethod(handler, method);
HandlerMethod oldHandlerMethod = handlerMethods.get(mapping); HandlerMethod oldHandlerMethod = this.handlerMethods.get(mapping);
if (oldHandlerMethod != null && !oldHandlerMethod.equals(newHandlerMethod)) { if (oldHandlerMethod != null && !oldHandlerMethod.equals(newHandlerMethod)) {
throw new IllegalStateException("Ambiguous mapping found. Cannot map '" + newHandlerMethod.getBean() throw new IllegalStateException("Ambiguous mapping found. Cannot map '" + newHandlerMethod.getBean() +
+ "' bean method \n" + newHandlerMethod + "\nto " + mapping + ": There is already '" "' bean method \n" + newHandlerMethod + "\nto " + mapping + ": There is already '" +
+ oldHandlerMethod.getBean() + "' bean method\n" + oldHandlerMethod + " mapped."); oldHandlerMethod.getBean() + "' bean method\n" + oldHandlerMethod + " mapped.");
} }
this.handlerMethods.put(mapping, newHandlerMethod); this.handlerMethods.put(mapping, newHandlerMethod);
@ -210,6 +211,14 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
*/ */
protected abstract Set<String> getMappingPathPatterns(T mapping); protected abstract Set<String> getMappingPathPatterns(T mapping);
/**
* Invoked after all handler methods have been detected.
* @param handlerMethods a read-only map with handler methods and mappings.
*/
protected void handlerMethodsInitialized(Map<T, HandlerMethod> handlerMethods) {
}
/** /**
* Look up a handler method for the given request. * Look up a handler method for the given request.
*/ */
@ -219,9 +228,7 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("Looking up handler method for path " + lookupPath); logger.debug("Looking up handler method for path " + lookupPath);
} }
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request); HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
if (handlerMethod != null) { if (handlerMethod != null) {
logger.debug("Returning handler method [" + handlerMethod + "]"); logger.debug("Returning handler method [" + handlerMethod + "]");
@ -230,8 +237,7 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
logger.debug("Did not find handler method for [" + lookupPath + "]"); logger.debug("Did not find handler method for [" + lookupPath + "]");
} }
} }
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
return (handlerMethod != null) ? handlerMethod.createWithResolvedBean() : null;
} }
/** /**
@ -245,25 +251,21 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
*/ */
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception { protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<Match>(); List<Match> matches = new ArrayList<Match>();
List<T> directPathMatches = this.urlMap.get(lookupPath); List<T> directPathMatches = this.urlMap.get(lookupPath);
if (directPathMatches != null) { if (directPathMatches != null) {
addMatchingMappings(directPathMatches, matches, request); addMatchingMappings(directPathMatches, matches, request);
} }
if (matches.isEmpty()) { if (matches.isEmpty()) {
// No choice but to go through all mappings // No choice but to go through all mappings...
addMatchingMappings(this.handlerMethods.keySet(), matches, request); addMatchingMappings(this.handlerMethods.keySet(), matches, request);
} }
if (!matches.isEmpty()) { if (!matches.isEmpty()) {
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request)); Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
Collections.sort(matches, comparator); Collections.sort(matches, comparator);
if (logger.isTraceEnabled()) { if (logger.isTraceEnabled()) {
logger.trace("Found " + matches.size() + " matching mapping(s) for [" + lookupPath + "] : " + matches); logger.trace("Found " + matches.size() + " matching mapping(s) for [" + lookupPath + "] : " + matches);
} }
Match bestMatch = matches.get(0); Match bestMatch = matches.get(0);
if (matches.size() > 1) { if (matches.size() > 1) {
Match secondBestMatch = matches.get(1); Match secondBestMatch = matches.get(1);
@ -275,7 +277,6 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
m1 + ", " + m2 + "}"); m1 + ", " + m2 + "}");
} }
} }
handleMatch(bestMatch.mapping, lookupPath, request); handleMatch(bestMatch.mapping, lookupPath, request);
return bestMatch.handlerMethod; return bestMatch.handlerMethod;
} }
@ -288,7 +289,7 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
for (T mapping : mappings) { for (T mapping : mappings) {
T match = getMatchingMapping(mapping, request); T match = getMatchingMapping(mapping, request);
if (match != null) { if (match != null) {
matches.add(new Match(match, handlerMethods.get(mapping))); matches.add(new Match(match, this.handlerMethods.get(mapping)));
} }
} }
} }
@ -335,7 +336,8 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
/** /**
* A temporary container for a mapping matched to a request. * A thin wrapper around a matched HandlerMethod and its mapping, for the purpose of
* comparing the best match with a comparator in the context of the current request.
*/ */
private class Match { private class Match {
@ -343,7 +345,7 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
private final HandlerMethod handlerMethod; private final HandlerMethod handlerMethod;
private Match(T mapping, HandlerMethod handlerMethod) { public Match(T mapping, HandlerMethod handlerMethod) {
this.mapping = mapping; this.mapping = mapping;
this.handlerMethod = handlerMethod; this.handlerMethod = handlerMethod;
} }

Loading…
Cancel
Save