springMVC 源码阅读(从servlet开始讲)
git:https://github.com/zhangpeibisha?tab=repositories
众所周知,springMVC的核心为DispatcherServlet,我们配置SpringMVC时需要在web.xml中配置这个servlet,那么我们就可以理解为:dispathcherServlet也是按照我们最基础的servlet进行执行的。在springmvc的类依赖图中可以看见他的继承结构:
由图所知,dispatcherServlet最基础的继承确实GenericServlet,而在平时我们就是使用GenericServlet中的:
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException
这个方法进行处理请求的,那么springmvc由于也是基于这个类进行实现的,那么他肯定也是由这个方法进行最终的处理请求,我们继续往下看:由于在HttpServletBean中主要做的是将配置参数映射到此servlet的bean属性,以及调用子类初始化。所以暂时不讲解,所以我们现在看框架定制的servlet,由于有了之前的类的铺垫,所以现在FrameworkServlet需要开始完成框架中需要的业务了,我们来看源码,在这个正式执行处理方法中,我们看到他其实是调用了
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
这个方法,因此,我们在看这个方法中主要是调用了
protected abstract void doService(HttpServletRequest request, HttpServletResponse response)
throws Exception;
这个方法,而这个方法正好是DispatcherServlet需要实现的方法,现在先倒推回去,我们会发现,所有源头都是只想service()方法的,而框架需要做的事其实就是在原有框架中对请求进行包装请求,让我们使用servlet更加方便。
好了,现在我们继续看SpringMvc的核心部分:首先看DispatcherServlet中实现的doService()方法,其实看其中源码就知道了,这个方法调用的核心其实就是doDispatcherServlet方法,而这个方法就是整个SpringMvc的核心方法,在百度中的所有时序图都是由这个方法画出来的,在这个方法中,官方给出的解释为:
*处理实际调度到处理程序。
* <p>将通过按顺序应用servlet的HandlerMappings来获取处理程序。
*将通过查询servlet安装的HandlerAdapter获取HandlerAdapter
*找到第一个支持处理程序类。
* <p>此方法处理所有HTTP方法。 这取决于HandlerAdapters或处理程序
*自己决定哪些方法可以接受。
而这句话也在源码中进行了体现:我将源码粘贴出来,上面有我的解释,而且该源码也体现了在网上看到的时序图的执行过程是相同的。
/**
* 处理实际调度到处理程序。
* <p>将通过按顺序应用servlet的HandlerMappings来获取处理程序。
* 将通过查询servlet安装的HandlerAdapter获取HandlerAdapter
* 找到第一个支持处理程序类。
* <p>此方法处理所有HTTP方法。 这取决于HandlerAdapters或处理程序
* 自己决定哪些方法可以接受。
* 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 {
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);
// 通过request获取处理程序执行链(HandlerExecutionChain)
// 该处使用了任务链模式
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// 通过获取的程序执行处理链获取到handlerAdapter(适配器)
// 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();
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;
}
}
// 在controller执行前执行拦截器链
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 实际上调用处理程序。
// 执行HandlerAdapter对象的handler方法,返回ModelAndView
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
// 在controller执行结束后执行拦截器的相关方法
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);
}
}
}
}