前言
用国庆的最后一天把SpringMVC感兴趣的部分全部看完了,网上资料五花八门,有些总结写的很好,就是SpringMVC版本过旧,真的很晕,本片博客的SpringMVC版本为5.1.0,以后都不会在博客中贴过多源码,因为记不住源码,只会大致讲讲处理过程
预备知识
代码来源:https://blog.csdn.net/u012420654/article/details/59480498
public HandlerMethod(Object bean, Method method) {
// 省略部分代码...
// 控制器名称
this.bean = bean;
// 所在容器,这里指 SpringMVC 容器
this.beanFactory = null;
// 控制器类型
this.beanType = ClassUtils.getUserClass(bean);
// 路径匹配的执行方法
this.method = method;
// 方法参数
this.parameters = initMethodParameters();
// 桥方法,一般情况与 method 值一样
this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
this.resolvedFromHandlerMethod = null;
}
举个例子:
Controller
public class LoginController {
@RequestMapping(value = "/login")
public Object test(HttpServletRequest request, Model model) throws Exception {
return null;
}
}
则HandlerMethod对应的属性值为:
bean= LoginController
beanType= Class<T> (com.apps.modules.login.controller.LoginController)
method=
public java.lang.Object com.apps.modules.login.controller.LoginController.test
(javax.servlet.http.HttpServletRequest,org.springframework.ui.Model)
throws java.lang.Exception
parameters=
[org.springframework.web.method.HandlerMethod$HandlerMethodParameter@c9d41104,
org.springframework.web.method.HandlerMethod$HandlerMethodParameter@c9d41105]
HandlerMapping
作用:将http请求映射到handler(即HandlerMethod对象,这个对象存储的值上面有,可以清楚看到这个对象封装了处理请求的方法的所有信息)
SpringMVC(5.1.0版本)默认初始化两个HandlerMapping的实现类:
- BeanNameUrlHandlerMapping:根据bean的name属性的值,name属性必须以"/"开头(name="/aluba")来选择handler
- RequestMappingHandlerMapping:根据@Controller类中的@RequestMapping注解来选择handler(优先级比BeanNameUrlHandlerMapping高)
DispatchServlet初始化时,会将所有的HandlerMapping实例存储到handlerMappings中,而HandlerMapping中存储有请求与handler之间的对应关系
当DispatcherServlet接收到请求时,会调用自己的getHandler方法:
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace("Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
}
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}
它会遍历handlerMappings,调用每个HandlerMapping的getHandler方法,传入request对象,根据请求的url选择对应的handler,最终返回HandlerExcutionChain(handler+拦截器)对象,接下来DispatchServlet会选择HandlerAdapter进行处理
HandlerAdapter
作用:调用handler中的方法处理请求,返回ModelAndview
接口源码:
public interface HandlerAdapter {
//判断适配器是否支持handler的调用
boolean supports(Object handler);
//调用handler
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
long getLastModified(HttpServletRequest request, Object handler);
}
SpringMVC(5.1.0版本)默认初始化三个HandlerAdapter实现类:
- HttpRequestHandlerAdapter:handler必须是HttpRequestHandler的实现类,主要用于静态资源的访问,例如图片等,但是Springboot项目的静态资源貌似可以直接通过url访问,它的Handle方法源码如下,最终调用的是Controller实现类的handleRequest方法:
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //执行HttpRequestHandler的handleRequest方法 ((HttpRequestHandler) handler).handleRequest(request, response); return null; }
- SimpleControllerHandlerAdapter:handler必须是Controller的实现类,它的handle方法源码如下,最终调用的是Controller实现类的handleRequest方法:
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception { //本质是执行Controller的handleRequest方法 return ((Controller) handler).handleRequest(request, response); }
- RequestMappingHandlerAdapter:handler使用了@RequestMapping,它的handle方法有点复杂,这里就不贴了,总结一下就是使用反射调用控制器的方法,其中还包括将Http请求参数转换为java类型(调用HttpMessageConverter、转换器、构造器),并进行参数绑定(使用HandlerMethodArgumentResolver)
在DispatcherServlet初始化时,会将所有的HandlerAdapter存放到HandlerAdapters中,当HandlerMapping返回HandlerExcutionChain给DispatcherServlet时,DispatcherServlet会调用getHandlerAdapter方法遍历HandlerAdapters,调用每个HandlerAdapter的support方法,判断使用哪个HandlerAdapter,如下:
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
for (HandlerAdapter ha : this.handlerAdapters) {
if (logger.isTraceEnabled()) {
logger.trace("Testing handler adapter [" + ha + "]");
}
//调用supports方法
if (ha.supports(handler)) {
return ha;
}
}
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}
我们平常更多使用的是RequestMappingHandlerAdapter,这其中涉及的参数转换我已经写过一篇博客了,参数绑定比较复杂,将在下一篇博客说明
参考资料:
https://blog.csdn.net/wangbiao007/article/details/50547020
https://blog.csdn.net/qq924862077/article/details/53843393
https://blog.csdn.net/qq924862077/article/details/53842993
https://blog.csdn.net/qq924862077/article/details/53895054
https://blog.csdn.net/u012420654/article/details/59480498
如有错误,欢迎指出