前言

用国庆的最后一天把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的实现类:

  1. BeanNameUrlHandlerMapping:根据bean的name属性的值,name属性必须以"/"开头(name="/aluba")来选择handler
  2. 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实现类:

  1. 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;
    }
    

     

  2. 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);
    }
     

     

  3. 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

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.html

 

如有错误,欢迎指出

10-07 16:58