handler是什么

handler从大的范围来说就是一个controller,即一个控制器image.pngimage.pngimage.pngimage.png

执行流程探索

image.pngimage.pngimage.pngimage.pngimage.png
handlerExectionChain里有有handler属性,并且getHandler()能拿出handler。然后
image.png
这个handler是Object类型,但是handler实际上有五种类型
image.pngimage.pngimage.png
根据request可以拿到它对应的handler。
方法是遍历所有handlerMapping。image.png
HandlerMapping这个接口本身没什么东西,只有一个getHandler方法,返回的是HandlerExecutionChainimage.pngimage.png
注意看上面AbstractUrlHandlerMapping是一样的。

但是this.handleMapping存放着五个值
image.pngimage.png

回到doDispatch(),调用getHandler找到合适的handlerMapping。怎么找的?以此遍历五个handlerMapping,,找到能够处理当前request的handlerMappingimage.png

每个handlerMapping有自己映射库。根据给定的request去匹配自己的库,如果里面有,说明自己就是这个hander的handlerMapping。
image.png
而handlerMapping的作用就是 在url和类/方法之间建立映射。即能根据指定的url去找特定的类和方法。
image.png
所以可以猜测 handlerMapping的getHandler()作用就是拿request去匹配自己的register库,判断是不是在库里。接下来验证这个过程

image.png
debug发现 R(/car/3/owner/lisi)恰好被RequestMappingHandlerMapping这个handlerMapping处理了,所以我们去找他的getHandler()方法,看他怎么处理的。
image.png
发现它里面没有getHandler()image.png
去他的父类里面找(为什么不去实现的接口里去找?如果接口里有getHandler,那么RequestMappingHandlerMapping就必须实现这个方法了,而没有实现,说明不是接口里的。总之一句话,一个类有某个方法,但是类里面又没写,那么一定在父类里。)image.png
父类里依旧没有,再去他的父类image.png
还是没有,继续找
image.pngimage.png
他的两个子类都有getHandlerInternal(),根据两个子类的返回值找到我们想要的那个。
image.pngimage.pngimage.pngimage.png
handler是HandlerMethod类型的
image.pngimage.png
handlerMapping有5个,但是handlerAdapter只有四个。
image.png
也有5个
image.png

HandlerAdapter

image.png
image.pngimage.pngimage.png

image.pngimage.png

image.pngimage.png
这两个最大的不同,就是第一个还多了个接口,第二个直接使用Adpater了。

getHandler()

共有三个getHandler()。 第一个调用第二个,最终在doDispatche() 里返回HandlerExecutionChain类型的mappedHandler(已经映射好的handler)。
第三个调用自身的getHandler,把真正的handler返回回来。

  1. image.png
  2. image.png
  3. image.png

网上找的HandlerMapping()解释

 Sping MVC用于处理Http请求那首先要做的第一件事情就是要为每个url找到对应的java类及方法。至于寻找的方式就有很多了,简单的做法,可以用一个Map保存所有url和“java类及方法”之间的映射;复杂一点的,使用注解来定义方法和url的关系……所以,自然而然的,我们可以抽象出一个接口来表示这个寻找动作,不同的人可以按照自己的需求订制这种寻找过程。
那么这个接口应该如何设计呢,很容易想到的是,这个接口有一个方法,入参是HttpServletRequest,出参是java类和方法。那么问题的关键就落到了这个出参上面。关于出参的定义,最主要的是解决下面几个问题:

返回的出参必须具有执行请求的能力,简单说就是能够解析入参,执行java方法,返回结果。要实现这个就比较复杂了,因为参数的解析方式多种多样,每个java类的会有很多方法,每个方法的出入参也千差万别。所以SpingMVC在设计的时候,将这个复杂的逻辑交给了HandleAdaptor,HandleMapping只需要返回需要执行的类就行了。
以前,我们定义拦截器可以实现Filter接口,然后在web.xml配置需要拦截的path就行,但是这样的拦截器没法交给SpingMVC管理,为了实现统一的管理,SpringMVC实现自定义了拦截器接口。定义拦截器接口、实现拦截器都很简单,麻烦的时候,拦截器什么时候应该调用,应该拦截哪些请求。最好的办法是每次处理请求时,返回java类的时候,一并返回这次请求的拦截器。
基于上面的几点,于是乎就有了 HandleMapping接口。

一、HandlerMapping
作用是根据当前请求的找到对应的 Handler,并将 Handler(执行程序)与一堆 HandlerInterceptor(拦截器)封装到 HandlerExecutionChain 对象中。在 HandlerMapping 接口的内部只有一个方法,如下:

  • HandlerExecutionChain getHandler(HttpServletRequest request);

HandlerMapping 是由 DispatcherServlet 调用,DispatcherServlet 会从容器中取出所有 HandlerMapping 实例并遍历,让 HandlerMapping 实例根据自己实现类的方式去尝试查找 Handler,而 HandlerMapping 具体有哪些实现类下面就会详细分析。
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 这些 HandlerMapping 在容器初始化时创建,在 initHandlerMappings 时放入集合中
for (HandlerMapping hm : this.handlerMappings) {
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}
另外上面说到的 Handler 有可能是一个 HandlerMethod(封装了 Controller 中的方法)对象,也有可能是一个 Controller 对象、 HttpRequestHandler 对象或 Servlet 对象,而这个 Handler 具体是什么对象,也是与所使用的 HandlerMapping 实现类有关。如下图所示,可以看到 HandlerMapping 实现类有两个分支,分别继承自 AbstractHandlerMethodMapping(得到 HandlerMethod)和 AbstractUrlHandlerMapping(得到 HttpRequestHandler、Controller 或 Servlet),它们又统一继承于 AbstractHandlerMapping。
handler、handlerAdapter、HandlerMapping - 图48
先来看一下 AbstractHandlerMapping,它实现了 HandlerMapping 接口中的 getHandler() 方法,源码如下所示

  1. @Override
  2. public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
  3. // 根据请求获取执行程序,具体的获取方式由子类决定,getHandlerInternal() 是抽象方法
  4. Object handler = getHandlerInternal(request);
  5. if (handler == null) {
  6. handler = getDefaultHandler();
  7. }
  8. if (handler == null) {
  9. return null;
  10. }
  11. // Bean name or resolved handler?
  12. if (handler instanceof String) {
  13. String handlerName = (String) handler;
  14. handler = getApplicationContext().getBean(handlerName);
  15. }
  16. // 将 Handler 与一堆拦截器包装到 HandlerExecutionChain 对象中
  17. return getHandlerExecutionChain(handler, request);
  18. }

可以看到在这个方法中又调用了 getHandlerInternal() 方法获取到了 Handler 对象,而 Handler 对象具体内容是由它的子类去定义的。下面就来一看下 AbstractHandlerMapping 的两个分支子类
1 AbstractUrlHandlerMapping
AbstractUrlHandlerMapping 这个分支获取的 Handler 的类型实际就是一个 Controller 类,所以一个 Controller 只能对应一个请求(或者像 Struts2 那样定位到方法,使同一个业务的方法放在同一个类里),源码如下所示

protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
    // 根据当前请求获取“查找路径”
    String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
    // 根据路径获取 Handler(即Controller),先尝试直接匹配,再尝试模式匹配
    Object handler = lookupHandler(lookupPath, request);
    if (handler == null) {
       // We need to care for the default handler directly, since we need to
        // expose the PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE for it as well.
        Object rawHandler = null;
        if ("/".equals(lookupPath)) {
            rawHandler = getRootHandler();
        }
        if (rawHandler == null) {
            rawHandler = getDefaultHandler();
        }
        if (rawHandler != null) {
            // Bean name or resolved handler?
            if (rawHandler instanceof String) {
                String handlerName = (String) rawHandler;
                rawHandler = getApplicationContext().getBean(handlerName);
            }
            validateHandler(rawHandler, request);
            handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);
        }
    }
    return handler;
}

1.1 AbstractUrlHandlerMapping 实现类及使用
handler、handlerAdapter、HandlerMapping - 图49
1) ControllerClassNameHandlerMapping:根据类名访问 Controller。




2) ControllerBeanNameHandlerMapping:根据 Bean 名访问 Controller,与 BeanNameUrlHandlerMapping 类似,但是bean名称不用遵循URL公约。




3) BeanNameUrlHandlerMapping:利用 BeanName 来作为 URL 使用。




4) SimpleUrlHandlerMapping:可以将 URL 与处理器的定义分离,还可以对 URL 进行统一的映射管理。




testController
testController





1.2 Controller 类
使用 AbstractUrlHandlerMapping 的实现类时,需要让控制层的类实现 Controller 接口(一般继承 AbstractController 即可),另外还有一些已经实现了的 Controller 类,如下图所示。但是不论是自己实现 Controller 接口还是使用系统已经实现的类,都只能处理一个请求(除了 MultiActionController 可以通过参数的方式让一个类可以处理多个请求)。
handler、handlerAdapter、HandlerMapping - 图50
另外下面所有的 Controller 均采用 SimpleUrlHandlerMapping 方式的。
1) UrlFilenameViewController:用于跳转界面,控制器根据请求的URL直接解析出视图名,省去了自己实现 Ccntroller 跳转页面。

2) ParameterizableViewController:同样用于界面跳转,控制器根据配置的参数来跳转界面,使用方式如下



3) ServletForwardingController:将请求转发到 Servlet,使用方式如下



另外还要在 web.xml 中配置要转发到的 Servlet

indexServlet
com.servlet.ServletForwarding

4) ServletWrappingController:将某个 Servlet 包装为 Controller,所有到 ServletWrappingController 的请求实际上是由它内部所包装的这个 Servlet 实例来处理的,这样可以将这个 Servlet 隐藏起来
5) MultiActionController:一个 Controller 可以写多个方法,分别对应不同的请求,使同一业务的方法可以放在一起了。在使用时让自己的 Controller 类继承 MultiActionController 类,使用方式如下
handler、handlerAdapter、HandlerMapping - 图51
public class IndexController extends MultiActionController {
public ModelAndView add(HttpServletRequest request,HttpServletResponse response) {
ModelAndView mv = new ModelAndView();
mv.addObject(“message”,”add”);
mv.setViewName(“add”);
return mv;
}
public ModelAndView delete(HttpServletRequest request,HttpServletResponse response) {
ModelAndView mv = new ModelAndView();
mv.addObject(“message”,”delete”);
mv.setViewName(“delete”);
return mv;
}
}
handler、handlerAdapter、HandlerMapping - 图52
配置自己的 Controller 时要配置一个方法名解析器(默认是 InternalPathMethodNameResolver )
handler、handlerAdapter、HandlerMapping - 图53









handler、handlerAdapter、HandlerMapping - 图54
当我们访问 http://localhost:8080/***/indexAction.do?action=add 时,进入 add() 方法;
当我们访问 http://localhost:8080/***/indexAction.do?action=delete 时,进入 delete() 方法。

2 AbstractHandlerMethodMapping
AbstractHandlerMethodMapping 这个分支获取的 Handler 的类型是 HandlerMethod,即这个 Handler 是一个方法,它保存了方法的信息(如Method),这样一个 Controller 就可以处理多个请求了,源码如下所示
handler、handlerAdapter、HandlerMapping - 图55
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
// 根据当前请求获取“查找路径”
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
// 获取当前请求最佳匹配的处理方法(即Controller类的方法中)
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
handler、handlerAdapter、HandlerMapping - 图56
上述代码中 lookupHandlerMethod() 方法主要工作是在 Map handlerMethods 中找到 HandlerMethod,这里的 T 是 HandlerMappingInfo,它封装了 @RequestMapping 注解中的信息。那 HandlerMethod 是怎么创建的(即怎么把 Controller 的方法变成了它),继续看一下源码找到 initHandlerMethods() 方法,这个方法是在这个类创建后调用的,如下所示是它的源码
handler、handlerAdapter、HandlerMapping - 图57
protected void initHandlerMethods() {
// 从容器中获取所有 Bean 的名称,detectHandlerMethodsInAncestorContexts 默认false,不从父容器中查找
//即默认只查找 SpringMVC 的 IOC 容器,不查找它的父容器 Spring 的 IOC 容器
String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
getApplicationContext().getBeanNamesForType(Object.class));
for (String beanName : beanNames) {
// 这里的 isHandler()方法由子类实现,判断是否拥有 @Controller 注解或 @RequestMapping 注解
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX) && isHandler(getApplicationContext().getType(beanName))){
// 利用反射得到 Bean 中的 Method 并包装成 HandlerMethod,然后放入 Map 中
detectHandlerMethods(beanName);
}
}
handlerMethodsInitialized(getHandlerMethods());
}
handler、handlerAdapter、HandlerMapping - 图58
看完上述代码后,可以知道是在 detectHandlerMethods() 方法中将 Bean 的方法转换为 HandlerMethod 对象,具体实现如下
handler、handlerAdapter、HandlerMapping - 图59
protected void detectHandlerMethods(final Object handler) {
// 获取这个 Bean 的 Class 对象
Class<?> handlerType = (handler instanceof String ? getApplicationContext().getType((String) handler) : handler.getClass());
// 避免重复调用 getMappingForMethod(),getMappingForMethod() 将重新构建 RequestMappingInfo 实例
final Map mappings = new IdentityHashMap();
// 获取被代理前的原始类型
final Class<?> userType = ClassUtils.getUserClass(handlerType);
// 获取 Method
Set methods = HandlerMethodSelector.selectMethods(userType, new MethodFilter() {
@Override
public boolean matches(Method method) {
// 根据 Method 和它的 @RequestMapping 注解,创建 RequestMappingInfo 对象。
// 这里的 T 就是 RequestMappingInfo,它封装了 @RequestMapping 信息
T mapping = getMappingForMethod(method, userType);
if (mapping != null) {
mappings.put(method, mapping);
return true;
} else {
return false;
}
}
});
for (Method method : methods) {
// 注册 Method 和它的映射,RequestMappingInfo 储存着映射信息
registerHandlerMethod(handler, method, mappings.get(method));
}
}
handler、handlerAdapter、HandlerMapping - 图60
最后在 registerHandlerMethod() 方法中,将 RequestMappingInfo 作为 key,把 Method 包装成 HandlerMethod 作为 value 添加到了 Map handlerMethods 中。
handler、handlerAdapter、HandlerMapping - 图61
protected void registerHandlerMethod(Object handler, Method method, T mapping) {
HandlerMethod newHandlerMethod = createHandlerMethod(handler, method);
HandlerMethod oldHandlerMethod = this.handlerMethods.get(mapping);
if (oldHandlerMethod != null && !oldHandlerMethod.equals(newHandlerMethod)) {
throw new IllegalStateException(“”);
}
this.handlerMethods.put(mapping, newHandlerMethod);
Set patterns = getMappingPathPatterns(mapping);
for (String pattern : patterns) {
if (!getPathMatcher().isPattern(pattern)) {
this.urlMap.add(pattern, mapping);
}
}
}
handler、handlerAdapter、HandlerMapping - 图62
1.1 AbstractHandlerMapping 实现类及使用
handler、handlerAdapter、HandlerMapping - 图63
AbstractHandlerMethodMapping 只有一个实现类 RequestMappingHandlerMapping

二、HandlerAdapter
根据 Handler 来找到支持它的 HandlerAdapter,通过 HandlerAdapter 执行这个 Handler 得到 ModelAndView 对象。HandlerAdapter 接口中的方法如下:

  • boolean supports(Object handler); // 当前 HandlerAdapter 是否支持这个 Handler
  • ModelAndView handle(HttpServletRequest req, HttpServletResponse res, Object handler); // 利用 Handler 处理请求
  • long getLastModified(HttpServletRequest request, Object handler);

handler、handlerAdapter、HandlerMapping - 图64
1 RequestMappingHandlerAdapter
从上面的文章中可以知道,利用 RequestMappingHandlerMapping 获取的 Handler 是 HadnlerMethod 类型,它代表 Controller 里要执行的方法,而 RequestMappingHandlerAdapter 可以执行 HadnlerMethod 对象。
RequestMappingHandlerAdapter 的 handle() 方法是在它的父类 AbstractHandlerMethodAdapter 类中实现的,源码如下所示
@Override
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return handleInternal(request, response, (HandlerMethod) handler);
}
handleInternal() 方法是由 RequestMappingHandlerAdapter 自己来实现的,源码如下所示
handler、handlerAdapter、HandlerMapping - 图65
@Override
protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
// 是否通过 @SessionAttributes 注释声明了 session 属性。
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);
} else {
checkAndPrepare(request, response, true);
}
// 是否需要在 synchronize 块中执行
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
// 执行 HandlerMethod
return invokeHandleMethod(request, response, handlerMethod);
}
}
}
// 执行 HandlerMethod,得到 ModelAndView
return invokeHandleMethod(request, response, handlerMethod);
}
handler、handlerAdapter、HandlerMapping - 图66
继续再来看一下如何得到 ModelAndView,invokeHandlerMethod() 方法如下
handler、handlerAdapter、HandlerMapping - 图67
private ModelAndView invokeHandleMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
//
ServletWebRequest webRequest = new ServletWebRequest(request, response);
// 数据绑定
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
// 绑定参数,执行方法
ServletInvocableHandlerMethod requestMappingMethod = createRequestMappingMethod(handlerMethod, binderFactory);
// 创建模型和视图容器
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
// 设置FlasgMap中的值
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
// 初始化模型
modelFactory.initModel(webRequest, mavContainer, requestMappingMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);<br />    asyncWebRequest.setTimeout(this.asyncRequestTimeout);

final WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);<br />    asyncManager.setTaskExecutor(this.taskExecutor);<br />    asyncManager.setAsyncWebRequest(asyncWebRequest);<br />    asyncManager.registerCallableInterceptors(this.callableInterceptors);<br />    asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);<br />    if (asyncManager.hasConcurrentResult()) {<br />        Object result = asyncManager.getConcurrentResult();<br />        mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];<br />        asyncManager.clearConcurrentResult();<br />        requestMappingMethod = requestMappingMethod.wrapConcurrentResult(result);<br />    }<br />    requestMappingMethod.invokeAndHandle(webRequest, mavContainer);<br />    if (asyncManager.isConcurrentHandlingStarted()) {<br />        return null;<br />    }<br />    return getModelAndView(mavContainer, modelFactory, webRequest);<br />}<br />![](https://cdn.nlark.com/yuque/0/2021/gif/2840444/1615438405554-c51eeeeb-593c-4e6e-916a-750fa1b9ace0.gif#height=20&id=DjLX1&originHeight=20&originWidth=20&originalType=binary&size=0&status=done&style=none&width=20)<br /> <br />2 HttpRequestHandlerAdapter<br />HttpRequestHandlerAdapter 可以执行 HttpRequestHandler 类型的 Handler,源码如下<br />![](https://cdn.nlark.com/yuque/0/2021/gif/2840444/1615438405579-56b69a87-4a5d-4f2c-818a-6b8f48392f88.gif#height=20&id=No02a&originHeight=20&originWidth=20&originalType=binary&size=0&status=done&style=none&width=20)<br />@Override<br />public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {<br />    ((HttpRequestHandler) handler).handleRequest(request, response);<br />    return null;<br />}<br />![](https://cdn.nlark.com/yuque/0/2021/gif/2840444/1615438405559-93ff4b52-3ca4-4a9c-b2ab-2d1abbfec608.gif#height=20&id=Qmuu8&originHeight=20&originWidth=20&originalType=binary&size=0&status=done&style=none&width=20)<br /> <br />3 SimpleControllerHandlerAdapter<br />SimpleControllerHandlerAdapter 可以执行 Controller 类型的 Handler,源码如下<br />@Override<br />public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {<br />    return ((Controller) handler).handleRequest(request, response);<br />}<br /> <br />4 SimpleServletHandlerAdapter <br />SimpleServletHandlerAdapter 可以执行 Servlet 类型的 Handler,源码如下<br />![](https://cdn.nlark.com/yuque/0/2021/gif/2840444/1615438405647-5beaa305-99f3-429b-a113-e61a73b21acf.gif#height=20&id=NYOhD&originHeight=20&originWidth=20&originalType=binary&size=0&status=done&style=none&width=20)<br />@Override<br />public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {<br />    ((Servlet) handler).service(request, response);<br />    return null;<br />}<br />![](https://cdn.nlark.com/yuque/0/2021/gif/2840444/1615438405608-50fb374b-9468-4178-be32-9da62217dadc.gif#height=20&id=lV3dI&originHeight=20&originWidth=20&originalType=binary&size=0&status=done&style=none&width=20)<br /> <br />三、HandlerExceptionResolver<br />负责处理异常的类,负责根据异常来设置 ModelAndView,然后交由 render 渲染界面。HandlerExecptionResolver 接口中只有一个方法,如下:
  • ModelAndView resolveException(HttpServletRequest req, HttpServletResponse res, Object handler, Exception ex);