前言
好长时间就在想,SpringMVC框架入口就是一个简单的servlet,是如何做到只是通过一些简单的注解就能让请求地址找到对应的方法,并且执行呢?注解又是如何解析的呢?
网上说的云里雾里,什么HandlerMapping
,什么HandlerAdapter
还有视图解析器?感觉好高大上的感觉一定很复杂把。但是这些组件是如何工作的,又是如何生成的呢?说实在的,现在的我也是懵懵懂懂。
1.SpringMVC初始化解析
现在我也不是很了解是怎么工作的,既然不知道,那就从入口开始吧。入口就是一个DispatcherServlet
,既然是通过servlet
进行配置的,那么一定遵循servlet
原理吧。
DispatcherServlet
负责完成的是SpringMVC具体内容,比如SpringMVC9大组件。
FrameworkServlet
负责完成容器上下文的建立。
HttpServletBean
进行初始化。
- 既然是servlet,那就找
init
方法了,执行HttpServletBean
的init
方法。 - 通过init方法调用
FrameworkServlet
的initServletBean
进行上下文初始化。 - 调用
initWebApplicationContext
方法进行初始化。这个方法中内容比较乱,设计到spring父子容器的内容,但是这里就任务只是配置了SpringMVC,不存在父容器。 - 既然不存在父容器,那么
wac
一定是null,那么就会执行createWebApplicationContext
方法。这个方法是创建一个全新的spring容器,作为SpringMVC的容器,(SpringMVC容器和spring容器其实不在一起); - 接着下面就直接按照流程跑就可以了,最后调用
wac.refresh
进行容器的初始化。容器初始化流程比较复杂,这里完成的功能点有:- ioc容器初始化,扫描包,注解处理。生成
BeanDefinition
- ioc注入 等等
- ioc容器初始化,扫描包,注解处理。生成
- 容器初始化完成之后,SpringMVC进行初始化组件。
- SpringMVC有9大组件,包括
HandlerMapping
,HandlerAdapter
,等等都是在这里进行初始化。
2.SpringMVC的工作流程
springMVC的工作流程,网上一搜一大堆。。随意复制一段,如下:
1、用户发送请求至前端控制器DispatcherServlet。
2、DispatcherServlet收到请求调用HandlerMapping处理器映射器。
3、处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
4、 DispatcherServlet调用HandlerAdapter处理器适配器。
5、HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。
6、Controller执行完成返回ModelAndView。
7、HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。
8、DispatcherServlet将ModelAndView传给ViewReslover视图解析器。
9、ViewReslover解析后返回具体View.
10、DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。
11、DispatcherServlet响应用户。
想必大家一定都很熟悉,但是字一会就背下来了,但是真正的流程是啥样子的呢?不废话,上图。
既然是servlet
那么当请求进来,一定走service
方法,DispatchResult
的父类FrameworkServlet
中重写了此方法。
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
if (httpMethod == HttpMethod.PATCH || httpMethod == null) {
processRequest(request, response);
}
else {
// 虽然会走这个方法,但是到最后还会走到当前类的 processRequest方法
super.service(request, response);
}
}
接着就直接跟着流程走就可以。接着看到最后这个流程,这段代码有说明为什么是
DispatcherServlet
收到请求调用HandlerMapping
处理器映射器,DispatcherServlet
又是如何调用HandlerAdapter
处理器适配器的,视图又是如何进行解析的等等。
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
// 这就是传说中的 通过处理器映射器找到具体的处理器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
String method = request.getMethod();
// 如果是get或head 方法, 调用getLastModified()获取上次更新时间
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
//如果小于浏览器缓存更新时间则直接返回浏览器使用本地缓存
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
// 这一段就是传说中的 HandlerAdapter经过适配调用具体的处理器,通过反射调用Controller执行完成之后返回ModelAndView
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
// 这里就是交给视图解析器进行解析
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}