11.SpringMVC 请求处理 - HandlerAdapter

基本概念

SpringMVC 通过 HandlerAdapterhandler 方法来调用请求处理函数。

在 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 的工作流程图:

这里写图片描述

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

oxf

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值