DispatcherServlet#doDispatch()

DispatcherServlet复写父类的doService()方法,其中最主要的处理客户端发的请求便是doDispath()方法,我们只深究此方法,大致上看下其中的逻辑

注释瞧一发

/**
* Process the actual dispatching to the handler.
* <p>The handler will be obtained by applying the servlet's HandlerMappings in order.
* The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters
* to find the first that supports the handler class.
* <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers
* themselves to decide which methods are acceptable.
* @param request current HTTP request
* @param response current HTTP response
* @throws Exception in case of any kind of processing failure
*/

由官方注释中可得出以下结论:

源码简析

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
//这里的processedRequest主要用于文件上传类的请求
HttpServletRequest processedRequest = request;
//mappedHandler是处理的核心,此处可以理解为处理链
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.优先从HandlerMappings中获取处理器对象
mappedHandler = getHandler(processedRequest);
//这里找不到handler则会出现我们熟悉的"No mapping found"日志打印
if (mappedHandler == null || mappedHandler.getHandler() == null) {
//返回404错误
noHandlerFound(processedRequest, response);
return;
} //HandlerAdapter必须拥有,否则会抛异常
//最终通过此对象来获取视图对象
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
//获取上次修改事时间,第一次访问为-1L
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
//对未修改的资源get请求,直接返回302状态码
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
//拦截器处理请求,调用拦截接口preHandle方法,一旦HandlerInteceptor返回false,则表示拦截成功
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
} // Actually invoke the handler.通过HandlerAdapter处理请求返回逻辑试图
mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); //异步请求直接返回
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
//倘若mv对象内部没有逻辑视图名则采取默认视图
applyDefaultViewName(processedRequest, mv);
//调用拦截器接口的postHandle()接口
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
//处理过程中出现了异常
dispatchException = ex;
}
//再次处理,如果有异常出现则需要处理异常信息,因为异常也可有对应的视图
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
//processDispatchResult()出现异常时调用
//倒序调用之前已调用过的HandlerInteceptor接口的afterCompletion()方法,再直接返回异常信息给客户端
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Error err) {
//processDispatchResult()出现异常时调用
//倒序调用之前已调用过的HandlerInteceptor接口的afterCompletion()方法,再直接返回异常信息给客户端
triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
//调用所有的实现了AsyncHandlerInterceptor接口的afterConcurrentHandlingStarted()方法
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
//清除文件上传请求的相关信息,释放资源
cleanupMultipart(processedRequest);
}
}
}
}

DispatcherServlet#getHandler()-获取HandlerExecutionChain处理链

简单代码如下

	protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
for (HandlerMapping hm : this.handlerMappings) {
//根据HandlerMapping对象获取处理链
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}

主要是注意此处的handlerMappings属性,根据我们在springmvc配置中常用mvc:annotation-driven节点,我们可以得知包含的属性主要有

  • RequestMappingHandlerMapping 主要解析@Controller注解类并解析其中包含@RequestMapping的注解方法包装为HandlerMethod作为handler对象
  • BeanNameUrlHandlerMapping 对含有/开头的beanName注册为handler,handler对象则为其本身在springmvc上下文中对应的class类实例
  • SimpleUrlHandlerMapping 即采用urlMap保存路径与处理类的关系,即可以直接指定url对应handler对象,其中handler对象多为beanName对应的class类【此处不包含】

DispatcherServlet#getHandlerAdapter()-获取Handler适配器

获取适配器的目的是为了通过其获取视图对象

	//参数handler一般为具体对象
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
//此处的handler可为HandlerMethod/HttpRequestHandler/Controller/Servlet
for (HandlerAdapter ha : this.handlerAdapters) {
//supports方法代表其支持何种handler对象,也就是适配器的意义所在
if (ha.supports(handler)) {
return ha;
}
}
//此处可知当HandlerAdapter没有找到则会抛出ServletException异常
throw new ServletException("No adapter for handler [" + handler +
"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}

HandlerExecutionChain#applyPreHandle()-对请求进行拦截的预处理

调用对应请求路径的拦截器集合的统一方法,源码奉上

	boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
//获取内部的HandlerInterceptor集合
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
//依次执行
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
//调用拦截器的preHandle()方法,一旦返回false则提前结束请求
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
}
return true;
}

HandlerAdapter#handle()-对请求进行业务处理并返回视图对象

限于篇幅过长,具体可见>>>SpringMVC源码情操陶冶-HandlerAdapter适配器简析

DispatcherServlet#processDispatchResult()-解析视图对象返回结果

主要处理视图和异常视图,具体源码奉上

	private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception { boolean errorView = false;
//对存在异常的优先处理
if (exception != null) {
//是否为ModelAndViewDefinitionException异常
if (exception instanceof ModelAndViewDefiningException) {
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
}
else {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
//根据异常解析类来解析特定的异常
mv = processHandlerException(request, response, handler, exception);
errorView = (mv != null);
}
} // Did the handler return a view to render?
if (mv != null && !mv.wasCleared()) {
//对视图进行渲染
render(mv, request, response);
//针对异常的视图,清除request对象中的error属性
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
} if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Concurrent handling started during a forward
return;
} //执行拦截器中的afterCompletion()方法
if (mappedHandler != null) {
mappedHandler.triggerAfterCompletion(request, response, null);
}
}

由以上代码可知springmvc优先对异常作视图解析,然后通过render()方法渲染视图返回给前台。这其中也会调用拦截器的afterCompletion()方法来收尾

DispatcherServlet#processHandlerException()-处理异常返回ModelAndView

通过已注册的HandlerExceptionResolver集合来解析异常返回视图,源码奉上

	protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,
Object handler, Exception ex) throws Exception { // Check registered HandlerExceptionResolvers...
ModelAndView exMv = null;
//遍历异常类解析器集合,解析成功则返回
for (HandlerExceptionResolver handlerExceptionResolver : this.handlerExceptionResolvers) {
//解析器解析异常,查找是否有配备的异常视图
exMv = handlerExceptionResolver.resolveException(request, response, handler, ex);
if (exMv != null) {
break;
}
}
if (exMv != null) {
//判断model和view是否为空
if (exMv.isEmpty()) {
request.setAttribute(EXCEPTION_ATTRIBUTE, ex);
return null;
}
//尝试设置默认的view对象,默认操作为
//比如"/view/req"-->设置"view/req"为viewName
if (!exMv.hasView()) {
exMv.setViewName(getDefaultViewName(request));
}
//将异常信息保存至request对象中
WebUtils.exposeErrorRequestAttributes(request, ex, getServletName());
return exMv;
}
//如果解析器没有解析到合适的视图对象则直接抛出异常
throw ex;
}

DispatcherServlet#render()-渲染视图

渲染视图返回给前端页面,具体源码奉上

	protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
// Determine locale for request and apply it to the response.
Locale locale = this.localeResolver.resolveLocale(request);
response.setLocale(locale); View view;
//判断mv内部属性view是否为string类型
if (mv.isReference()) {
// 根据mv通过viewResolvers集合(FreemarkerResolver/VelocityResolver..)解析获取视图对象
// 包括寻找页面
view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);
if (view == null) {
throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
"' in servlet with name '" + getServletName() + "'");
}
}
else {
// No need to lookup: the ModelAndView object contains the actual View object.
//表明存储在ModelAndView对象内部的view要么是String.class类型要么是View.class类型
view = mv.getView();
if (view == null) {
throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
"View object in servlet with name '" + getServletName() + "'");
}
}
try {
//最后才是对视图的渲染,返回具体页面给前台
view.render(mv.getModelInternal(), request, response);
}
catch (Exception ex) {
//渲染失败仍会抛出异常直接返回给前端
throw ex;
}
}

小结

04-04 00:45