SpringMVC-前端控制器源码分析
来源:互联网 发布:网络授课教师招聘 编辑:程序博客网 时间:2024/06/12 01:30
上篇文章中提到了关于springmvc的请求流程,大家 可以看到中心就是前端控制器DispatcherServlet的作用,今天小编来讲一下关于DispatcherServlet的源码分析过程。
第一步:前端控制器接收请求
DispatcherServlet中的jar包调用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; // Determine handler for the current request. mappedHandler = getHandler(processedRequest, false); if (mappedHandler == null || mappedHandler.getHandler() == 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()) { String requestUri = urlPathHelper.getRequestUri(request); logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified); } if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return; } } if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } try { // Actually invoke the handler. mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); } finally { if (asyncManager.isConcurrentHandlingStarted()) { return; } } applyDefaultViewName(request, mv); mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } 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 mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); return; } // Clean up any resources used by a multipart request. if (multipartRequestParsed) { cleanupMultipart(processedRequest); } } }
第二步:前端控制器调用处理器映射器查找Handler,通过url返回执行链
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,得到执行结果ModelAndViewmv = ha.handle(processedRequest, response, mappedHandler.getHandler());第四步:视图渲染,将Model数据填充到request域,查看下面的代码: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; if (mv.isReference()) { // We need to resolve the view name. 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. 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() + "'"); } } // Delegate to the View object for rendering. if (logger.isDebugEnabled()) { logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'"); } view.render(mv.getModelInternal(), request, response); }protected void exposeModelAsRequestAttributes(Map<String, Object> model, HttpServletRequest request) throws Exception { for (Map.Entry<String, Object> entry : model.entrySet()) { String modelName = entry.getKey(); Object modelValue = entry.getValue(); if (modelValue != null) { request.setAttribute(modelName, modelValue); if (logger.isDebugEnabled()) { logger.debug("Added model object '" + modelName + "' of type [" + modelValue.getClass().getName() + "] to request in view with name '" + getBeanName() + "'"); } } else { request.removeAttribute(modelName); if (logger.isDebugEnabled()) { logger.debug("Removed model object '" + modelName + "' from request in view with name '" + getBeanName() + "'"); } } } }
小结:
最后小编来总结一下springmvc前端控制器、处理器映射器、处理器适配器、视图解析器用法。
前端控制器配置:
第一种:*.action,访问以.action结尾由DispatcherServlet进行解析,解析源码见上面的分析。
第二种:/,访问的地址都是由DispatcherServlet进行解析,对于静态文件的解析需要配置不让DispatcherServlet进行解析。使用此种方式可以实现RESTful风格的url。
处理器映射器:
非注解处理器映射器(了解)
注解处理器映射器(掌握)
对标记@Controller类中标识有@requestMapping的方法进行映射,在@RequestMapping里边定义映射的
url。使用注解的映射器,不用再xml中配置url和Handler的映射关系。
处理器适配器:
非注解处理器适配器
注解处理器适配器
注解处理器适配器和注解的处理器映射器是配对使用。理解为不能使用非注解的处理器映射器进行映射。
这个mvc下的注解驱动可以代替下边的配置:
实际开发使用的是注解驱动
视图解析器:
可以配置前缀和后缀,来简约路径
- SpringMVC-前端控制器源码分析
- 【SpringMVC框架】前端控制器源代码分析
- SpringMVC前端控制器-----DispatcherServlet
- springmvc前端控制器匹配
- Springmvc前端控制器配置
- springMVC源码--Controller控制器
- SpringMVC源码深度分析DispatcherServlet核心的控制器(初始化)
- SpringMVC源码深度分析DispatcherServlet核心的控制器(初始化)
- springmvc入门-前端控制器配置
- springmvc前端控制器的配置
- springMVC前端控制器路径问题
- springmvc前端控制器的配置
- springMVC的前端控制器的配置
- springmvc学习笔记(4)-前端控制器
- 前端控制器模式在springmvc的应用
- struts2和springmvc的前端控制器
- SpringMVC前端控制器三种配置方式
- springmvc处理器及前端控制器介绍
- 测试
- spring集成quartz实现的定时更新cache的代码配置
- Canvas(画布)类的使用
- oracle相关
- 程序员保值的4个秘密
- SpringMVC-前端控制器源码分析
- 上机笔试题3及程序源码
- 使用(x&y) + ((x^y)>>1) 求平均数
- android mainfest
- 模式总结之结构型:代理模式 Vs 适配器模式 Vs 门面模式(外观模式)
- java 反射和注解的简单应用
- bootstrap 弹出包含iframe模态窗口的修改
- 通过反射+注解生成sql语句
- java并发编程(五)--volatile变量修饰符—意料之外的问题