Optimized access to resolved bean type (avoiding BeanFactory locks)

Revised HandlerMethod.getBeanType() impl for both web and messaging.
In addition, HandlerMethods get created with the internal BeanFactory now.

Issue: SPR-12832
(cherry picked from commit 898c24f)
This commit is contained in:
Juergen Hoeller 2015-03-20 17:35:44 +01:00
parent 4446b5fe8a
commit 5f95ff6bfd
4 changed files with 100 additions and 93 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2014 the original author or authors. * Copyright 2002-2015 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.
@ -30,26 +30,30 @@ import org.springframework.util.Assert;
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
/** /**
* Encapsulates information about a bean method consisting of a {@link #getMethod() method} * Encapsulates information about a handler method consisting of a
* and a {@link #getBean() bean}. Provides convenient access to method parameters, * {@linkplain #getMethod() method} and a {@linkplain #getBean() bean}.
* method return value, method annotations. * Provides convenient access to method parameters, method return value, method annotations.
* *
* <p>The class may be created with a bean instance or with a bean name (e.g. lazy bean, * <p>The class may be created with a bean instance or with a bean name (e.g. lazy-init bean,
* prototype bean). Use {@link #createWithResolvedBean()} to obtain an {@link HandlerMethod} * prototype bean). Use {@link #createWithResolvedBean()} to obtain a {@link HandlerMethod}
* instance with a bean instance initialized through the bean factory. * instance with a bean instance resolved through the associated {@link BeanFactory}.
* *
* @author Arjen Poutsma * @author Arjen Poutsma
* @author Rossen Stoyanchev * @author Rossen Stoyanchev
* @author Juergen Hoeller
* @since 4.0 * @since 4.0
*/ */
public class HandlerMethod { public class HandlerMethod {
protected final Log logger = LogFactory.getLog(HandlerMethod.class); /** Logger that is available to subclasses */
protected final Log logger = LogFactory.getLog(getClass());
private final Object bean; private final Object bean;
private final BeanFactory beanFactory; private final BeanFactory beanFactory;
private final Class<?> beanType;
private final Method method; private final Method method;
private final Method bridgedMethod; private final Method bridgedMethod;
@ -65,6 +69,7 @@ public class HandlerMethod {
Assert.notNull(method, "Method is required"); Assert.notNull(method, "Method is required");
this.bean = bean; this.bean = bean;
this.beanFactory = null; this.beanFactory = null;
this.beanType = ClassUtils.getUserClass(bean);
this.method = method; this.method = method;
this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(method); this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
this.parameters = initMethodParameters(); this.parameters = initMethodParameters();
@ -79,6 +84,7 @@ public class HandlerMethod {
Assert.notNull(methodName, "Method name is required"); Assert.notNull(methodName, "Method name is required");
this.bean = bean; this.bean = bean;
this.beanFactory = null; this.beanFactory = null;
this.beanType = ClassUtils.getUserClass(bean);
this.method = bean.getClass().getMethod(methodName, parameterTypes); this.method = bean.getClass().getMethod(methodName, parameterTypes);
this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(this.method); this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(this.method);
this.parameters = initMethodParameters(); this.parameters = initMethodParameters();
@ -93,22 +99,22 @@ public class HandlerMethod {
Assert.hasText(beanName, "Bean name is required"); Assert.hasText(beanName, "Bean name is required");
Assert.notNull(beanFactory, "BeanFactory is required"); Assert.notNull(beanFactory, "BeanFactory is required");
Assert.notNull(method, "Method is required"); Assert.notNull(method, "Method is required");
Assert.isTrue(beanFactory.containsBean(beanName),
"BeanFactory [" + beanFactory + "] does not contain bean [" + beanName + "]");
this.bean = beanName; this.bean = beanName;
this.beanFactory = beanFactory; this.beanFactory = beanFactory;
this.beanType = ClassUtils.getUserClass(beanFactory.getType(beanName));
this.method = method; this.method = method;
this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(method); this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
this.parameters = initMethodParameters(); this.parameters = initMethodParameters();
} }
/** /**
* Copy constructor for use in sub-classes. * Copy constructor for use in subclasses.
*/ */
protected HandlerMethod(HandlerMethod handlerMethod) { protected HandlerMethod(HandlerMethod handlerMethod) {
Assert.notNull(handlerMethod, "HandlerMethod is required"); Assert.notNull(handlerMethod, "HandlerMethod is required");
this.bean = handlerMethod.bean; this.bean = handlerMethod.bean;
this.beanFactory = handlerMethod.beanFactory; this.beanFactory = handlerMethod.beanFactory;
this.beanType = handlerMethod.beanType;
this.method = handlerMethod.method; this.method = handlerMethod.method;
this.bridgedMethod = handlerMethod.bridgedMethod; this.bridgedMethod = handlerMethod.bridgedMethod;
this.parameters = handlerMethod.parameters; this.parameters = handlerMethod.parameters;
@ -122,6 +128,7 @@ public class HandlerMethod {
Assert.notNull(handler, "Handler object is required"); Assert.notNull(handler, "Handler object is required");
this.bean = handler; this.bean = handler;
this.beanFactory = handlerMethod.beanFactory; this.beanFactory = handlerMethod.beanFactory;
this.beanType = handlerMethod.beanType;
this.method = handlerMethod.method; this.method = handlerMethod.method;
this.bridgedMethod = handlerMethod.bridgedMethod; this.bridgedMethod = handlerMethod.bridgedMethod;
this.parameters = handlerMethod.parameters; this.parameters = handlerMethod.parameters;
@ -152,18 +159,17 @@ public class HandlerMethod {
} }
/** /**
* Returns the type of the handler for this handler method. * This method returns the type of the handler for this handler method.
* Note that if the bean type is a CGLIB-generated class, the original, user-defined class is returned. * <p>Note that if the bean type is a CGLIB-generated class, the original
* user-defined class is returned.
*/ */
public Class<?> getBeanType() { public Class<?> getBeanType() {
Class<?> clazz = (this.bean instanceof String ? return this.beanType;
this.beanFactory.getType((String) this.bean) : this.bean.getClass());
return ClassUtils.getUserClass(clazz);
} }
/** /**
* If the bean method is a bridge method, this method returns the bridged (user-defined) method. * If the bean method is a bridge method, this method returns the bridged
* Otherwise it returns the same method as {@link #getMethod()}. * (user-defined) method. Otherwise it returns the same method as {@link #getMethod()}.
*/ */
protected Method getBridgedMethod() { protected Method getBridgedMethod() {
return this.bridgedMethod; return this.bridgedMethod;
@ -198,8 +204,8 @@ public class HandlerMethod {
} }
/** /**
* Returns a single annotation on the underlying method traversing its super methods if no * Returns a single annotation on the underlying method traversing its super methods
* annotation can be found on the given method itself. * if no annotation can be found on the given method itself.
* @param annotationType the type of annotation to introspect the method for. * @param annotationType the type of annotation to introspect the method for.
* @return the annotation, or {@code null} if none found * @return the annotation, or {@code null} if none found
*/ */
@ -208,8 +214,8 @@ public class HandlerMethod {
} }
/** /**
* If the provided instance contains a bean name rather than an object instance, the bean name is resolved * If the provided instance contains a bean name rather than an object instance,
* before a {@link HandlerMethod} is created and returned. * the bean name is resolved before a {@link HandlerMethod} is created and returned.
*/ */
public HandlerMethod createWithResolvedBean() { public HandlerMethod createWithResolvedBean() {
Object handler = this.bean; Object handler = this.bean;
@ -220,26 +226,27 @@ public class HandlerMethod {
return new HandlerMethod(this, handler); return new HandlerMethod(this, handler);
} }
public String getShortLogMessage() {
int args = this.method.getParameterTypes().length;
return getBeanType().getName() + "#" + this.method.getName() + "[" + args + " args]";
}
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object other) {
if (this == obj) { if (this == other) {
return true; return true;
} }
if (obj != null && obj instanceof HandlerMethod) { if (!(other instanceof HandlerMethod)) {
HandlerMethod other = (HandlerMethod) obj;
return this.bean.equals(other.bean) && this.method.equals(other.method);
}
return false; return false;
} }
HandlerMethod otherMethod = (HandlerMethod) other;
return (this.bean.equals(otherMethod.bean) && this.method.equals(otherMethod.method));
}
@Override @Override
public int hashCode() { public int hashCode() {
return this.bean.hashCode() * 31 + this.method.hashCode(); return (this.bean.hashCode() * 31 + this.method.hashCode());
}
public String getShortLogMessage() {
int args = method.getParameterTypes().length;
return getBeanType().getName() + "#" + this.method.getName() + "[" + args + " args]";
} }
@Override @Override

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2014 the original author or authors. * Copyright 2002-2015 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.
@ -30,7 +30,6 @@ import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware; import org.springframework.context.ApplicationContextAware;
@ -154,7 +153,7 @@ public abstract class AbstractMethodMessageHandler<T>
/** /**
* Configure the complete list of supported argument types effectively overriding * Configure the complete list of supported argument types effectively overriding
* the ones configured by default. This is an advanced option. For most use cases * the ones configured by default. This is an advanced option. For most use cases
* it should be sufficient to use {@link #setCustomArgumentResolvers(java.util.List)}. * it should be sufficient to use {@link #setCustomArgumentResolvers}.
*/ */
public void setArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) { public void setArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
if (argumentResolvers == null) { if (argumentResolvers == null) {
@ -171,7 +170,7 @@ public abstract class AbstractMethodMessageHandler<T>
/** /**
* Configure the complete list of supported return value types effectively overriding * Configure the complete list of supported return value types effectively overriding
* the ones configured by default. This is an advanced option. For most use cases * the ones configured by default. This is an advanced option. For most use cases
* it should be sufficient to use {@link #setCustomReturnValueHandlers(java.util.List)} * it should be sufficient to use {@link #setCustomReturnValueHandlers}.
*/ */
public void setReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) { public void setReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {
if (returnValueHandlers == null) { if (returnValueHandlers == null) {
@ -193,7 +192,7 @@ public abstract class AbstractMethodMessageHandler<T>
} }
@Override @Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext; this.applicationContext = applicationContext;
} }
@ -204,7 +203,6 @@ public abstract class AbstractMethodMessageHandler<T>
@Override @Override
public void afterPropertiesSet() { public void afterPropertiesSet() {
if (this.argumentResolvers.getResolvers().isEmpty()) { if (this.argumentResolvers.getResolvers().isEmpty()) {
this.argumentResolvers.addResolvers(initArgumentResolvers()); this.argumentResolvers.addResolvers(initArgumentResolvers());
} }
@ -222,17 +220,17 @@ public abstract class AbstractMethodMessageHandler<T>
/** /**
* Return the list of argument resolvers to use. Invoked only if the resolvers * Return the list of argument resolvers to use. Invoked only if the resolvers
* have not already been set via {@link #setArgumentResolvers(java.util.List)}. * have not already been set via {@link #setArgumentResolvers}.
* <p>Sub-classes should also take into account custom argument types configured via * <p>Subclasses should also take into account custom argument types configured via
* {@link #setCustomArgumentResolvers(java.util.List)}. * {@link #setCustomArgumentResolvers}.
*/ */
protected abstract List<? extends HandlerMethodArgumentResolver> initArgumentResolvers(); protected abstract List<? extends HandlerMethodArgumentResolver> initArgumentResolvers();
/** /**
* Return the list of return value handlers to use. Invoked only if the return * Return the list of return value handlers to use. Invoked only if the return
* value handlers have not already been set via {@link #setReturnValueHandlers(java.util.List)}. * value handlers have not already been set via {@link #setReturnValueHandlers}.
* <p>Sub-classes should also take into account custom return value types configured * <p>Subclasses should also take into account custom return value types configured
* via {@link #setCustomReturnValueHandlers(java.util.List)}. * via {@link #setCustomReturnValueHandlers}.
*/ */
protected abstract List<? extends HandlerMethodReturnValueHandler> initReturnValueHandlers(); protected abstract List<? extends HandlerMethodReturnValueHandler> initReturnValueHandlers();
@ -248,9 +246,8 @@ public abstract class AbstractMethodMessageHandler<T>
* @param handler the handler to check, either an instance of a Spring bean name * @param handler the handler to check, either an instance of a Spring bean name
*/ */
protected final void detectHandlerMethods(Object handler) { protected final void detectHandlerMethods(Object handler) {
Class<?> handlerType = (handler instanceof String ?
Class<?> handlerType = (handler instanceof String) ? this.applicationContext.getType((String) handler) : handler.getClass());
this.applicationContext.getType((String) handler) : handler.getClass();
final Class<?> userType = ClassUtils.getUserClass(handlerType); final Class<?> userType = ClassUtils.getUserClass(handlerType);
@ -285,14 +282,13 @@ public abstract class AbstractMethodMessageHandler<T>
* under the same mapping * under the same mapping
*/ */
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);
@ -313,7 +309,8 @@ public abstract class AbstractMethodMessageHandler<T>
HandlerMethod handlerMethod; HandlerMethod handlerMethod;
if (handler instanceof String) { if (handler instanceof String) {
String beanName = (String) handler; String beanName = (String) handler;
handlerMethod = new HandlerMethod(beanName, this.applicationContext, method); handlerMethod = new HandlerMethod(beanName,
this.applicationContext.getAutowireCapableBeanFactory(), method);
} }
else { else {
handlerMethod = new HandlerMethod(handler, method); handlerMethod = new HandlerMethod(handler, method);
@ -491,9 +488,8 @@ public abstract class AbstractMethodMessageHandler<T>
} }
this.returnValueHandlers.handleReturnValue(returnValue, returnType, message); this.returnValueHandlers.handleReturnValue(returnValue, returnType, message);
} }
catch (Throwable t) { catch (Throwable ex2) {
logger.error("Error while handling exception", t); logger.error("Error while processing handler method exception", ex2);
return;
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2014 the original author or authors. * Copyright 2002-2015 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.
@ -30,9 +30,9 @@ import org.springframework.util.Assert;
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
/** /**
* Encapsulates information about a handler method consisting of a {@linkplain #getMethod() method} * Encapsulates information about a handler method consisting of a
* and a {@linkplain #getBean() bean}. Provides convenient access to method parameters, * {@linkplain #getMethod() method} and a {@linkplain #getBean() bean}.
* method return value, method annotations. * Provides convenient access to method parameters, method return value, method annotations.
* *
* <p>The class may be created with a bean instance or with a bean name (e.g. lazy-init bean, * <p>The class may be created with a bean instance or with a bean name (e.g. lazy-init bean,
* prototype bean). Use {@link #createWithResolvedBean()} to obtain a {@link HandlerMethod} * prototype bean). Use {@link #createWithResolvedBean()} to obtain a {@link HandlerMethod}
@ -40,17 +40,20 @@ import org.springframework.util.ClassUtils;
* *
* @author Arjen Poutsma * @author Arjen Poutsma
* @author Rossen Stoyanchev * @author Rossen Stoyanchev
* @author Juergen Hoeller
* @since 3.1 * @since 3.1
*/ */
public class HandlerMethod { public class HandlerMethod {
/** Logger that is available to subclasses */ /** Logger that is available to subclasses */
protected final Log logger = LogFactory.getLog(HandlerMethod.class); protected final Log logger = LogFactory.getLog(getClass());
private final Object bean; private final Object bean;
private final BeanFactory beanFactory; private final BeanFactory beanFactory;
private final Class<?> beanType;
private final Method method; private final Method method;
private final Method bridgedMethod; private final Method bridgedMethod;
@ -66,6 +69,7 @@ public class HandlerMethod {
Assert.notNull(method, "Method is required"); Assert.notNull(method, "Method is required");
this.bean = bean; this.bean = bean;
this.beanFactory = null; this.beanFactory = null;
this.beanType = ClassUtils.getUserClass(bean);
this.method = method; this.method = method;
this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(method); this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
this.parameters = initMethodParameters(); this.parameters = initMethodParameters();
@ -80,6 +84,7 @@ public class HandlerMethod {
Assert.notNull(methodName, "Method name is required"); Assert.notNull(methodName, "Method name is required");
this.bean = bean; this.bean = bean;
this.beanFactory = null; this.beanFactory = null;
this.beanType = ClassUtils.getUserClass(bean);
this.method = bean.getClass().getMethod(methodName, parameterTypes); this.method = bean.getClass().getMethod(methodName, parameterTypes);
this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(this.method); this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(this.method);
this.parameters = initMethodParameters(); this.parameters = initMethodParameters();
@ -94,22 +99,22 @@ public class HandlerMethod {
Assert.hasText(beanName, "Bean name is required"); Assert.hasText(beanName, "Bean name is required");
Assert.notNull(beanFactory, "BeanFactory is required"); Assert.notNull(beanFactory, "BeanFactory is required");
Assert.notNull(method, "Method is required"); Assert.notNull(method, "Method is required");
Assert.isTrue(beanFactory.containsBean(beanName),
"BeanFactory [" + beanFactory + "] does not contain bean [" + beanName + "]");
this.bean = beanName; this.bean = beanName;
this.beanFactory = beanFactory; this.beanFactory = beanFactory;
this.beanType = ClassUtils.getUserClass(beanFactory.getType(beanName));
this.method = method; this.method = method;
this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(method); this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
this.parameters = initMethodParameters(); this.parameters = initMethodParameters();
} }
/** /**
* Copy constructor for use in sub-classes. * Copy constructor for use in subclasses.
*/ */
protected HandlerMethod(HandlerMethod handlerMethod) { protected HandlerMethod(HandlerMethod handlerMethod) {
Assert.notNull(handlerMethod, "HandlerMethod is required"); Assert.notNull(handlerMethod, "HandlerMethod is required");
this.bean = handlerMethod.bean; this.bean = handlerMethod.bean;
this.beanFactory = handlerMethod.beanFactory; this.beanFactory = handlerMethod.beanFactory;
this.beanType = handlerMethod.beanType;
this.method = handlerMethod.method; this.method = handlerMethod.method;
this.bridgedMethod = handlerMethod.bridgedMethod; this.bridgedMethod = handlerMethod.bridgedMethod;
this.parameters = handlerMethod.parameters; this.parameters = handlerMethod.parameters;
@ -123,6 +128,7 @@ public class HandlerMethod {
Assert.notNull(handler, "Handler object is required"); Assert.notNull(handler, "Handler object is required");
this.bean = handler; this.bean = handler;
this.beanFactory = handlerMethod.beanFactory; this.beanFactory = handlerMethod.beanFactory;
this.beanType = handlerMethod.beanType;
this.method = handlerMethod.method; this.method = handlerMethod.method;
this.bridgedMethod = handlerMethod.bridgedMethod; this.bridgedMethod = handlerMethod.bridgedMethod;
this.parameters = handlerMethod.parameters; this.parameters = handlerMethod.parameters;
@ -153,18 +159,17 @@ public class HandlerMethod {
} }
/** /**
* Returns the type of the handler for this handler method. * This method returns the type of the handler for this handler method.
* Note that if the bean type is a CGLIB-generated class, the original, user-defined class is returned. * <p>Note that if the bean type is a CGLIB-generated class, the original
* user-defined class is returned.
*/ */
public Class<?> getBeanType() { public Class<?> getBeanType() {
Class<?> clazz = (this.bean instanceof String ? return this.beanType;
this.beanFactory.getType((String) this.bean) : this.bean.getClass());
return ClassUtils.getUserClass(clazz);
} }
/** /**
* If the bean method is a bridge method, this method returns the bridged (user-defined) method. * If the bean method is a bridge method, this method returns the bridged
* Otherwise it returns the same method as {@link #getMethod()}. * (user-defined) method. Otherwise it returns the same method as {@link #getMethod()}.
*/ */
protected Method getBridgedMethod() { protected Method getBridgedMethod() {
return this.bridgedMethod; return this.bridgedMethod;
@ -199,8 +204,8 @@ public class HandlerMethod {
} }
/** /**
* Returns a single annotation on the underlying method traversing its super methods if no * Returns a single annotation on the underlying method traversing its super methods
* annotation can be found on the given method itself. * if no annotation can be found on the given method itself.
* @param annotationType the type of annotation to introspect the method for. * @param annotationType the type of annotation to introspect the method for.
* @return the annotation, or {@code null} if none found * @return the annotation, or {@code null} if none found
*/ */
@ -209,8 +214,8 @@ public class HandlerMethod {
} }
/** /**
* If the provided instance contains a bean name rather than an object instance, the bean name is resolved * If the provided instance contains a bean name rather than an object instance,
* before a {@link HandlerMethod} is created and returned. * the bean name is resolved before a {@link HandlerMethod} is created and returned.
*/ */
public HandlerMethod createWithResolvedBean() { public HandlerMethod createWithResolvedBean() {
Object handler = this.bean; Object handler = this.bean;
@ -221,21 +226,22 @@ public class HandlerMethod {
return new HandlerMethod(this, handler); return new HandlerMethod(this, handler);
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object other) {
if (this == obj) { if (this == other) {
return true; return true;
} }
if (obj != null && obj instanceof HandlerMethod) { if (!(other instanceof HandlerMethod)) {
HandlerMethod other = (HandlerMethod) obj;
return (this.bean.equals(other.bean) && this.method.equals(other.method));
}
return false; return false;
} }
HandlerMethod otherMethod = (HandlerMethod) other;
return (this.bean.equals(otherMethod.bean) && this.method.equals(otherMethod.method));
}
@Override @Override
public int hashCode() { public int hashCode() {
return this.bean.hashCode() * 31 + this.method.hashCode(); return (this.bean.hashCode() * 31 + this.method.hashCode());
} }
@Override @Override

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2014 the original author or authors. * Copyright 2002-2015 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.
@ -40,8 +40,8 @@ import org.springframework.web.method.HandlerMethodSelector;
import org.springframework.web.servlet.HandlerMapping; import org.springframework.web.servlet.HandlerMapping;
/** /**
* Abstract base class for {@link HandlerMapping} implementations that define a * Abstract base class for {@link HandlerMapping} implementations that define
* mapping between a request and a {@link HandlerMethod}. * a mapping between a request and a {@link HandlerMethod}.
* *
* <p>For each registered handler method, a unique mapping is maintained with * <p>For each registered handler method, a unique mapping is maintained with
* subclasses defining the details of the mapping type {@code <T>}. * subclasses defining the details of the mapping type {@code <T>}.
@ -73,7 +73,6 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
private HandlerMethodMappingNamingStrategy<T> namingStrategy; private HandlerMethodMappingNamingStrategy<T> namingStrategy;
private final Map<T, HandlerMethod> handlerMethods = new LinkedHashMap<T, HandlerMethod>(); private final Map<T, HandlerMethod> handlerMethods = new LinkedHashMap<T, HandlerMethod>();
private final MultiValueMap<String, T> urlMap = new LinkedMultiValueMap<String, T>(); private final MultiValueMap<String, T> urlMap = new LinkedMultiValueMap<String, T>();
@ -96,8 +95,6 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
/** /**
* Configure the naming strategy to use for assigning a default name to every * Configure the naming strategy to use for assigning a default name to every
* mapped handler method. * mapped handler method.
*
* @param namingStrategy strategy to use.
*/ */
public void setHandlerMethodMappingNamingStrategy(HandlerMethodMappingNamingStrategy<T> namingStrategy) { public void setHandlerMethodMappingNamingStrategy(HandlerMethodMappingNamingStrategy<T> namingStrategy) {
this.namingStrategy = namingStrategy; this.namingStrategy = namingStrategy;
@ -118,6 +115,7 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
return this.nameMap.get(mappingName); return this.nameMap.get(mappingName);
} }
/** /**
* Detects handler methods at initialization. * Detects handler methods at initialization.
*/ */
@ -234,7 +232,6 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
} }
private void updateNameMap(String name, HandlerMethod newHandlerMethod) { private void updateNameMap(String name, HandlerMethod newHandlerMethod) {
List<HandlerMethod> handlerMethods = this.nameMap.get(name); List<HandlerMethod> handlerMethods = this.nameMap.get(name);
if (handlerMethods != null) { if (handlerMethods != null) {
for (HandlerMethod handlerMethod : handlerMethods) { for (HandlerMethod handlerMethod : handlerMethods) {
@ -266,7 +263,8 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
HandlerMethod handlerMethod; HandlerMethod handlerMethod;
if (handler instanceof String) { if (handler instanceof String) {
String beanName = (String) handler; String beanName = (String) handler;
handlerMethod = new HandlerMethod(beanName, getApplicationContext(), method); handlerMethod = new HandlerMethod(beanName,
getApplicationContext().getAutowireCapableBeanFactory(), method);
} }
else { else {
handlerMethod = new HandlerMethod(handler, method); handlerMethod = new HandlerMethod(handler, method);
@ -375,7 +373,7 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
* Return a comparator for sorting matching mappings. * Return a comparator for sorting matching mappings.
* The returned comparator should sort 'better' matches higher. * The returned comparator should sort 'better' matches higher.
* @param request the current request * @param request the current request
* @return the comparator, never {@code null} * @return the comparator (never {@code null})
*/ */
protected abstract Comparator<T> getMappingComparator(HttpServletRequest request); protected abstract Comparator<T> getMappingComparator(HttpServletRequest request);