spring mvc工作原理浅析

spring mvc执行流程概括

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

执行流程图

(1)第一步是找控制器,通过HandleMapping(处理器映射器),遍历所有实现了HandleMapping接口的实现类对象,找到合适的handle,返回给中央控制器(DispatcherServlet),最终返回的是一个handleExecutionChain类对象
(2)第二步是执行控制器,第一步已经拿到了控制器,接下来要去执行控制器,也就是拿到控制器适配器(handleAdapter中执行控制器,执行handler 方法,得到 ModelAndView 对象,为什么需要适配器,可以理解为我们现在都是使用@Controller、@RequestMapping注解来标注控制器,其实还可以通过继承Controller类实现handleRequest方法来处理用户请求,请求的地址还可以在xml中配置,总之就是执行控制器的方法不一样,所以spring mvc设计了不同的适配器来执行
(3)返回视图对象,然后把视图对象交给视图解析器,去渲染,最后响应给用户。
在这里插入图片描述

如何根据用户请求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方法里面完成
在这里插入图片描述
在doGet()、doGet()方法里面会调用processRequest(request, response)
在这里插入图片描述
在processRequest方法里面调用doService(request, response)
在这里插入图片描述
最后找到最核心的方法doDispatch
在这里插入图片描述
下面重点分析一下doDispatch方法里面的逻辑
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
经过上面的分析,大概了解了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”;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值