先看一下SpringMVC的处理流程:

各个组件的作用:

  • DispatcherServlet:分发请求
  • HandlerMapping:根据URL匹配能够处理当前requestHandler(也就是我们的 Controller )和拦截器
  • HandlerAdapter:负责实际执行Handler的处理方法,并返回ModelAndView
  • ViewResolver:将ModelAndView解析为实际的视图

具体过程

  1. 首先用户发送请求 —> DispatcherServlet,前端控制器收到请求后自己不进行处理,而是委托给其他的解析器进行 处理,作为统一访问点,进行全局的流程控制;
  2. DispatcherServlet —> HandlerMapping, HandlerMapping 将会把请求映射为 HandlerExecutionChain 对象(包含Handler 处理器和HandlerInterceptor 拦截器)对象
  3. DispatcherServlet —> HandlerAdapter,HandlerAdapter 将会根据适配的结果调用真正的处理器的功能处理方法,完成功能处理,并返回 ModelAndView;
  4. ModelAndView —> ViewResolver,ViewResolver 将把ModelAndView中的逻辑视图名解析为具体的 View
  5. View —> 渲染,View 会根据传进来的 Model 模型数据进行渲染
  6. 返回控制权给 DispatcherServlet,由 DispatcherServlet 返回响应给用户,到此一个流程结束。

上面的流程有两个关键点:HandlerMappingHandlerAdapterHandlerAdapter据说是使用了适配器模式,但具体适配了什么,我一直不知道🤨,直到后面看到了一篇博客才明白。至于它俩的作用,还得从Controller的定义方式说起

SpringMVC中定义Controller的方式有三种:

  • @RequestMapping最最最常用的方式,除了这个都不知道其他的了🤣
  • 继承 org.springframework.web.servlet.mvc.Controller接口,大概是这样:
1
2
3
4
5
6
7
8
9
@Component("/home")
public class HomeController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
...
return null;
}
}
  • 继承 org.springframework.web.HttpRequestHandler接口

不管后面两个怎么实现,总之,他们仨的处理方式是不一样的,需要用到不同的HandlerMappingHandlerAdapter处理,比如:

  • @RequestMappingRequestMappingHandlerMappingRequestMappingHandlerAdapter
  • Controller接口 → BeanNameUrlHandlerMappingHttpRequestHandlerAdapter
  • HttpRequestHandler接口 → BeanNameUrlHandlerMappingHttpRequestHandlerAdapter

HandlerMapping

HandlerMapping处理后所有的URL和对应的Handler都会被放在一个Map里做映射,这里其实是用了一个策略模式根据Controller定义方式的不同使用不同策略的HandlerMapping去处理

HandlerMapping 是一个策略接口,RequestMappingHandlerMappingBeanNameUrlHandlerMapping是对应的具体策略

HandlerExecutionChain是一个封装策略的上下文角色

来看一下如何根据request来获取HandlerMapping

1
2
3
4
5
6
7
8
9
10
11
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}

HandlerAdapter

说完HandlerMapping之后,下面就要来介绍HandlerAdapter了。

既然Handler有多种实现形式,但是Servlet需要的处理方法的结构却是固定的,都是以requestresponse作为方法入参,因此HandlerAdapter的实现类都实现了统一的handle()方法来处理Servlet

不过由于上面提到的Handler的形式不同,@RequestMapping对应的Handler是一个方法,而其他两个对应的Handler是一个类,而HandlerAdapter使用了适配器模式能够模糊掉具体的实现,从而就能提供统一访问接口(妙😎)

我们来看一下getHandlerAdapter()方法,注意Handler是Object类型:

1
2
3
4
5
6
7
8
9
10
protected HandlerAdapter getHandlerAdapter(Object handler) 
throws ServletException {
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
if (adapter.supports(handler)) {
return adapter;
}
}
}
}

DispatcherServlet的分发流程

最后看一下DispatcherServlet#doDispatch()的分发流程,注意DispatcherServlet是如何使用HandlerMappingHandlerAdapter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
...
//1、根据URL(当然不一定非得是URL)匹配到一个处理器
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
// 若匹配不到Handler处理器,就404了
noHandlerFound(processedRequest, response);
return;
}

//2、从HandlerExecutionChain里拿出Handler,然后找到属于它的适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
...
//3、执行Handler上的所有拦截器的Pre方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
//4、真正执行handle方法,得到一个ModelAndView
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

//5、视图渲染
applyDefaultViewName(processedRequest, mv);

//6、执行拦截器的post方法(视图渲染完成后执行)
mappedHandler.applyPostHandle(processedRequest, response, mv);
...
//7、执行拦截器的afterCompletion方法(不管抛出与否)
}

参考: