该文章主要介绍了DispatcherServlet的主要逻辑实现 – doDispatch方法,包括拦截器各个方法调用时机、Handler的查找和调用等主要逻辑
DispatcherServlet主要在doDispatch中分发请求以及拦截器的调用,
(源代码下方有流程图)
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
...
// 检查是否为multipart/*类型
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// 确认支持当前请求Handler的Adapter,用于调用Handler的handle方法
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 处理last-modified请求头
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
// 对拦截器链preHandle的调用
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// HandlerAdapter代理执行Handler的handle方法
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
...
//进行视图的渲染
applyDefaultViewName(processedRequest, mv);
//调用拦截器链的postHandle方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
...
}
转换成流程图如下:
当一个请求到来时:
1、根据request的uri和其他信息(比如HttpMethod、Header等信息)确定Handler,选择支持该类型Hanlder的HandlerAdapter(HandlerAdapter主要用于对Handler的handle方法调用:处理函数参数的注入、返回值的处理等);
//确认处理当前请求的Handler
mappedHandler = getHandler(processedRequest);
...
// 确认支持当前请求Handler的Adapter,用于调用Handler的handle方法
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
2、如果是Get或者Head请求,判断文件修改时间;如果未修改直接返回;RequestMappingAdapter的修改时间默认返回-1,即判断文件修改时间总是返回false;
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
3、从步骤1中确定的Hanlder是一条包含拦截器集合和Hanlder的调用链,DispatcherServlet调用所有拦截器的preHandle方法;
// 对拦截器链preHandle的调用
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
4、handler通过adapter进行调用,主要进行参数值的匹配和注入
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
5、渲染视图
//进行视图的渲染
applyDefaultViewName(processedRequest, mv);
6、调用拦截器postHandle方法(逆序调用)
//调用拦截器链的postHandle方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
7、对正常完成的部分拦截器调用afterCompletion;例如
拦截器1 --> 拦截器2 --> 拦截器3 …
拦截器3抛出异常
afterCompletion的调用过程
拦截器2 --> 拦截器1 …
这里拦截器调用有三种情况:
1、对于拦截器返回false的情况,直接返回,不调用postHandle和afterCompletion方法;
2、对于中间拦截器抛出异常,对于成功执行的拦截器,反序调用其afterCompletion方法;
3、如果拦截器成功执行,所有拦截器的afterCompletion反序调用
即按照成功执行preHandle方法后的拦截器逆序调用。