HandlerAdapters

HandlerAdapters

HandlerAdapter是处理器适配器,Spring MVC通过HandlerAdapter来实际调用处理函数。它是SpringMvc处理流程的第二步,当HandlerMapping获取了定位请求处理器Handler,DispatcherServlet会将得到的Handler告知HandlerAdapter,HandlerAdapter再根据请求去定位请求的具体处理方法是哪一个。

流程

  1. DispatcherServlte会根据配置文件信息注册HandlerAdapter,如果在配置文件中没有配置,那么 DispatcherServlte会获取HandlerAdapter的默认配置,如果是读取默认配置的话,DispatcherServlte会读取 DispatcherServlte.properties文件,该文件中配置了三种 HandlerAdapter:HttpRequestHandlerAdapter,SimpleControllerHandlerAdapter和 AnnotationMethodHandlerAdapter。DispatcherServlte会将这三个HandlerAdapter对象存储到 它的handlerAdapters这个集合属性中,这样就完成了HandlerAdapter的注册。

  2. DispatcherServlte会根据handlerMapping传过来的controller与已经注册好了的HandlerAdapter 一一匹配,看哪一种HandlerAdapter是支持该controller类型的,如果找到了其中一种HandlerAdapter是支持传过来的 controller类型,那么该HandlerAdapter会调用自己的handle方法,handle方法运用Java的 反射机制执行controller的具体方法来获得ModelAndView,例如SimpleControllerHandlerAdapter是支持 实现了controller接口的控制器,如果自己写的控制器实现了controller接口,那么 SimpleControllerHandlerAdapter就会去执行自己写控制器中的具体方法来完成请求。

作用

  1. HandlerAdapter定义了如何处理请求的策略,通过请求url、请求Method和处理器的requestMapping定义,最终确定使用处理类的哪个方法来处理请求,并检查处理类相应处理方法的参数以及相关的Annotation配置,确定如何转换需要的参数传入调用方法,并最终调用返回ModelAndView。

  2. DispatcherServlet中根据HandlerMapping找到对应的handler method后,首先检查当前工程中注册的所有可用的handlerAdapter,根据handlerAdapter中的supports方法找到可以使用的handlerAdapter。

  3. 通过调用handlerAdapter中的handler方法来处理及准备handler method的参数及annotation(这就是spring mvc如何将request中的参数变成handle method中的输入参数的地方),最终调用实际的handler method。

初始化

与initHandlerMappings的处理一致,读取DispatcherServlet.properties中的HandlerAdapters,但不是通过后置处理器触发

private void initHandlerAdapters(ApplicationContext context) {
    this.handlerAdapters = null;

    if (this.detectAllHandlerAdapters) {
        // 从应用上下文中查找HandlerAdapter
        Map<String, HandlerAdapter> matchingBeans =
                BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
        if (!matchingBeans.isEmpty()) {
            this.handlerAdapters = new ArrayList<>(matchingBeans.values());
            AnnotationAwareOrderComparator.sort(this.handlerAdapters);
        }
    } else {
        try {
            //如果在web.xml配了detectAllHandlerAdapters=false,此时spring会加载名称为handlerAdapter的bean为处理器适配器
            HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);
            // 转化为集合赋给handlerAdapters属性
            this.handlerAdapters = Collections.singletonList(ha);
        } catch (NoSuchBeanDefinitionException ex) {
        }
    }

    //如果未配置,读取DispatcherServlet.properties中的HandlerAdapters,放入this.handlerAdapters
    if (this.handlerAdapters == null) {
        this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
        if (logger.isTraceEnabled()) {
            logger.trace("No HandlerAdapters declared for servlet '" + getServletName() +
                    "': using default strategies from DispatcherServlet.properties");
        }
    }
}
org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
   org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
   org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter,\
   org.springframework.web.servlet.function.support.HandlerFunctionAdapter

DispatcherServlet的doDispatch方法会遍历handlerAdapters,找到handler对应的适配器

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    if (this.handlerAdapters != null) {
        for (HandlerAdapter adapter : this.handlerAdapters) {
            if (adapter.supports(handler)) {//判断是否适配成功
                return adapter;
            }
        }
    }
    throw new ServletException("No adapter for handler [" + handler +
                               "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}

HandlerAdapter的接口中定义了三个方法:

(1)boolean supports(Object handler); 判断适配器是否适配Handler

(2)ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) 使用适配的Handler处理用户请求

(3)long getLastModified(HttpServletRequest request, Object handler); 返回资源的最后修改时间,如果handler实现类不支持可以返回-1

SimpleServletHandlerAdapter

SimpleSerlvetHandlerAdapter是Spring使用HandlerAdapter最简单的方式,此方式是为了在Spring中支持Servlet方式开发,即把Servlet适配为处理器handler。

是一个Servlet的适配器,其最终执行的方法是Servlet的service方法,非默认提供(DispatcherServlet.properties中没有)

需要自己导入bean

supports方法就是判断handler是否是Servlet

getLastModified直接返回-1

handle方法本质是执行Servlet.service方法。

public class SimpleServletHandlerAdapter implements HandlerAdapter {

    //判断handler是否实现Servlet接口
    @Override
    public boolean supports(Object handler) {
        return (handler instanceof Servlet);
    }

    @Override
    @Nullable
    public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        ((Servlet) handler).service(request, response);
        return null;
    }

    @Override
    public long getLastModified(HttpServletRequest request, Object handler) {
        return -1;
    }

}

SimpleControllerHandlerAdapter

是Controller实现类的适配器类,其本质是执行Controller中的handleRequest方法。

supports方法就是判断handler是否是Controller

getLastModified直接返回-1

handle方法本质是执行Controller.handleRequest方法。

public class SimpleControllerHandlerAdapter implements HandlerAdapter {

    @Override
    public boolean supports(Object handler) {
        return (handler instanceof Controller);
    }

    @Override
    @Nullable
    public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        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;
    }

}

HttpRequestHandlerAdapter

supports方法就是判断handler是否是HttpRequestHandler

getLastModified直接返回-1

handle方法本质是执行HttpRequestHandler.handleRequest方法。

public class HttpRequestHandlerAdapter implements HandlerAdapter {
    @Override
    public boolean supports(Object handler) {
        //判断是否是HttpRequestHandler子类
        return (handler instanceof HttpRequestHandler);
    }
    @Override
    public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        //执行HttpRequestHandler的handleRequest方法
        ((HttpRequestHandler) handler).handleRequest(request, response);
        return null;
    }
    @Override
    public long getLastModified(HttpServletRequest request, Object handler) {
        //返回modified值
        if (handler instanceof LastModified) {
            return ((LastModified) handler).getLastModified(request);
        }
        return -1L;
    }
}

RequestMappingHandlerAdapter

通过继承抽象类AbstractHandlerMethodAdapter实现了HandlerAdapter接口

请求适配给@RequestMapping类型的Handler处理。

采用反射机制调用url请求对应的Controller中的方法(这其中还包括参数处理),返回执行结果值,完成HandlerAdapter的使命

getLastModified直接返回-1

@Override
protected long getLastModifiedInternal(HttpServletRequest request, HandlerMethod handlerMethod) {
    return -1;
}

//通过父类调用
@Override
protected ModelAndView handleInternal(HttpServletRequest request,
        HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
 
    ModelAndView mav;
    checkRequest(request);
 
    // 判断当前是否需要支持在同一个session中只能线性地处理请求
    if (this.synchronizeOnSession) {
        // 获取当前请求的session对象
        HttpSession session = request.getSession(false);
        if (session != null) {
            // 为当前session生成一个唯一的可以用于锁定的key
            Object mutex = WebUtils.getSessionMutex(session);
            synchronized (mutex) {
                // 对HandlerMethod进行参数等的适配处理,并调用目标handler
                mav = invokeHandlerMethod(request, response, handlerMethod);
            }
        } else {
            // 如果当前不存在session,则直接对HandlerMethod进行适配
            mav = invokeHandlerMethod(request, response, handlerMethod);
        }
    } else {
        // 如果当前不需要对session进行同步处理,则直接对HandlerMethod进行适配
        mav = invokeHandlerMethod(request, response, handlerMethod);
    }
 
    // 判断当前请求头中是否包含Cache-Control请求头,如果不包含,则对当前response进行处理,为其设置过期时间
    if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
        // 如果当前SessionAttribute中存在配置的attributes,则为其设置过期时间。
        // 这里SessionAttribute主要是通过@SessionAttribute注解生成的
        if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
            applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
        } else {
            // 如果当前不存在SessionAttributes,则判断当前是否存在Cache-Control设置,
            // 如果存在,则按照该设置进行response处理,如果不存在,则设置response中的
            // Cache的过期时间为-1,即立即失效
            prepareResponse(response);
        }
    }
    return mav;
}

//核心处理流程
@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
        HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
 
    ServletWebRequest webRequest = new ServletWebRequest(request, response);
    try {
        // 获取容器中全局配置的InitBinder和当前HandlerMethod所对应的Controller中配置的InitBinder,用于进行参数的绑定
        WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
        // 获取容器中全局配置的ModelAttribute和当前HandlerMethod所对应的Controller
        // 中配置的ModelAttribute,这些配置的方法将会在目标方法调用之前进行调用
        ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
 
        // 将handlerMethod封装为一个ServletInvocableHandlerMethod对象,该对象用于对当前request的整体调用流程进行了封装
        ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
        if (this.argumentResolvers != null) {
            // 设置当前容器中配置的所有ArgumentResolver
            invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
        }
        if (this.returnValueHandlers != null) {
            // 设置当前容器中配置的所有ReturnValueHandler
            invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
        }
        // 将前面创建的WebDataBinderFactory设置到ServletInvocableHandlerMethod中
        invocableMethod.setDataBinderFactory(binderFactory);
        // 设置ParameterNameDiscoverer,该对象将按照一定的规则获取当前参数的名称
        invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
 
        ModelAndViewContainer mavContainer = new ModelAndViewContainer();
        mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
        // 这里initModel()方法主要作用是调用前面获取到的@ModelAttribute标注的方法,
        // 从而达到@ModelAttribute标注的方法能够在目标Handler调用之前调用的目的
        modelFactory.initModel(webRequest, mavContainer, invocableMethod);
        mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
 
        // 获取当前的AsyncWebRequest,这里AsyncWebRequest的主要作用是用于判断目标
        // handler的返回值是否为WebAsyncTask或DefferredResult,如果是这两种中的一种,
        // 则说明当前请求的处理应该是异步的。所谓的异步,指的是当前请求会将Controller中
        // 封装的业务逻辑放到一个线程池中进行调用,待该调用有返回结果之后再返回到response中。
        // 这种处理的优点在于用于请求分发的线程能够解放出来,从而处理更多的请求,只有待目标任务
        // 完成之后才会回来将该异步任务的结果返回。
        AsyncWebRequest asyncWebRequest = WebAsyncUtils
            .createAsyncWebRequest(request, response);
        asyncWebRequest.setTimeout(this.asyncRequestTimeout);
 
        // 封装异步任务的线程池,request和interceptors到WebAsyncManager中
        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
        asyncManager.setTaskExecutor(this.taskExecutor);
        asyncManager.setAsyncWebRequest(asyncWebRequest);
        asyncManager.registerCallableInterceptors(this.callableInterceptors);
        asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
 
        // 这里就是用于判断当前请求是否有异步任务结果的,如果存在,则对异步任务结果进行封装
        if (asyncManager.hasConcurrentResult()) {
            Object result = asyncManager.getConcurrentResult();
            mavContainer = (ModelAndViewContainer) 
                asyncManager.getConcurrentResultContext()[0];
            asyncManager.clearConcurrentResult();
            if (logger.isDebugEnabled()) {
                logger.debug("Found concurrent result value [" + result + "]");
            }
            // 封装异步任务的处理结果,虽然封装的是一个HandlerMethod,但只是Spring简单的封装
            // 的一个Callable对象,该对象中直接将调用结果返回了。这样封装的目的在于能够统一的
            // 进行右面的ServletInvocableHandlerMethod.invokeAndHandle()方法的调用
            invocableMethod = invocableMethod.wrapConcurrentResult(result);
        }
 
        // 对请求参数进行处理,调用目标HandlerMethod,并且将返回值封装为一个ModelAndView对象
        invocableMethod.invokeAndHandle(webRequest, mavContainer);
        if (asyncManager.isConcurrentHandlingStarted()) {
            return null;
        }
 
        // 对封装的ModelAndView进行处理,主要是判断当前请求是否进行了重定向,如果进行了重定向,
        // 还会判断是否需要将FlashAttributes封装到新的请求中
        return getModelAndView(mavContainer, modelFactory, webRequest);
    } finally {
        // 调用request destruction callbacks和对SessionAttributes进行处理
        webRequest.requestCompleted();
    }
}

获取当前容器中使用@InitBinder注解注册的属性转换器;

获取当前容器中使用@ModelAttribute标注但没有使用@RequestMapping标注的方法,并且在调用目标方法之前调用这些方法;

判断目标handler返回值是否使用了WebAsyncTask或DefferredResult封装,如果封装了,则按照异步任务的方式进行执行;

处理请求参数,调用目标方法和处理返回值。

总结

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值