1.HandlerMapping
HandlerMapping接口只有一个方法
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
就是根据Reuqest返回HandlerExecutionChain,看名字就知道是一个处理链,包含多个Interceptor和一个Handler。
2.AbstractHandlerMapping
AbstractHandlerMapping是HanlderMapping的默认实现类。是一个模板方法(Spring 底层大代码大量使用模板方法)。
2.1 初始化interceptor
@Override
protected void initApplicationContext() throws BeansException {
extendInterceptors(this.interceptors);
detectMappedInterceptors(this.adaptedInterceptors);
initInterceptors();
}
deleteMappedIntercptors方法的左右就是把ApplicationContext中所有类型为MappedInterceptor的bean加入到adaptedIntercptors这个成员变量中
protected void detectMappedInterceptors(List<HandlerInterceptor> mappedInterceptors) {
mappedInterceptors.addAll(
BeanFactoryUtils.beansOfTypeIncludingAncestors(
getApplicationContext(), MappedInterceptor.class, true, false).values());
}
initInterceptors()函数的作用就是把成员变量interceptors中的interceptor加入到adaptedInterceptors成员变量中去,如果是WebRequestInterceptor则转换为对应的adapter类,代码如下
protected void initInterceptors() {
if (!this.interceptors.isEmpty()) {
for (int i = 0; i < this.interceptors.size(); i++) {
Object interceptor = this.interceptors.get(i);
if (interceptor == null) {
throw new IllegalArgumentException("Entry number " + i + " in interceptors array is null");
}
this.adaptedInterceptors.add(adaptInterceptor(interceptor));
}
}
}
protected HandlerInterceptor adaptInterceptor(Object interceptor) {
if (interceptor instanceof HandlerInterceptor) {
return (HandlerInterceptor) interceptor;
}
else if (interceptor instanceof WebRequestInterceptor) {
return new WebRequestHandlerInterceptorAdapter((WebRequestInterceptor) interceptor);
}
else {
throw new IllegalArgumentException("Interceptor type not supported: " + interceptor.getClass().getName());
}
}
2.2 实现Handler接口
@Override
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
Object handler = getHandlerInternal(request);
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
if (CorsUtils.isCorsRequest(request)) {
CorsConfiguration globalConfig = this.corsConfigSource.getCorsConfiguration(request);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}
主要做了2件事:
- 1.获取request对应的Handler,获取handler是通过getHandlerInternal方法,这个由子类去实现
- 2.找出对应的Interceptors返回HandlerExecutionChain,从根据request找出合适的Interceptors加入其中(例如MappedInterceptor是根据url地址来判断是否加入)。
AbstractHandleMapping是一个模板方法,子类需要实现getHandlerInternal。下面介绍2个主要实现类AbstractUrlHandleMapping和AbstractHandleMethodMapping。
3. AbstractUrlHandleMapping
3.1 getHandlerInternal
从名字可以猜到,AbstractUrlHandleMapping是通过url来匹配对应的Handler。AbstractUrlHandleMapping依然是一个抽象类。getHandlerInternal代码:
/**
* 根据request的url查询对应的handler
*/
@Override
protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
//查找url地址,有可能是servlet的url,也有可能是Spring Mvc定义的url
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
//通过url查找对应的Handler
Object handler = lookupHandler(lookupPath, request);
//如果找不到对应的handler
if (handler == null) {
// 特殊情况,如果查询地址为"/",则判断是否用rootHandler,如果没有就设置为defaultHandler
Object rawHandler = null;
if ("/".equals(lookupPath)) {
rawHandler = getRootHandler();
}
if (rawHandler == null) {
rawHandler = getDefaultHandler();
}
if (rawHandler != null) {
// 如果是字符串,则从ApplicationConetxt中获取对应的bean
if (rawHandler instanceof String) {
String handlerName = (String) rawHandler;
rawHandler = getApplicationContext().getBean(handlerName);
}
//模板方法,验证Handler
validateHandler(rawHandler, request);
//返回HandlerExecutionChain类型,会注册2个interceptor
//PathExposingHandlerInterceptor和UriTemplateVariablesHandlerInterceptor
handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);
}
}
if (handler != null && logger.isDebugEnabled()) {
logger.debug("Mapping [" + lookupPath + "] to " + handler);
}
else if (handler == null && logger.isTraceEnabled()) {
logger.trace("No handler mapping found for [" + lookupPath + "]");
}
return handler;
}
主要做了一下几件事:
- 根据request生成查询handler的URL
- 根据url获取对应的handler
- 如果handler没有在map中查到,则使用默认的handler。
3.2 lookupHandler
方法目的就是根据url 查找对应的Handler,但是在url匹配的时候往往会有"/test/*"或者Path变量“/test/{id}”这样的情况,这样就无法通过url地址直接从map中获取对应的handler。
protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
// 能否直接找到
Object handler = this.handlerMap.get(urlPath);
if (handler != null) {
// 如果是字符串从ApplicationContext中直接获取
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
// 模板方法,验证handler
validateHandler(handler, request);
//返回HandlerExecutionChain类型,会注册2个interceptor
//PathExposingHandlerInterceptor和UriTemplateVariablesHandlerInterceptor
return buildPathExposingHandler(handler, urlPath, urlPath, null);
}
// 模板匹配
List<String> matchingPatterns = new ArrayList<String>();
for (String registeredPattern : this.handlerMap.keySet()) {
if (getPathMatcher().match(registeredPattern, urlPath)) {
matchingPatterns.add(registeredPattern);
}
else if (useTrailingSlashMatch()) {
if (!registeredPattern.endsWith("/") && getPathMatcher().match(registeredPattern + "/", urlPath)) {
matchingPatterns.add(registeredPattern +"/");
}
}
}
//根据order找出优先级坐高的
String bestPatternMatch = null;
Comparator<String> patternComparator = getPathMatcher().getPatternComparator(urlPath);
if (!matchingPatterns.isEmpty()) {
Collections.sort(matchingPatterns, patternComparator);
if (logger.isDebugEnabled()) {
logger.debug("Matching patterns for request [" + urlPath + "] are " + matchingPatterns);
}
bestPatternMatch = matchingPatterns.get(0);
}
if (bestPatternMatch != null) {
handler = this.handlerMap.get(bestPatternMatch);
if (handler == null) {
Assert.isTrue(bestPatternMatch.endsWith("/"));
handler = this.handlerMap.get(bestPatternMatch.substring(0, bestPatternMatch.length() - 1));
}
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
validateHandler(handler, request);
String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestPatternMatch, urlPath);
// 这里是处理当有多个url和最优的path是同一优先级的,那么从里面获取地址变量,加入到uriTemplateVariables中
Map<String, String> uriTemplateVariables = new LinkedHashMap<String, String>();
for (String matchingPattern : matchingPatterns) {
if (patternComparator.compare(bestPatternMatch, matchingPattern) == 0) {
Map<String, String> vars = getPathMatcher().extractUriTemplateVariables(matchingPattern, urlPath);
Map<String, String> decodedVars = getUrlPathHelper().decodePathVariables(request, vars);
uriTemplateVariables.putAll(decodedVars);
}
}
return buildPathExposingHandler(handler, bestPatternMatch, pathWithinMapping, uriTemplateVariables);
}
//找不到对应的handler
return null;
}
这个函数主要完成了几下几件事
- url能直接从map中获取的则直接获取
- 否则通过路径pattern去匹配url
- 从所有匹配到handler查找出优先级最高的
- 如果有多个同最优先级的,则查看里面是否有pathVariable
- 找到任意的Handler则加入2个特殊的interceptor
3.3 buildPathExposingHandler
上面所有的能成功找到对应的handler后,都会调用这个方法。这儿方法就是在handler的基础上,加入2个interceptor,返回一个HandlerExecutionChain
protected Object buildPathExposingHandler(Object rawHandler, String bestMatchingPattern,
String pathWithinMapping, Map<String, String> uriTemplateVariables) {
HandlerExecutionChain chain = new HandlerExecutionChain(rawHandler);
chain.addInterceptor(new PathExposingHandlerInterceptor(bestMatchingPattern, pathWithinMapping));
if (!CollectionUtils.isEmpty(uriTemplateVariables)) {
chain.addInterceptor(new UriTemplateVariablesHandlerInterceptor(uriTemplateVariables));
}
return chain;
}
这2个interceptor的作用就是当前匹配的url、匹配条件和url模板参数设置到request的attribute里面
3.4 Map初始化
上面一直说的通过url从map中获取对应的Handler,这个map是成员变量
private final Map<String, Object> handlerMap = new LinkedHashMap<String, Object>();
这个map的初始化是在registerHandler方法,这个方法比较功能比较简单,参数分别是url和handler,然后把url和handler放入map中,再做一些重复检查和特殊handler(roothandler)的设置。url和handler从哪里来,则又是子类提供处理具体的逻辑来调用这个方法。
到这里,关于怎么通过url来获取handler已经解决了,下面就是url和handler是怎么注册到handlermap中的,其中大部分子类都被@Deprecated标记,
3.5 SimpleUrlHandlerMapping
这个类非常简单,就是给定参数map,注册到handlermap中
protected void registerHandlers(Map<String, Object> urlMap) throws BeansException {
if (urlMap.isEmpty()) {
logger.warn("Neither 'urlMap' nor 'mappings' set on SimpleUrlHandlerMapping");
}
else {
for (Map.Entry<String, Object> entry : urlMap.entrySet()) {
String url = entry.getKey();
Object handler = entry.getValue();
// Prepend with slash if not already present.
if (!url.startsWith("/")) {
url = "/" + url;
}
// Remove whitespace from handler bean name.
if (handler instanceof String) {
handler = ((String) handler).trim();
}
registerHandler(url, handler);
}
}
}
4. AbstractHandlerMethodMapping
现在来看看AbstractHandlerMapping的另外一个继承 AbstractHandlerMethodMapping
AbstractHandlerMethodMapping从名字就可以看出,是把一个方法作为一个handler。并且继承体系也十分清晰。分析的顺序和AbstractUrlHandleMapping类似,首先还是先分析一下getHandlerInternal这个方法
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
if (logger.isDebugEnabled()) {
logger.debug("Looking up handler method for path " + lookupPath);
}
this.mappingRegistry.acquireReadLock();
try {
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
if (logger.isDebugEnabled()) {
if (handlerMethod != null) {
logger.debug("Returning handler method [" + handlerMethod + "]");
}
else {
logger.debug("Did not find handler method for [" + lookupPath + "]");
}
}
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
finally {
this.mappingRegistry.releaseReadLock();
}
}
看起来和AbstractUrlHandleMapping类似,只不过AbstractUrlHandleMapping中的handler是一个bean,而AbstractHandlerMethodMapping的handler是一个Method
初始化方法initHandlerMethods:
protected void initHandlerMethods() {
//获取所有beanName
String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
getApplicationContext().getBeanNamesForType(Object.class));
for (String beanName : beanNames) {
//beanName是以scopedTarget.开头的,则不用户Handler Method
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
Class<?> beanType = null;
try {
beanType = getApplicationContext().getType(beanName);
}
catch (Throwable ex) {
...
}
// isHandler模板方法,由子类去判断改bean是否注册
if (beanType != null && isHandler(beanType)) {
//注册到HandlerMethod
detectHandlerMethods(beanName);
}
}
}
//初始化HandlerMethod
handlerMethodsInitialized(getHandlerMethods());
}
detectHandlerMethods,就是注册handlerMethod。具体说明看注解
protected void detectHandlerMethods(final Object handler) {
Class<?> handlerType = (handler instanceof String ?
getApplicationContext().getType((String) handler) : handler.getClass());
final Class<?> userType = ClassUtils.getUserClass(handlerType);
//查找该handler中的method及其对应的条件(参照@RequestMapping中的参数)
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
new MethodIntrospector.MetadataLookup<T>() {
@Override
public T inspect(Method method) {
return getMappingForMethod(method, userType);
}
});
for (Map.Entry<Method, T> entry : methods.entrySet()) {
Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType);
T mapping = entry.getValue();
registerHandlerMethod(handler, invocableMethod, mapping);
}
}
- isHandler 是一个模板方法,由子类去判断改bean是否是一个handler。
- getMappingForMethod也是一个模板方法,判断一个类中Method方法的相关条件信息
- detectHandlerMethods是在传入的beanName对应的bean中查找handlerMethod,然后注册
- handlerMethodsInitialized 是一个预留方法,里面没有做任何事,如果我们自定义一个HandlerMapping有需要的话可以重写
4.1 RequestMappingHandlerMapping
RequestMappingHandlerMapping继承AbstractHandlerMethodMapping,首先看两个模板方法
isHandler,就是判断是否有Controller或者RequestMapping注解。
@Override
protected boolean isHandler(Class<?> beanType) {
return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}
getMappingForMethod这个方法就是根据传入的函数,返回一个RequestMappingInfo (也就是@RequestMapping中的参数信息)
@Override
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
RequestMappingInfo info = createRequestMappingInfo(method);
if (info != null) {
RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
if (typeInfo != null) {
info = typeInfo.combine(info);
}
}
return info;
}
这样,AbstractHandlerMethodMapping的就能通过一个url可以找出对应MethodHandler,
转载于:https://my.oschina.net/u/3039671/blog/825068