SpringMVC 请求处理
来源:互联网 发布:b2b自动发布软件 编辑:程序博客网 时间:2024/06/02 00:25
转自http://blog.csdn.net/u012420654/article/details/52304594
基本概念
SpringMVC 通过 HandlerAdapter 的 handler 方法来调用请求处理函数。
在 DispatcherServlet 中根据请求路径利用 Handlermapping 找到对应的 handler 后,首先检查当前 Ioc 容器中所有可用的HandlerAdapter ,再利用 HandlerAdapter 中的 supports 方法找到可以使用的HandlerAdapter。
首先来看它的继承关系:
内部构造
该接口内部定义了定义了三个方法。
public interface HandlerAdapter { // 是否支持该 HandlerMethod boolean supports(Object handler); // 根据 HandlerMethod 取得 ModelAndView ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception; long getLastModified(HttpServletRequest request, Object handler);}
AbstractHandlerMethodAdapter
该类是 HandlerAdapter 接口的简单抽象类,实现了接口定义的方法。
但也并未做真正的实现,而是留给了子类。下面来看它的源码:
public final boolean supports(Object handler) { return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));}public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return handleInternal(request, response, (HandlerMethod) handler);}public final long getLastModified(HttpServletRequest request, Object handler) { return getLastModifiedInternal(request, (HandlerMethod) handler);}
RequestMappingHandlerAdapter
该类继承了 AbstractHandlerMethodAdapter 类,真正意义上实现了 HandlerAdapter 接口定义的功能。
1.supportsInternal
默认返回 true,说明只要处理器是 HandlerMethod 类即可
protected boolean supportsInternal(HandlerMethod handlerMethod) { return true;}
2.getLastModifiedInternal
默认返回 -1.
protected long getLastModifiedInternal(HttpServletRequest request, HandlerMethod handlerMethod) { return -1;}
3.handleInternal
该方法负责调用 HandlerMethod(处理器) ,并返回 ModelAndView 。
protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { // 1.校验请求 // 检查是否支持当前 rqeuest 的 method 和 session checkRequest(request); // 2.判断控制器是否存在 @SessionAttributes 注解 if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) { // 2.1设置缓存 applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers); } else { // 2.2准备响应 prepareResponse(response); } // 默认为 false,为 true 表示在同步块中执行 invokeHandlerMethod if (this.synchronizeOnSession) { HttpSession session = request.getSession(false); if (session != null) { Object mutex = WebUtils.getSessionMutex(session); synchronized (mutex) { return invokeHandlerMethod(request, response, handlerMethod); } } } // 关键 -> 3.处理器调用 return invokeHandlerMethod(request, response, handlerMethod);}
分析代码,该方法的具体过程如下:
- 1.校验请求,即检查是否支持当前 rqeuest 的 method 和 session
- 2.判断控制器是否存在 @SessionAttributes 注解,有则设置缓存,否则准备响应
- 3.处理器调用,返回 ModelAndView 。
ModelMap
该类继承自 LinkedHashMap,说明它代表一组有序的映射集,用于保存数据。
它的签名如下:
public class ModelMap extends LinkedHashMap<String, Object>
再来看它的构造函数:
public ModelMap(String attributeName, Object attributeValue) { addAttribute(attributeName, attributeValue);}public ModelMap addAttribute(String attributeName, Object attributeValue) { // 存储 <K,V> put(attributeName, attributeValue); return this;}
ModelAndView
该类内部保存了 ModelMap 和 View。
private Object view;private ModelMap model;public ModelAndView(String viewName, String modelName, Object modelObject) { this.view = viewName; addObject(modelName, modelObject);}public ModelAndView addObject(String attributeName, Object attributeValue) { getModelMap().addAttribute(attributeName, attributeValue); return this;}public ModelMap getModelMap() { if (this.model == null) { this.model = new ModelMap(); } return this.model;}
ModelAndViewContainer
该类表示一个容器,不仅包含了 ModelMap 、View 还有其他相关内容。
观察它的成员变量可知:
private Object view;private final ModelMap defaultModel = new BindingAwareModelMap();private ModelMap redirectModel;private final SessionStatus sessionStatus = new SimpleSessionStatus();private boolean redirectModelScenario = false;private boolean ignoreDefaultModelOnRedirect = false;private boolean requestHandled = false;
ServletInvocableHandlerMethod
1.基本概念
该类实现了 HandlerMethod 类,具体继承关系如下:
下面来看它的构造函数:
public ServletInvocableHandlerMethod(HandlerMethod handlerMethod) { super(handlerMethod); initResponseStatus();}
观察代码,该类的构造函数执行过程如下:
调用父类,即 HandlerMethod 的构造函数 ,将 HandlerMethod 的成员变量赋值给自己的成员变量。
protected HandlerMethod(HandlerMethod handlerMethod) { this.bean = handlerMethod.bean; this.beanFactory = handlerMethod.beanFactory; this.beanType = handlerMethod.beanType; this.method = handlerMethod.method; this.bridgedMethod = handlerMethod.bridgedMethod; this.parameters = handlerMethod.parameters; this.resolvedFromHandlerMethod = handlerMethod.resolvedFromHandlerMethod;}
提取 @ResponseStatus 注解的相关内容赋值给自己的成员变量
private void initResponseStatus() { ResponseStatus annotation = getMethodAnnotation(ResponseStatus.class); if (annotation != null) { this.responseStatus = annotation.code(); this.responseReason = annotation.reason(); }}
2. invokeAndHandle
关键来看该类的 invokeAndHandle 方法, 它负责调用 HandlerMethod 中控制器的指定方法。
public void invokeAndHandle(ServletWebRequest webRequest,ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { // 关键 -> 1.执行控制器指定方法 Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs); // 2.设置响应状态 setResponseStatus(webRequest); // 3.判断请求是否处理完毕,根据返回值来判断。 if (returnValue == null) { if (isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) { // 为 true ,表示方法调用完毕 mavContainer.setRequestHandled(true); return; } }else if (StringUtils.hasText(this.responseReason)) { mavContainer.setRequestHandled(true); return; } // 存在返回值时,可能还需进行视图解析 mavContainer.setRequestHandled(false); try { // 处理返回值,在 MavContainer 中设置 ViewName // 并判断其是不是【重定向请求】 this.returnValueHandlers.handleReturnValue( returnValue, getReturnValueType(returnValue), mavContainer, webRequest); }catch (Exception ex) { // 抛出异常... }}
- 执行控制器指定方法
public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { // 省略部分代码... // 取得方法入参值 Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs); // 利用反射执行该方法,并取得返回值 Object returnValue = doInvoke(args); return returnValue;}protected Object doInvoke(Object... args) throws Exception { // 设置方法的访问权限,BridgedMethod 表示控制器类的指定方法 ReflectionUtils.makeAccessible(getBridgedMethod()); try { // 关键 -> 利用反射执行该方法,Bean 表示控制器类名称 return getBridgedMethod().invoke(getBean(), args); }catch (IllegalArgumentException ex) { // 抛出异常... }catch (InvocationTargetException ex) { // 抛出异常... }}
处理器调用
接下里分析下 handleInternal 方法中的处理器调用
protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ServletWebRequest webRequest = new ServletWebRequest(request, response); // 1.数据绑定 WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod); // 2.创建 ModelFactory // 添加了 @ModelAttribute,@SessionAttributes 等注解内容 ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory); // 3.创建 ServletInvocableHandlerMethod,并绑定相关属性 ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod); invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers); invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers); invocableMethod.setDataBinderFactory(binderFactory); invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer); // 4.创建 ModelAndViewContainer ModelAndViewContainer mavContainer = new ModelAndViewContainer(); mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request)); modelFactory.initModel(webRequest, mavContainer, invocableMethod); mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect); // 省略部分源码... // 5.调用控制器方法 invocableMethod.invokeAndHandle(webRequest, mavContainer); // 6.返回 ModelAndView return getModelAndView(mavContainer, modelFactory, webRequest);}
接着来看该类的 getModelAndView 方法:
private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception { // 更新 Mdoel modelFactory.updateModel(webRequest, mavContainer); // 判断请求是否处理器完毕 if (mavContainer.isRequestHandled()) { return null; } // 关键 -> 创建 ModelAndView ModelMap model = mavContainer.getModel(); ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model); // 判断 view 是不是字符串 if (!mavContainer.isViewReference()) { mav.setView((View) mavContainer.getView()); } // 重定向相关 if (model instanceof RedirectAttributes) { Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes(); HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes); } return mav;}
总结
下面来看 HandlerAdapter 的工作流程图:
- SpringMVC请求处理操作
- SpringMVC请求处理流程
- SpringMVC处理AJAX请求
- SpringMVC 请求处理流程
- springmvc 处理异步请求
- SpringMVC-处理请求参数
- SpringMvc处理请求流程
- springmvc处理ajax请求
- 05.SpringMVC 请求处理
- 06.SpringMVC 请求处理
- 07.SpringMVC 请求处理
- SpringMVC处理请求流程
- SpringMVC请求处理流程
- springmvc异步处理请求
- SpringMVC处理请求流程
- springMvc处理ajax请求
- SpringMVC:ajax请求处理
- SpringMVC处理请求流程
- 一个jsp引入另一个jsp页面的方式
- nginx整合多个tomcat现实负载均衡
- Sql语句为什么大写
- 内容回顾
- org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: cn.oa.d
- SpringMVC 请求处理
- 1005. 继续(3n+1)猜想 (25)
- 软件过程管理-测试过程讨论
- N皇后问题---回溯法之一维数组存储
- java 数字与英文字母相互转换
- NTFS系统存储介质上文件操作痕迹分析
- Kotlin 其他(七) --- 操作符重载(Operator overloading)
- [C++]This指针
- Spring框架之注册—SingletonBeanRegistry接口