作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO
联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬
学习必须往深处挖,挖的越深,基础越扎实!
阶段1、深入多线程
阶段2、深入多线程设计模式
阶段3、深入juc源码解析
码哥源码部分
码哥讲源码-原理源码篇【2024年最新大厂关于线程池使用的场景题】
码哥讲源码-原理源码篇【揭秘join方法的唤醒本质上决定于jvm的底层析构函数】
码哥源码-原理源码篇【Doug Lea为什么要将成员变量赋值给局部变量后再操作?】
码哥讲源码【谁再说Spring不支持多线程事务,你给我抽他!】
打脸系列【020-3小时讲解MESI协议和volatile之间的关系,那些将x86下的验证结果当作最终结果的水货们请闭嘴】
文将通过阅读源码的方式带大家了解springmvc处理请求的完整流程,干货满满。
1、先了解下SpringMVC常用的10组件
1.1、DispatcherServlet:前端控制器
这个大家是最熟悉的,是一个servlet,是springmvc处理请求的入口,不需要咱们开发,由框架提供。
作用:统一处理请求和响应,整个流程控制的中心,由它来调用其他组件处理用户的请求。
1.2、HandlerMapping:处理器映射器
作用:根据请求的信息(如url、method、header等)查找请求处理器,即找到自定义的controller中处理请求的方法。
HandlerMapping接口源码如下,getHandler:根据请求查找请求处理器,会返回一个HandlerExecutionChain对象。
public interface HandlerMapping {
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}
常见的实现类:
- RequestMappingHandlerMapping:请求映射处理器映射,用来处理@RequestMapping定义的处理器的
1.3、HandlerExecutionChain:处理器执行链
HandlerMapping#getHandler方法会根据请求得到一个HandlerExecutionChain对象。
HandlerExecutionChain源码如下,主要包含了3个信息
- handler:请求处理器,通常就是我们自定义的controller对象及方法
- interceptorList:拦截器,当前请求匹配到的拦截器列表
- interceptorIndex:拦截器索引,用来记录执行到第几个拦截器了
public class HandlerExecutionChain {
private final Object handler;
private final List<HandlerInterceptor> interceptorList = new ArrayList<>();
private int interceptorIndex = -1;
}
1.4、handler:处理器
通常需要我们自己开发,一般指我们自定义的controller,在DispatcherServlet的控制下handler对具体的请求进行处理。
1.5、HandlerAdapter:处理器适配器
他负责对handler的方法进行调用,由于handler的类型可能有很多种,每种handler的调用过程可能不一样,此时就需要用到适配器HandlerAdapte,适配器对外暴露了统一的调用方式(见其handle方法),内部将handler的调用过程屏蔽了,HandlerAdapter接口源码如下,主要有2个方法需要注意:
- supports:当前HandlerAdapter是否支持handler,其内部主要就是判HandlerAdapter是否能够处理handler的调用
- handle:其内部负责调用handler的来处理用户的请求,返回返回一个ModelAndView对象
public interface HandlerAdapter {
boolean supports(Object handler);
@Nullable
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
}
常见的实现类:
- RequestMappingHandlerAdapter:其内部用来调用@RequestMapping标注的方法
1.6、ModelAndView:模型和视图
这个对象中主要用来存放视图的名称和共享给客户端的数据。
public class ModelAndView {
/*视图*/
@Nullable
private Object view;
/*模型,用来存放共享给客户端的数据*/
@Nullable
private ModelMap model;
}
1.7、ViewResolver:视图解析器
这个是框架提供的,不需要咱们自己开发,它负责视图解析,根据视图的名称得到对应的视图对象(View)。
ViewResolver接口源码
public interface ViewResolver {
@Nullable
View resolveViewName(String viewName, Locale locale) throws Exception;
}
这个接口有很多实现类,比如jsp的、freemarker、thymeleaf的等,他们都有各自对应的ViewResolver。
而比较常的实现类是InternalResourceViewResolver
,这个大家应该比较熟悉吧,目前为止我们前面的文章用到的都是这个视图解析器,用来处理jsp格式的视图页面,带大家再回顾一下这个类的配置,如下
<!-- 添加视图解析器 -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/view/"/>
<property name="suffix" value=".jsp"/>
</bean>
InternalResourceViewResolver比较重要,这里说下这个类的resolveViewName方法获取视图的过程 ,大家也可以去阅读InternalResourceViewResolver#resolveViewName方法获得
,大致的过程如下:
step1:判断视图viewName是否以redirect:
开头,如果是,则返回RedirectView
类型的视图对象,RedirectView是用来重定向的,RedirectView内部用到的是response.sendRedirect(url)
进行页面重定向;否则继续向下step2
step2:判断viewName是否以forward:
开头,如果是,则返回InternalResourceView
类型的视图对象,InternalResourceView是用来做跳转的,InternalResourceView内部用到的是request.getRequestDispatcher(path).forward(request, response)
进行页面跳转;否则继续向下step3
step3:判断当前项目是否存在jstl所需的类,如果是,则返回JstlView类型的视图,否则返回InternalResourceView类型的视图,这两个视图的render方法最终会通过request.getRequestDispatcher(path).forward(request, response)
进行页面的跳转,跳转的路径是:InternalResourceViewResolver的前缀prefix + viewName+InternalResourceViewResolver的后缀prefix
1.8、View:视图
负责将结果展示给用户,View接口源码如下,render方法根据指定的模型数据(model)渲染视图,即render方法负责将结果输出给客户端。
public interface View {
void render(@Nullable Map<String, ?> model, HttpServletRequest request, HttpServletResponse response)
throws Exception;
}
View接口常见的2个实现类
- RedirectView :负责重定向的,内部通过
response.sendRedirect(url)
进行页面重定向 - InternalResourceViewResolver :负责页面跳转的,内部通过
request.getRequestDispatcher(pa