前言
我们已经知道HandlerMapping的主要作用是通过request找到Handler,Spring MVC中HandlerMapping的实现有很多,比如SimpleUrlHandlerMapping、BeanNameUrlHandlerMapping、DefaultAnnotationHandlerMapping以及RequestMappingHandlerMapping等等,本篇文章就来分析下最常用的RequestMappingHandlerMapping。
RequestMappingHandlerMapping
我们先来看下RequestMappingHandlerMapping的继承关系,然后从继承关系从上到下依次分析。
HandlerMapping
HandlerMapping我们已经分析过了,不过最好还是回顾下接口的定义
public interface HandlerMapping {
String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE = HandlerMapping.class.getName() + ".pathWithinHandlerMapping";
String BEST_MATCHING_PATTERN_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingPattern";
String INTROSPECT_TYPE_LEVEL_MAPPING = HandlerMapping.class.getName() + ".introspectTypeLevelMapping";
String URI_TEMPLATE_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".uriTemplateVariables";
String MATRIX_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".matrixVariables";
String PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE = HandlerMapping.class.getName() + ".producibleMediaTypes";
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}
AbstractHandlerMapping
创建过程
AbstractHandlerMapping继承了WebApplicationObjectSupport,初始化的时候会调用initApplicationContext,其内部主要是初始化interceptors,供以后使用。
Interceptor分为两种
- 一种是直接或间接实现了Interceptor接口的普通拦截器,它对所有的请求都会拦截
- 另一种是MappedInterceptor,MappedInterceptor内部包含一个第一种的拦截器,但是它有一个matches方法,只有符合要求的请求它才会拦截
protected void initApplicationContext() throws BeansException {
// 模板方法,用于子类扩展或修改interceptors,不过并没有子类实现
extendInterceptors(this.interceptors);
// 将ApplicationContext中所有的MappedInterceptor添加到adaptedInterceptors中
detectMappedInterceptors(this.adaptedInterceptors);
// 将interceptors中的元素添加到adaptedInterceptors中
initInterceptors();
}
使用过程
AbstractHandlerMapping实现了getHandler方法,主要分为两个部分
- 获取Handler,这部分是模板方法,由子类实现
- 将创建过程中初始化的interceptors和第一步获取的handler一起组成HandlerExecutionChain
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 模板方法,由子类实现
Object handler = getHandlerInternal(request);
if (handler == null) {
// 获取默认Handler,默认为null
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// handler是beanName,就从ApplicationContext中取出对应的bean
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
// 通过handler和request获取HandlerExecutionChain
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
// 如果是cors请求,添加一些拦截器
if (CorsUtils.isCorsRequest(request)) {
CorsConfiguration globalConfig = this.globalCorsConfigSource.getCorsConfiguration(request);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
现在我们再来看下获取HandlerExecutionChain的具体过程,第一步是构造HandlerExecutionChain,第二步是根据情况添加拦截器。
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
// 构造HandlerExecutionChain
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
// 添加拦截器
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
// 添加符合条件的MappedInterceptor
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
} else {
// 非MappedInterceptor都添加进来
chain.addInterceptor(interceptor);
}
}
return chain;
}
AbstractHandlerMethodMapping
我们先来解释下AbstractHandlerMethodMapping中泛型T的含义,官方定义为The mapping for a HandlerMethod containing the conditions needed to match the handler method to incoming request
,也就是它是一个包含了各种条件(包括url、HttpMethod、Header等)的一个类,通过这个类可以找到一个HandlerMethod(一种Handler),T默认的实现是RequestMappingInfo。
创建过程
AbstractHandlerMethodMapping实现了InitializingBean,所以它的初始化入口是
afterPropertiesSet,其内部只是简单地调用了initHandlerMethods方法,并没有做其他操作,下面我们来看下initHandlerMethods的具体实现
protected void initHandlerMethods() {
// 找到ApplicationContext中所有的beanName
String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
getApplicationContext().getBeanNamesForType(Object.class));
for (String beanName : beanNames) {
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
Class<?> beanType = null;
try {
// 获取到bean
beanType = getApplicationContext().getType(beanName);
}
catch (Throwable ex) {
if (logger.isDebugEnabled()) {
logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
}
}
// isHandler是模板方法
if (beanType != null && isHandler(beanType)) {
// 将bean中符合条件的方法注册到mappingRegistry
detectHandlerMethods(beanName);
}
}
}
// 对handler做一些初始化操作,模板方法,并没有子类实现
handlerMethodsInitialized(getHandlerMethods());
}
这里说一下isHandler方法,它由RequestMappingHandlerMapping实现,可以看出它的判断依据是类上是否有@Controller或@RequestMapping注解。
protected boolean isHandler(Class<?> beanType) {
return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}
下面我们再来具体看下detectHandlerMethods方法
protected void detectHandlerMethods(final Object handler) {
// 获取handler的类
Class<?> handlerType = (handler instanceof String ?
getApplicationContext().getType((String) handler) : handler.getClass());
// 如果是cglib代理的子类,则返回父类,否则直接返回传入的类
final Class<?> userType = ClassUtils.getUserClass(handlerType);
// 获取所有符合条件的方法以及对应的匹配条件
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
new MethodIntrospector.MetadataLookup<T>() {
@Override
public T inspect(Method method) {
try {
// 模板方法,返回方法对应的匹配条件
return getMappingForMethod(method, userType);
}
catch (Throwable ex) {
throw new IllegalStateException("Invalid mapping on handler class [" +
userType.getName() + "]: " + method, ex);
}
}
});
// 注册到mappingRegistry
for (Map.Entry<Method, T> entry : methods.entrySet()) {
Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType);
T mapping = entry.getValue();
registerHandlerMethod(handler, invocableMethod, mapping);
}
}
其实我们可以总结出AbstractHandlerMethodMapping的创建过程其实就是根据代码里@Controller和@RequestMapping注解,将符合条件的方法包装成HandlerMethod,并且建立HandlerMethod和T的对应关系。
AbstractHandlerMethodMapping的使用过程
从AbstractHandlerMapping的使用过程我们知道,AbstractHandlerMethodMapping使用的入口是getHandlerInternal方法
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
// 获取lookupPath,可以简单理解成url
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
this.mappingRegistry.acquireReadLock();
try {
// 通过lookupPath和request中的一些条件(比如是GET请求还是POST请求等)找到HandlerMethod
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
this.mappingRegistry.releaseReadLock();
}
}