接下来将会分析SpringMVC是怎么处理请求的,首先会分析HttpServletBean、FrameServlet和DispatcherServlet,然后再看一下核心方法doDispatch
HttpServletBean主要参与创建工作,没有涉及请求的处理
FrameworkServlet:
servlet的处理流程是:首先从Servlet接口的service方法开始,然后在HttpServlet的service方法中根据请求的类型路由到doGet、doPost等方法上:
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//获取请求的方法
String method = request.getMethod();
//根据是否是PATCH类型
if (method.equalsIgnoreCase(RequestMethod.PATCH.name())) {
processRequest(request, response);
}
else {
super.service(request, response);
}
}
我们发现在service方法中对于除了PATCH类型,都交给了父类去处理,processRequest方法是处理请求的核心方法:
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
long startTime = System.currentTimeMillis();
Throwable failureCause = null;
//获取LocaleContextHolder中原来保存的LocaleContext
LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
//获取当前请求的LocaleContext
LocaleContext localeContext = buildLocaleContext(request);
//获取原来保存的requestAttributes
RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
//获取当前请求的requestAttributes
ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
//设置当前请求的requestAttributes和localeContext
initContextHolders(request, localeContext, requestAttributes);
try {
//请求处理的入口
doService(request, response);
}
...
finally {
//恢复原来的设置
resetContextHolders(request, previousLocaleContext, previousAttributes);
if (requestAttributes != null) {
requestAttributes.requestCompleted();
}
...
//发布一个请求处理的消息
publishRequestHandledEvent(request, response, startTime, failureCause);
}
}
在这个方法中最终处理还是交给了doService,这个方法留给了DispatcherServlet来实现,在这之前和之后还做了LocaleContext和RequestAttributes的设置及恢复,处理完后发布ServletRequestHandledEvent消息以及使用request获取到了异步管理器并且注册了拦截器。
DispatcherServlet
在处理请求的过程中doService是这个Servlet 的入口方法:
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
Map attributesSnapshot = null;
//判断是否是include请求
if (WebUtils.isIncludeRequest(request)) {
//对request里面的属性进行快照备份
attributesSnapshot = new HashMap();
Enumeration> attrNames = request.getAttributeNames();
while (attrNames.hasMoreElements()) {
String attrName = (String) attrNames.nextElement();
if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
}
// 设置一些属性
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
//用于redirect是的参数传递
FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
if (inputFlashMap != null) {
request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
}
request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
try {
//处理请求的核心方法
doDispatch(request, response);
}
finally {
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// 如果是保存的快照属性不为空,需要个request恢复快照属性
if (attributesSnapshot != null) {
restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
}
在这个方法中首先判断当前request是否是include类型的,如果是需要对他里面的属性进行快照备份,然后个request设置上一些必要的属性,然后调用doDispatch处理请求,最后如果是include类型的request,需要给它恢复属性
doDispatch方法最核心的代码只有四句:
mappedHandler = getHandler(processedRequest);
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException)
1、根据request找到对应的handler
2、根据handler找到对应的handlerAdapter
3、用handlerAdapter处理handler
4、调用processDispatchResult处理上面处理之后的结果
Handler:处理器,直接对应着MVC中的controller层,标注了RequestMapping的所有方法都可以看成一个Handler。只要可以实际处理请求就可以使Handler
HandlerMapping:用来查找Handler
HandlerAdapter:让固定的Servlet处理方法调用灵活的Handler来进行处理
View:展示数据
ViewResolver:查找View
来看一下doDispatch的代码:
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找到对应的Handler
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// 根据Handler找到对应的HandlerAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
//处理get、head请求的Last-Modified
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;
}
}
//执行拦截器的preHandle
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// HandlerAdapter使用handler处理请求
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
//如果需要异步处理直接返回
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
//如果view为空,根据request设置默认的view
applyDefaultViewName(request, mv);
//执行拦截器的postHandle方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
//处理上面的处理结果。包括异常处理,渲染页面,发出完成通知触发拦截器的afterCompletion
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Error err) {
triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
}
finally {
//判断是否执行异步请求
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// 删除上传请求的资源
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
doDispatch首先会检查是不是上传请求,如果是上传请求,则将request转换为MultipartHttpServletRequest,并将multipartRequestParsed标志设置为true,然后通过getHandler方法获取Handler处理器链:
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace(
"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
}
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}
在返回的处理器链中,包含着一些拦截器和handler就像Pipline中的处理过程一样
在请求处理完成之后,就要使用processDispatchResult方法处理之前返回的结果:
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {
boolean errorView = false;
//异常处理
if (exception != null) {
if (exception instanceof ModelAndViewDefiningException) {
logger.debug("ModelAndViewDefiningException encountered", exception);
mv = ((ModelAndViewDefiningException) exception).getModelAndView();
}
else {
Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
mv = processHandlerException(request, response, handler, exception);
errorView = (mv != null);
}
}
// 渲染页面
if (mv != null && !mv.wasCleared()) {
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
"': assuming HandlerAdapter completed request handling");
}
}
//如果启动了异步处理则返回
if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
return;
}
//请求处理完成之后触发拦截器AfterCompletion
if (mappedHandler != null) {
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
在处理错误的时候会将错误信息设置到view中,然后通过render方法渲染页面,最后触发拦截器的拦截的事件。