SpringMVC源码分析(二)
来源:互联网 发布:阿里云服务器硬盘扩容 编辑:程序博客网 时间:2024/05/16 13:41
上一篇博文SpringMVC源码分析(一) 中已经对SpringMVC中的Servlet(GenericServlet,HttpServlet,HttpServletBean,FrameworkServlet,DispatcherServlet)源码进行分析,今天接着分析SpringMVC请求处理过程。
SpringMVC请求处理过程主要由DispatchServlet来负责完成,FrameworkServlet是DispatchServlet的父类,先看一下FrameWorkServlet的处理请求过程。
当接收到请求时会调用service方法,代码如下:
@Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpMethod httpMethod = HttpMethod.resolve(request.getMethod()); if (HttpMethod.PATCH == httpMethod || httpMethod == null) { processRequest(request, response);//如果请求方式是PATCH时直接调用 } else { super.service(request, response);//调用父类的service方法,也就是HttpServlet的service方法 } }
service方法中会根据请求类型选择处理方式,比如get请求就会调用doGet()方法,
FrameworkServlet中重写doGet()方法,代码如下:
@Override protected final void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { processRequest(request, response); }
所以最后会调用processRequest处理请求,processRequest是FrameworkServlet类处理请求的核心方法。
protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { long startTime = System.currentTimeMillis(); Throwable failureCause = null; //获取LocalContextHolder中保存LocalContext(保存了本地化信息,比如zh-cn) LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext(); //获取当前请求的LocalContext(保存了本地化信息,比如zh-cn) LocaleContext localeContext = buildLocaleContext(request); //获取RequestContextHolder保存的RequestAttributes RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes(); //获取当前请求的RequestAttributes ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes); WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor()); //将当前的LocalContext和RequestAttributes分别放置到LocalContextHolder和RequestContextHolder中 initContextHolders(request, localeContext, requestAttributes); try { //实际处理请求的入口 doService(request, response);//在DispatchServlet中实现 } catch (ServletException ex) { failureCause = ex; throw ex; } catch (IOException ex) { failureCause = ex; throw ex; } catch (Throwable ex) { failureCause = ex; throw new NestedServletException("Request processing failed", ex); } finally { //恢复原来的LocalContext和ServletRequestAttributes到LocalContextHolder和RequestContextHolder中 resetContextHolders(request, previousLocaleContext, previousAttributes); if (requestAttributes != null) { requestAttributes.requestCompleted();//执行完这个方法后isRequestActive()返回值为false } if (logger.isDebugEnabled()) { if (failureCause != null) { this.logger.debug("Could not complete request", failureCause); } else { if (asyncManager.isConcurrentHandlingStarted()) { logger.debug("Leaving response open for concurrent processing"); } else { this.logger.debug("Successfully completed request"); } } } //发送servletRequestHandlerEvent消息 publishRequestHandledEvent(request, response, startTime, failureCause); } }
ServletRequestAttributes中封装了我们平时使用setAttribute和getAttribute方法,根据scope参数来判断是request还是session。
@Override public void setAttribute(String name, Object value, int scope) { if (scope == SCOPE_REQUEST) { if (!isRequestActive()) {//上面调用了requestCompleted之后就会变为false也就是不进行操作了 throw new IllegalStateException( "Cannot set request attribute - request is not active anymore!"); } this.request.setAttribute(name, value); } else { HttpSession session = getSession(true); this.sessionAttributesToUpdate.remove(name); session.setAttribute(name, value); } }
publishRequestHandledEvent方法是请求处理结束后会发出消息,无论请求是否成功都会发出。
接下来继续看service()处理请求,service方法会调用doService方法,doService是个模板方法,DispatcherServlet中重写了这个方法,我们转到ServletDispatcherServlet上分析处理请求过程,DispatcherServlet是Spring 的最核心的类。整个处理请求的过程的顶层设计都在这里。我们来看看DispatcherServlet的doService方法。
@Override protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception { if (logger.isDebugEnabled()) { String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : ""; logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed + " processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]"); } // Keep a snapshot of the request attributes in case of an include, // to be able to restore the original attributes after the include. Map<String, Object> attributesSnapshot = null; //当include请求时把request中的atrribute备份一份 if (WebUtils.isIncludeRequest(request)) { attributesSnapshot = new HashMap<String, Object>(); Enumeration<?> attrNames = request.getAttributeNames(); while (attrNames.hasMoreElements()) { String attrName = (String) attrNames.nextElement(); if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) { attributesSnapshot.put(attrName, request.getAttribute(attrName)); } } } // Make framework objects available to handlers and view objects. request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());//设置webApplication request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);//设置localResolver request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);//设置themeResolver request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());//设置themeResource FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);//用于redirect中attribute的数据传递 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()) { // Restore the original attribute snapshot, in case of an include. if (attributesSnapshot != null) { //还原request中的attribute restoreAttributesAfterInclude(request, attributesSnapshot); } } } }
继续追踪doDispatch方法,doDispatch主要的任务是根据request找到Handler,根据handler找到相对应的HandlerAdapter,用HandlerAdapter处理Handler,最后把结果通过processDispatchResult()返回,实现代码如下:
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);//通过请求找到handler(这里的handler就是我们说的Controller中处理请求的方法) if (mappedHandler == null || mappedHandler.getHandler() == null) { noHandlerFound(processedRequest, response);//没有找到handler则调用此方法处理 return; } // Determine handler adapter for the current request. HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());//通过handler找到HandlerAdapter // Process last-modified header, if supported by the handler. String method = request.getMethod();//获取请求方式 boolean isGet = "GET".equals(method); if (isGet || "HEAD".equals(method)) { //处理GET、HEAD请求的Last-Modified 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; } } //执行相应Interceptor的preHandler方法 if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } //handlerAdapter使用handler处理请求 // Actually invoke the handler. mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; } //当View为空时,比如我们写的Controller中处理请求的方法为空时,根据request的设置view applyDefaultViewName(processedRequest, mv); //执行相应Intercerptor的postHandler方法 mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } catch (Throwable err) { dispatchException = new NestedServletException("Handler dispatch failed", err); } //返回处理结果,包括异常处理、渲染页面、发出通知出发Interceptor的afterCompletion方法 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方法中的核心工作就是
1.根据当前Request找到handler;
2.根据Handler找到对应的HandlerAdapter;
3.使用HandlerAdapter处理handler
4.调用processDispatchResult方法处理上面请求之后的结果
补充几个重要的概念:
Handler:也就是处理器,他直接对应着MVC的Controller层,他的表现形式很多,标注了@RequestMapping的所有方法都可以看出一个handler,只要能处理实际请求的就可以是Handler。
HandlerMapping:用来查找Handler的,SpringMVC的请求很多,每个请求都需要一个handler来处理,收到的请求由那个handler来处理就由HandlerMapping来确定。
HandlerAdapter:他就是一个适配器,SpringMVC中handler的形式可以任意,主要能处理请求就OK,但是Servlet处理请求的方法结构是固定的。如何让固定的servlet处理方法调用灵活的handler来处理就由HandlerAdapter来实现。
接着分析handlerAdpter中调用handler方法处理请求。
public interface HandlerAdapter { //判断是否可以用某个handler boolean supports(Object handler); //具体使用Handler处理请求 ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception; //返回LastModified的值 long getLastModified(HttpServletRequest request, Object handler);}
我们只要实现HandlerAdapter接口就可以处理请求,SimpleControllerHandlerAdapter实现了HandlerAdapter,实现代码如下:
public class SimpleControllerHandlerAdapter implements HandlerAdapter { //判断是否可以用某个handler @Override public boolean supports(Object handler) { return (handler instanceof Controller); } @Override public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //调用Controller接口中的handleRequest方法,我们如果继承了Controller接口就需要重写这个方法,然后在里面处理逻辑即可。 return ((Controller) handler).handleRequest(request, response); } @Override public long getLastModified(HttpServletRequest request, Object handler) { if (handler instanceof LastModified) { return ((LastModified) handler).getLastModified(request); } return -1L; }}
请求处理完的结果会封装在ModelAndView中,我们通过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); } } // Did the handler return a view to render? 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()) { // Concurrent handling started during a forward return; } //发出请求处理完成的通知,出发Interceptor的afterCompletion if (mappedHandler != null) { mappedHandler.triggerAfterCompletion(request, response, null); } }
在render方法中会去查找视图解析器,然后转化成View类型的视图(比如jsp,html,freemaker等)显示在页面上。
- SpringMVC源码分析(二)
- springMVC源码分析--AbstractHandlerMapping(二)
- springMVC源码分析--SimpleServletHandlerAdapter(二)
- springMVC源码分析--AbstractHandlerMapping(二)
- springMVC源码分析--容器初始化(二)DispatcherServlet
- springMVC源码分析--国际化实现Session和Cookie(二)
- SpringMVC源码分析(二)-URL映射的注册
- springMVC源码分析--动态样式ThemeResolver(二)
- springMVC源码分析--HandlerInterceptor拦截器调用过程(二)
- springMVC源码分析--HttpMessageConverter参数read操作(二)
- springMVC源码分析--视图AbstractView和InternalResourceView(二)
- springMVC源码分析--容器初始化(二)DispatcherServlet
- springMVC源码分析--HandlerInterceptor拦截器调用过程(二)
- springMVC源码分析--国际化实现Session和Cookie(二)
- SpringMVC源码分析(二)从框架设计说起
- springMVC原理(二):SpringMVC核心分发器DispatcherServlet分析[附带源码分析]
- SpringMVC源码(二)DispatcherServlet
- SpringMVC源码分析(一)
- bootstrap 心得
- java_String类
- 用java实现简单的计算器
- http://www.cnblogs.com/tbcaaa8/p/4415429.html
- 数据结构与算法(贪婪算法)
- SpringMVC源码分析(二)
- Linux 基础入门--笔记
- poj1637(混合图判欧拉回路)
- Javascript——可选的分号
- pi近似值计算
- Java基础16:Java和Mysql的连接、查询和修改
- 精通正则表达式五:NFA与DFA
- 烽火星空C++笔试
- 直接插入排序