前提要点
本篇文章使用的项目为SpringMVC源码分析------基础知识(二)的代码
1.重要的DispatcherServlet
DispatcherServlet是SpringMVC的核心类,俗称前端控制器。
客户端所有请求都会转发到它执行,最终能够执行我们的url请求(根据url找到请求方法,利用反射执行)
2.关键源码分析
我们了解了DispatcherServlet是前端控制器,那么我们前端的请求一定会通过他的处理。我们来看看DispatcherServlet这个类。
查看类图(ctrl+alt+u)
可以看到他的父类是FrameworkServlet,而FrameworkServlet父类是HttpServlet,在java中,子类的运行需要先执行父类的方法,所以就先执行HttpServlet的方法。看到HttpServlet的service()方法。
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String method = req.getMethod();
if (method.equals(METHOD_GET)) {
long lastModified = getLastModified(req);
if (lastModified == -1) {
// servlet doesn't support if-modified-since, no reason
// to go through further expensive logic
doGet(req, resp);
} else {
long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
if (ifModifiedSince < lastModified) {
// If the servlet mod time is later, call doGet()
// Round down to the nearest second for a proper compare
// A ifModifiedSince of -1 will always be less
maybeSetLastModified(resp, lastModified);
doGet(req, resp);
} else {
resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
}
} else if (method.equals(METHOD_HEAD)) {
long lastModified = getLastModified(req);
maybeSetLastModified(resp, lastModified);
doHead(req, resp);
} else if (method.equals(METHOD_POST)) {
doPost(req, resp);
} else if (method.equals(METHOD_PUT)) {
doPut(req, resp);
} else if (method.equals(METHOD_DELETE)) {
doDelete(req, resp);
} else if (method.equals(METHOD_OPTIONS)) {
doOptions(req,resp);
} else if (method.equals(METHOD_TRACE)) {
doTrace(req,resp);
} else {
//
// Note that this means NO servlet supports whatever
// method was requested, anywhere on this server.
//
String errMsg = lStrings.getString("http.method_not_implemented");
Object[] errArgs = new Object[1];
errArgs[0] = method;
errMsg = MessageFormat.format(errMsg, errArgs);
resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
}
}
我们在项目中定义的均为GET方法,所以此方法执行到doGet(req, resp)方法。
进入到子类FrameworkServlet的doGet方法
进入此方法,可以看到
这个doService()就是核心方法。进入看看(进入之后会发现我们来到了前端控制器,也就是DispatcherServlet)
再跳到doDispatch(request, response),进入此方法。
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();
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.
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);
}
}
}
}
现在我们来看看这个方法doDispatch(HttpServletRequest request, HttpServletResponse response)。
processedRequest = checkMultipart(request);
判断是否属于文件上传mappedHandler = getHandler(processedRequest);
进入getHandler()方法查看
我们可以通过debug查看for循环中的HandlerMapping。
一共有五个,我们了解前面两个即可。我们主要看第一个。查看数据
this.handlerMapping[0]数据可以看到有我们定义的拦截器,还有url映射。这时候我们就知道了,HandlerMapping是储存mvc的所有信息的。this.handlerMapping[1]数据是差不多的,他只不过是收集xml启动配置信息。而this.handlerMapping[0]数据是收集注解方式启动的配置信息。
在看到
进入之后
再进入
lookupPath变量存储的就是访问的url。
我们在回到DispatcherServlet。HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());寻找适配器
此方法主要判断是否为HandlerMethod子类,后面supportsInternal((HandlerMethod) handler)这一个判断在handler instanceof HandlerMethod为true的情况下,返回true。if (!mappedHandler.applyPreHandle(processedRequest, response))
PreHandle应该很熟悉。这不就是我们的拦截器第一个方法?
进入看代码。
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 获取所有的拦截器
HandlerInterceptor[] interceptors = getInterceptors();
// 拦截器判空
if (!ObjectUtils.isEmpty(interceptors)) {
// 遍历所有拦截器
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
// 调用拦截器的preHandle()方法
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
}
return true;
}
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
里面有几个重要的语句
if (this.synchronizeOnSession)
判断是否使用session
invokeHandlerMethod(request, response, handlerMethod);
执行目标方法mappedHandler.applyPostHandle(processedRequest, response, mv);
和第四小点一样的,执行拦截器的PostHandle()方法,内部方法一样的,就不看了。processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
进入查看方法。
render(mv, request, response);
设置渲染视图
mappedHandler.triggerAfterCompletion(request, response, null);
这个方法点击进入查看~~(其实看着这个AfterCompletion眼熟的话,应该知道是干嘛了)~~
很容易理解,这是拦截器的AfterCompletion()方法的调用,这也解释了,我们在基础知识(二)中提到的问题,为什么有两个都是在目标方法执行之后。其实,他们的区别就在于一个(PreHandle)在设置渲染之前,一个(AfterCompletion)在设置渲染之后