基本概念
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 的工作流程图: