一、HandlerMapping的类图
可以看到HandlerMapping家族有两个分支,分别是AbstractUrlHandlerMapping和AbstractHandlerMethodMapping,而我们熟知的RequestMappingHandlerMapping就是它的子类。
二、HandlerMapping的加载
RequestMappingHandlerMapping实现了InitializingBean接口,在其初始化时执行afterPropertiesSet方法。在此方法中其遍历ApplicationContext中所有Bean,通过反射判断其类型Class上是否有@Controller或@RequestMapping注解。
调用链如下:
RequestMappingHandlerMapping#afterPropertiesSet
->AbstractHandlerMethodMapping#initHandlerMethods
AbstractHandlerMethodMapping#initHandlerMethods()核心代码如下:
protected void initHandlerMethods() {
// detectHandlerMethodsInAncestorContexts默认false,所以是得到所有的beanNames
String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
getApplicationContext().getBeanNamesForType(Object.class));
// 遍历所有的beanName
for (String beanName : beanNames) {
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
Class<?> beanType = null;
try {
beanType = getApplicationContext().getType(beanName);
}
catch (Throwable ex) {
// An unresolvable bean type, probably from a lazy bean - let's ignore it.
if (logger.isDebugEnabled()) {
logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
}
}
// 判断是否是handler类,即类注解是否含有Controller,RequestMapping
if (beanType != null && isHandler(beanType)) {
// 找出handler类中有有@RequestMapping注解的方法并注册
detectHandlerMethods(beanName);
}
}
}
// 空方法
handlerMethodsInitialized(getHandlerMethods());
}
判断是否是handler类,即类注解是否含有Controller,RequestMapping:
protected boolean isHandler(Class<?> beanType) {
return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}
找出handler类中有有@RequestMapping注解的方法并注册:
protected void detectHandlerMethods(final Object handler) {
//1. 得到controller真实类型
Class<?> handlerType = (handler instanceof String ?
getApplicationContext().getType((String) handler) : handler.getClass());
final Class<?> userType = ClassUtils.getUserClass(handlerType);
//3. 封装所有的Method和RequestMappingInfo到Map中
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
new MethodIntrospector.MetadataLookup<T>() {
@Override
public T inspect(Method method) {
try {
//2. 根据方法上的@RequestMapping信息构建RequestMappingInfo
return getMappingForMethod(method, userType);
}
catch (Throwable ex) {
throw new IllegalStateException("Invalid mapping on handler class [" +
userType.getName() + "]: " + method, ex);
}
}
});
if (logger.isDebugEnabled()) {
logger.debug(methods.size() + " request handler methods found on " + userType + ": " + methods);
}
for (Map.Entry<Method, T> entry : methods.entrySet()) {
Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType);
T mapping = entry.getValue();
//4. 将RequestMappingInfo注册到请求容器中
registerHandlerMethod(handler, invocableMethod, mapping);
}
}
三、HandlerMapping的数据结构
HandlerMapping的数据是保存到AbstractHandlerMethodMapping的内部类MappingRegistry的成员变量中,其中mappingLookup是我们常用的RequestMapping所存储的地方,
class MappingRegistry {
private final Map<T, MappingRegistration<T>> registry = new HashMap<T, MappingRegistration<T>>();
private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<T, HandlerMethod>();
private final MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<String, T>();
}
看到这个map数据结构应该能猜出来,key是URL,value是对应的handler类名+handler方法名,debug查看如下: