这里写自定义目录标题

  • spring mvc执行流程概括
  • 执行流程图
  • 如何根据用户请求url找到控制器对应的方法
  • HandleMapping(处理器映射器)
  • handleAdapter(处理器适配器)
  • ViewResolver(视图解析器)
  • 扩展点


spring mvc执行流程概括

spring mvc执行的流程可以简单概括为:第一步是找控制器,第二步是执行控制器,然后返回视图对象,把视图对象交给视图解析器,去渲染,最后响应给用户。

执行流程图

(1)第一步是找控制器,通过HandleMapping(处理器映射器),遍历所有实现了HandleMapping接口的实现类对象,找到合适的handle,返回给中央控制器(DispatcherServlet),最终返回的是一个handleExecutionChain类对象

(2)第二步是执行控制器,第一步已经拿到了控制器,接下来要去执行控制器,也就是拿到控制器适配器(handleAdapter中执行控制器,执行handler 方法,得到 ModelAndView 对象,为什么需要适配器,可以理解为我们现在都是使用@Controller、@RequestMapping注解来标注控制器,其实还可以通过继承Controller类实现handleRequest方法来处理用户请求,请求的地址还可以在xml中配置,总之就是执行控制器的方法不一样,所以spring mvc设计了不同的适配器来执行

(3)返回视图对象,然后把视图对象交给视图解析器,去渲染,最后响应给用户。

springmvc怎么执行sql_mvc

如何根据用户请求url找到控制器对应的方法

如果我们自己实现一个mvc框架,要实现这个功能可能要做以下几个步骤:
1、扫描整个项目所有的类
2、判断类上面有没有加@Controller、@Requestmapping注解
3、扫描方法、判断有没有注解
4、把注解的值和方法绑定起来,放到一个map里面HashMap<String,Method> map
5、自已定义一个MyDispatcherServlet,拦截用户请求,获取请求的url,根据url从map对象里面获取方法对象,通过反射执行方法里面的业务逻辑

通过源码分析一下spring mvc内部的工作流程:

1、首先看下最核心的一个类DispatcherServlet的继承关系,它既然是个Servlet,必然有init()、service()、doGet()和doPost()方法,在doGet()、doGet()方法里面会调用processRequest(request, response)——>doService(request, response)—>doDispatch(request, response),最核心的逻辑都在doDispatch方法里面完成

springmvc怎么执行sql_解析器_02


在doGet()、doGet()方法里面会调用processRequest(request, response)

springmvc怎么执行sql_spring_03


在processRequest方法里面调用doService(request, response)

springmvc怎么执行sql_mvc_04


最后找到最核心的方法doDispatch

springmvc怎么执行sql_springmvc怎么执行sql_05


下面重点分析一下doDispatch方法里面的逻辑

springmvc怎么执行sql_解析器_06


springmvc怎么执行sql_spring mvc原理_07


springmvc怎么执行sql_解析器_08


经过上面的分析,大概了解了spring mvc接收请求的处理和调用过程,关于HandleMapping初始化以及各种handlemapping的作用后续再分析

HandleMapping(处理器映射器)

HandleMapping接口负责根据request请求找到对应的handle处理器及Intercepter拦截器,并将它们封装在handleExecutionChain对象中,返回给中央处理器,常用的实现类主要有:
(1)RequestMappingHandlerMapping
(2)SimpleUrlHandlerMapping
(3)BeanNameUrlHandlerMapping

handleAdapter(处理器适配器)

1、 Spring MVC 通过HandlerAdapter来实际调用处理函数,就是调用具体的方法对用户发来的请求来进行处理,当handlerMapping获取到执行请求的controller时,DispatcherServlte会根据对应的controller类型来调用相应的HandlerAdapter来进行处理。
2、DispatcherServlte会根据配置文件信息注册HandlerAdapter,DispatcherServlte会读取DispatcherServlte.properties文件,该文件中配置了三种HandlerAdapter:HttpRequestHandlerAdapter,SimpleControllerHandlerAdapter和AnnotationMethodHandlerAdapter,比如:我们的控制器如果实现了Controller接口,那么就要实现Controller接口的handleRequest方法,实现了Controller接口的控制器会由SimpleControllerHandlerAdapter适配器开执行,SimpleControllerHandlerAdapter的实现也是很简单的,就是适配执行Controller的handleRequest方法。

**Controller接口**的定义也很简单,仅仅定义了一个handleRequest方法:
public interface Controller {
       ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception;
}

**SimpleControllerHandlerAdapter**类实现了HandlerAdapter 接口,其中有两个方法supports方法就是判断handler是否是Controller接口的实现类,handle方法本质是执行Controller.handleRequest方法
public class SimpleControllerHandlerAdapter implements HandlerAdapter {
@Override
public boolean supports(Object handler) {
	//判断是否是Controller类
	return (handler instanceof Controller);
}
//执行Controller的handleRequest方法
@Override
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
		throws Exception {
	//本质是执行Controller的handleRequest方法
	return ((Controller) handler).handleRequest(request, response);
}

}

ViewResolver(视图解析器)

扩展点

1、自定义参数解析器
我们经常用的,比如用注解 @RequestBody 修饰参数,最终 SpringMVC 会通过自带的 RequestResponseBodyMethodProcessor 解析器进行解析,使用 Jackson 提供的 MappingJackson2HttpMessageConverter 转换器将JSON数据转换成我们想要的格式。如果提交的是正常表单数据,用 @RequestParam 修饰参数,最终 SpringMVC 会通过自带的 RequestParamMethodArgumentResolver 解析器解析出表单里面的 value,然后找到合适的转换器将数据装换成我们想要的格式。那么如何自定义一个参数解析器那?
自定义解析器需要实现HandlerMethodArgumentResolver接口,HandlerMethodArgumentResolver接口包含两个方法:
supportsParameter:用于判定是否需要处理该参数分解,返回true为需要,并会去调用下面的方法
resolveArgument:真正用于处理参数分解的方法,返回的Object就是controller方法上的形参对象。

通过定义个配置类继承WebMvcConfigurationSupport或者WebMvcConfigure类在addArgumentResolvers方法里面把自定义的参数解析器添加进去,这些spring mvc在进行参数解析的时候会调用

public class UserArgumentsResolver implements HandlerMethodArgumentResolver {
 @Override
 public boolean supportsParameter(MethodParameter parameter) {
 return parameter.hasParameterAnnotation(UserParam .class);
 }
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
		NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
	UserInfo userVo = new UserInfo ();
	userVo.setName("张三");
	userVo.setDept("研发部")
	return userVo;
}


@Target(ElementType.PARAMETER)
 @Retention(RetentionPolicy.RUNTIME)
 public @interface UserParam {}
@ResponseBody
 @RequestMapping(value = “test”, method = RequestMethod.GET)
 public String test(@UserParam UserInfo userInfo) {
 System.out.println(userInfo.getName());
 return “success”;
 }