SpringMVC源码解读 --- 处理器适配器(HandlerAdapter)的结构及源码分析

  这一章我们主要是梳理下HandlerAdapter,在看这一篇的时候可以去看下前面的关于HandlerMapping与处理器映射器前置知识的内容,怎样能更好的理解。

   1、HandlerAdapter接口:

public interface HandlerAdapter {

   boolean supports(Object handler);

   @Nullable
   ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

   long getLastModified(HttpServletRequest request, Object handler);
}

    可以看到这个接口有三个方法。

   1、supports方法

         这个接口就是看这类是用来处理哪种handler的。

   2、handle方法

   这个方法就是具体的处理方法,通过前面的文章的梳理,可以看到Spring在进行选择的时候一般是通过supports方法判断选择哪个,然后再用handle方法去具体处理。

   3、getLastModified

       这个就是看这个handler最后的修改时间,,有些参数能在没有修改的时候不进行处理。

  下面我们来看下其的实现类

  2、SimpleControllerHandlerAdapter

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;
   }
}

  这里可以看到,这个HandlerAdapter就是通过supports看下当前要处理的handler是不是Controller。如果是,就通过handle去处理。

 3、SimpleServletHandlerAdapter

public class SimpleServletHandlerAdapter implements HandlerAdapter {

   @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;
   }
}

 这个HandlerAdapter supports方法就是判断handler是不是Servlet,如果是就用handle去处理,直接调用Servlet的service方法。返回的为null。

 4、HttpRequestHandlerAdapter

public class HttpRequestHandlerAdapter implements HandlerAdapter {

   @Override
   public boolean supports(Object handler) {
      return (handler instanceof HttpRequestHandler);
   }
   @Override
   @Nullable
   public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
         throws Exception {

      ((HttpRequestHandler) handler).handleRequest(request, response);
      return null;
   }
   @Override
   public long getLastModified(HttpServletRequest request, Object handler) {
      if (handler instanceof LastModified) {
         return ((LastModified) handler).getLastModified(request);
      }
      return -1L;
   }
}

  可以看到这个Adapter是用来处理HttpRequestHandler的,handle调用的是其的handleRequest方法。这个HttpRequestHandler我的理解其实这个与Servlet是类似的(因为其入参一样是HttpServletRequest 、HttpServletResponse ),你可以自定义处理器去实现HttpRequestHandler这个接口。

     SpringMVC对HttpRequestHandler的实现一般会用到的应该是两个

  1、DefaultServletHttpRequestHandler

public class DefaultServletHttpRequestHandler implements HttpRequestHandler, ServletContextAware {
       ............
   @Override
   public void setServletContext(ServletContext servletContext) {
      this.servletContext = servletContext;
      if (!StringUtils.hasText(this.defaultServletName)) {
         if (this.servletContext.getNamedDispatcher(COMMON_DEFAULT_SERVLET_NAME) != null) {
            this.defaultServletName = COMMON_DEFAULT_SERVLET_NAME;
         }
         else if (this.servletContext.getNamedDispatcher(GAE_DEFAULT_SERVLET_NAME) != null) {
            this.defaultServletName = GAE_DEFAULT_SERVLET_NAME;
         }
         else if (this.servletContext.getNamedDispatcher(RESIN_DEFAULT_SERVLET_NAME) != null) {
            this.defaultServletName = RESIN_DEFAULT_SERVLET_NAME;
         }
         else if (this.servletContext.getNamedDispatcher(WEBLOGIC_DEFAULT_SERVLET_NAME) != null) {
            this.defaultServletName = WEBLOGIC_DEFAULT_SERVLET_NAME;
         }
         else if (this.servletContext.getNamedDispatcher(WEBSPHERE_DEFAULT_SERVLET_NAME) != null) {
            this.defaultServletName = WEBSPHERE_DEFAULT_SERVLET_NAME;
         }
         else {
            throw new IllegalStateException("Unable to locate the default servlet for serving static content. " +
                  "Please set the 'defaultServletName' property explicitly.");
         }
      }
   }
   @Override
   public void handleRequest(HttpServletRequest request, HttpServletResponse response)
         throws ServletException, IOException {

      Assert.state(this.servletContext != null, "No ServletContext set");
      RequestDispatcher rd = this.servletContext.getNamedDispatcher(this.defaultServletName);
      if (rd == null) {
         throw new IllegalStateException("A RequestDispatcher could not be located for the default servlet '" +
               this.defaultServletName + "'");
      }
      rd.forward(request, response);
   }
}

   这里有些tomcat的内容,这里先挖一个坑。

可以看到其是先通过setServletContext方法,看是哪种getNamedDispatcher,再将defaultServletName进行对应的设置,然后在通过handleRequest方法,获取到RequestDispatcher(tomcat)的类,再调用其的forward方法。

  2、ResourceHttpRequestHandler

   这个类看名称就是知道其是用来处理Resource的,这里简答看下其的handleRequest方法:

@Override
public void handleRequest(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
   Resource resource = getResource(request);
      ............
   MediaType mediaType = getMediaType(request, resource);
    ........
   ServletServerHttpResponse outputMessage = new ServletServerHttpResponse(response);
   if (request.getHeader(HttpHeaders.RANGE) == null) {
      setHeaders(response, resource, mediaType);
      this.resourceHttpMessageConverter.write(resource, mediaType, outputMessage);
   }
   else {
      response.setHeader(HttpHeaders.ACCEPT_RANGES, "bytes");
      ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(request);
      try {
         ...........
         this.resourceRegionHttpMessageConverter.write(
               HttpRange.toResourceRegions(httpRanges, resource), mediaType, outputMessage);
      }
      catch (IllegalArgumentException ex) {
         response.setHeader("Content-Range", "bytes */" + resource.contentLength());
         response.sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
      }
   }
}

 可以看到,这里分为5个部分:

     1、通过request,获取对应的Resource。

     2、获取对应的MediaType。

     3、通过response构建outputMessage。

     4、设置response的头部。

     5、通过this.resourceRegionHttpMessageConverter.write将resource的内容写到response中。

  1、我们再通过一个demo来更直接的了解:

<?xml version="1.0" encoding="UTF-8"?>
<beans
        xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:mvc="http://www.springframework.org/schema/mvc"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.2.xsd
    http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
      http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">

    <bean id="beanNameUrlHandlerMapping"
          class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">
    </bean>
    <bean id="resourceHandler1" name="/ResourceHandlerHello.html"
          class="org.springframework.web.servlet.resource.ResourceHttpRequestHandler">
        <property name="locations">
           <list>
               <ref bean="myClassPathResource"/>
           </list>
        </property>
    </bean>

    <bean id="myClassPathResource" class="org.springframework.core.io.ClassPathResource">
        <constructor-arg name="path" value="static/"/>
    </bean>
</beans>

  然后在maven项目的resource目录新建static目录,创建ResourceHandlerHello.html静态界面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
        Hello ResourceHttpRequestHandler
</body>
</html>

                                                     

 启动tomcat项目,访问http://localhost:8080/ResourceHandlerHello.html 地址就能返回界面:

           

         下面 我们来debug看下流程,前面获取到handler(resourceHandler1)我们就不再梳理了,可以看以前关于HandlerMapping的内容。这里会根据这个bean标签的name="/ResourceHandlerHello.html"将其注册到BeanNameUrlHandlerMapping中,然后在请求的时候就会将对应的ResourceHttpRequestHandler返回,然后会根据这个ResourceHttpRequestHandler(HttpRequestHandler)获取到对应的HttpRequestHandlerAdapter,我们现在来看下这个handler的handleRequest方法:

    1、先是getResource

然后这里的getLocations方法就是我们添加的 <ref bean="myClassPathResource"/>:

                   

可以看到这里之后就获取到这个resource了,获取resource后,将将其写到response中,这个可以看前面关于ResourceHttpRequestHandler的handleRequest方法五部介绍。

5、RequestMappingHandlerAdapter

  现在就来到了算是所有HandlerAdapter中很复杂的的RequestMappingHandlerAdapter了(这也是在梳理HandlerAdapter之前,梳理了一些前缀内容)  

public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
      implements BeanFactoryAware, InitializingBean {

   这章我们直接来开下其的一些主要内容,所以就不具体的介绍其的父类、及其他的一些内容了(有一些主要方法来展开这些点)

  1、方法

      1、构造函数(RequestMappingHandlerAdapter)

public RequestMappingHandlerAdapter() {
   StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
   stringHttpMessageConverter.setWriteAcceptCharset(false);  // see SPR-7316

   this.messageConverters = new ArrayList<>(4);
   this.messageConverters.add(new ByteArrayHttpMessageConverter());
   this.messageConverters.add(stringHttpMessageConverter);
   this.messageConverters.add(new SourceHttpMessageConverter<>());
   this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());
}
private List<HttpMessageConverter<?>> messageConverters;

    可以看到RequestMappingHandlerAdapter的构造函数就是设置HttpMessageConverter,这个HttpMessageConverter前面梳理HandlerMethodArgumentResolver、HandlerMethodReturnValueHandler接口的时候有了解,一般是用与实现AbstractMessageConverterMethodArgumentResolver抽象类中,用来操作request body/response body的。

    2、getDefaultArgumentResolvers(RequestMappingHandlerAdapter)

private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
   List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>();
     ..........
   resolvers.add(new ServletModelAttributeMethodProcessor(false));
   resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
   resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice));
    ..........
   resolvers.add(new ModelMethodProcessor());
   .............
   return resolvers;
}

    可以看到这里在构建RequestResponseBodyMethodProcessor(HandlerMethodArgumentResolver、HandlerMethodReturnValueHandler实现类)的时候,会传入前面设置的默认HttpMessageConverter。

   3、afterPropertiesSet(RequestMappingHandlerAdapter)

     这个是因为其实现了InitializingBean接口

@Override
public void afterPropertiesSet() {
   // Do this first, it may add ResponseBody advice beans
   initControllerAdviceCache();

   if (this.argumentResolvers == null) {
      List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
      this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
   }
   if (this.initBinderArgumentResolvers == null) {
      List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
      this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
   }
   if (this.returnValueHandlers == null) {
      List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
      this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
   }
}

     可以看到这里是有创建argumentResolvers(HandlerMethodArgumentResolverComposite)、returnValueHandlers(HandlerMethodReturnValueHandlerComposite),将前面的那些resolvers(HandlerMethodArgumentResolver)、handlers(HandlerMethodReturnValueHandler)传入完成其的初始化。

  4、initControllerAdviceCache

   这个方法是上面afterPropertiesSet调用的  

private void initControllerAdviceCache() {
       ..............
   List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
   AnnotationAwareOrderComparator.sort(adviceBeans);
   List<Object> requestResponseBodyAdviceBeans = new ArrayList<>();
   for (ControllerAdviceBean adviceBean : adviceBeans) {
      Class<?> beanType = adviceBean.getBeanType();
       .......
      Set<Method> attrMethods = MethodIntrospector.selectMethods(beanType, MODEL_ATTRIBUTE_METHODS);
      if (!attrMethods.isEmpty()) {
         this.modelAttributeAdviceCache.put(adviceBean, attrMethods);
      }
      Set<Method> binderMethods = MethodIntrospector.selectMethods(beanType, INIT_BINDER_METHODS);
          .......... // this.initBinderAdviceCache.put(adviceBean, binderMethods);
      if (RequestBodyAdvice.class.isAssignableFrom(beanType)) {
         requestResponseBodyAdviceBeans.add(adviceBean);
      }
      if (ResponseBodyAdvice.class.isAssignableFrom(beanType)) {
         requestResponseBodyAdviceBeans.add(adviceBean);
      }
   }
     .........
}
public static List<ControllerAdviceBean> findAnnotatedBeans(ApplicationContext applicationContext) {
   List<ControllerAdviceBean> beans = new ArrayList<>();
   for (String name : BeanFactoryUtils.beanNamesForTypeIncludingAncestors(applicationContext, Object.class)) {
      if (applicationContext.findAnnotationOnBean(name, ControllerAdvice.class) != null) {
         beans.add(new ControllerAdviceBean(name, applicationContext));
      }
   }
   return beans;
}

   这里就是从BeanFactory中获取所有bean(Object),然后判断该bean有没有注解ControllerAdvice,如果是就产生ControllerAdviceBean添加到beans中,然后再遍历。

   这里有两个MethodFilter

public static final MethodFilter INIT_BINDER_METHODS = method ->
      AnnotationUtils.findAnnotation(method, InitBinder.class) != null;

public static final MethodFilter MODEL_ATTRIBUTE_METHODS = method ->
      ((AnnotationUtils.findAnnotation(method, RequestMapping.class) == null) &&
      (AnnotationUtils.findAnnotation(method, ModelAttribute.class) != null));

 如果bean的方法有InitBinder、RequestMapping这些注解,就将其添加到Cache中,下面同样是判断RequestBodyAdvice、ResponseBodyAdvice。

  5、handleInternal

@Override
protected ModelAndView handleInternal(HttpServletRequest request,
      HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
   ModelAndView mav;
   checkRequest(request);
   if (this.synchronizeOnSession) {
      HttpSession session = request.getSession(false);
      if (session != null) {
         Object mutex = WebUtils.getSessionMutex(session);
         synchronized (mutex) {
            mav = invokeHandlerMethod(request, response, handlerMethod);
         }
      }
      else {
         mav = invokeHandlerMethod(request, response, handlerMethod);
      }
   }
   else {
      mav = invokeHandlerMethod(request, response, handlerMethod);
   }
   if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
      ........这里是与response中有些cache设置有关
   }
   return mav;
}
private boolean synchronizeOnSession = false;

   这里就是整个RequestMappingHandlerAdapter的的主要方法handleInternal

   首先是checkRequest,可以看到这里是对method 、Session的一些判断。requireSession 默认为false,如果主动修改为true,就会校验

protected final void checkRequest(HttpServletRequest request) throws ServletException {
   // Check whether we should support the request method.
   String method = request.getMethod();
   if (this.supportedMethods != null && !this.supportedMethods.contains(method)) {
      throw new HttpRequestMethodNotSupportedException(method, this.supportedMethods);
   }

   if (this.requireSession && request.getSession(false) == null) {
      throw new HttpSessionRequiredException("Pre-existing session required but none found");
   }
}
private boolean requireSession = false;

   然后是看需不需要使用同步,调用invokeHandlerMethod方法。

  6、invokeHandlerMethod

@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
      HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

   ServletWebRequest webRequest = new ServletWebRequest(request, response);
   try {
      WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
      ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
      ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
      if (this.argumentResolvers != null) {
         invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
      }
      if (this.returnValueHandlers != null) {
         invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
      }
      invocableMethod.setDataBinderFactory(binderFactory);
      invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);

      ModelAndViewContainer mavContainer = new ModelAndViewContainer();
      mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
      modelFactory.initModel(webRequest, mavContainer, invocableMethod);
      mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
      AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
      asyncWebRequest.setTimeout(this.asyncRequestTimeout);

      WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
      asyncManager.setTaskExecutor(this.taskExecutor);
        .........
      if (asyncManager.hasConcurrentResult()) {
         ..........
      }

      invocableMethod.invokeAndHandle(webRequest, mavContainer);
      if (asyncManager.isConcurrentHandlingStarted()) {
         return null;
      }
      return getModelAndView(mavContainer, modelFactory, webRequest);
   }
   finally {
      webRequest.requestCompleted();
   }
}
public boolean hasConcurrentResult() {
   return (this.concurrentResult != RESULT_NONE);
}
private Object concurrentResult = RESULT_NONE;

  这篇文章之前的那些前置知识点,主要就是用在这里了。

   7、getDataBinderFactory

private WebDataBinderFactory getDataBinderFactory(HandlerMethod handlerMethod) throws Exception {
   Class<?> handlerType = handlerMethod.getBeanType();
   Set<Method> methods = this.initBinderCache.get(handlerType);
   if (methods == null) {
      methods = MethodIntrospector.selectMethods(handlerType, INIT_BINDER_METHODS);
      this.initBinderCache.put(handlerType, methods);
   }
   List<InvocableHandlerMethod> initBinderMethods = new ArrayList<>();
   this.initBinderAdviceCache.forEach((clazz, methodSet) -> {
      if (clazz.isApplicableToBeanType(handlerType)) {
         Object bean = clazz.resolveBean();
         for (Method method : methodSet) {
            initBinderMethods.add(createInitBinderMethod(bean, method));
         }
      }
   });
   for (Method method : methods) {
      Object bean = handlerMethod.getBean();
      initBinderMethods.add(createInitBinderMethod(bean, method));
   }
   return createDataBinderFactory(initBinderMethods);
}
protected InitBinderDataBinderFactory createDataBinderFactory(List<InvocableHandlerMethod> binderMethods)
      throws Exception {

   return new ServletRequestDataBinderFactory(binderMethods, getWebBindingInitializer());
}

   这里主要是就是将@InitBinder注解的的方法,不管是前面的ControllerAdvice注解添加的cache中的(initBinderAdviceCache)),还是当前handlerType本身有这个注解,都创建对应的InvocableHandlerMethod对象,通过createInitBinderMethod方法。

  8、createInitBinderMethod

private InvocableHandlerMethod createInitBinderMethod(Object bean, Method method) {
   InvocableHandlerMethod binderMethod = new InvocableHandlerMethod(bean, method);
   if (this.initBinderArgumentResolvers != null) {
      binderMethod.setHandlerMethodArgumentResolvers(this.initBinderArgumentResolvers);
   }
   binderMethod.setDataBinderFactory(new DefaultDataBinderFactory(this.webBindingInitializer));
   binderMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
   return binderMethod;
}

  这里就是创建binderFactory的内容(ServletRequestDataBinderFactory)。

  9、getModelFactory

private ModelFactory getModelFactory(HandlerMethod handlerMethod, WebDataBinderFactory binderFactory) {
   SessionAttributesHandler sessionAttrHandler = getSessionAttributesHandler(handlerMethod);
   Class<?> handlerType = handlerMethod.getBeanType();
   Set<Method> methods = this.modelAttributeCache.get(handlerType);
   if (methods == null) {
      methods = MethodIntrospector.selectMethods(handlerType, MODEL_ATTRIBUTE_METHODS);
      this.modelAttributeCache.put(handlerType, methods);
   }
   List<InvocableHandlerMethod> attrMethods = new ArrayList<>();
   // Global methods first
   this.modelAttributeAdviceCache.forEach((clazz, methodSet) -> {
      if (clazz.isApplicableToBeanType(handlerType)) {
         Object bean = clazz.resolveBean();
         for (Method method : methodSet) {
            attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
         }
      }
   });
   for (Method method : methods) {
      Object bean = handlerMethod.getBean();
      attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
   }
   return new ModelFactory(attrMethods, binderFactory, sessionAttrHandler);
}
public ModelFactory(@Nullable List<InvocableHandlerMethod> handlerMethods,
      WebDataBinderFactory binderFactory, SessionAttributesHandler attributeHandler) {

   if (handlerMethods != null) {
      for (InvocableHandlerMethod handlerMethod : handlerMethods) {
         this.modelMethods.add(new ModelMethod(handlerMethod));
      }
   }
   this.dataBinderFactory = binderFactory;
   this.sessionAttributesHandler = attributeHandler;
}

  这里与上面WebDataBinderFactory 类似,不过这里是使用就是MODEL_ATTRIBUTE_METHODS这个MethodFilter。例如当前handlerMethod对应handlerType对应的@RequestMapping、@ModelAttribute注解(这个前置知识里面有分析),然后去创建ModelFactory。

  10、createModelAttributeMethod

private InvocableHandlerMethod createModelAttributeMethod(WebDataBinderFactory factory, Object bean, Method method) {
   InvocableHandlerMethod attrMethod = new InvocableHandlerMethod(bean, method);
   if (this.argumentResolvers != null) {
      attrMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
   }
   attrMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
   attrMethod.setDataBinderFactory(factory);
   return attrMethod;
}

   这里也是将这些method创建为InvocableHandlerMethod。我们再回到前面的invokeHandlerMethod方法。

  11、createInvocableHandlerMethod

protected ServletInvocableHandlerMethod createInvocableHandlerMethod(HandlerMethod handlerMethod) {
   return new ServletInvocableHandlerMethod(handlerMethod);
}

  这里是将当前要处理的HandlerMethod转化为ServletInvocableHandlerMethod。再之后就对其进行一些初始化设置argumentResolvers、returnValueHandlers。

  12、modelFactory.initModel

    这些都处理后之后就是initModel

public void initModel(NativeWebRequest request, ModelAndViewContainer container,
      HandlerMethod handlerMethod) throws Exception {

   Map<String, ?> sessionAttributes = this.sessionAttributesHandler.retrieveAttributes(request);
   container.mergeAttributes(sessionAttributes);
   invokeModelAttributeMethods(request, container);
   for (String name : findSessionAttributeArguments(handlerMethod)) {
      if (!container.containsAttribute(name)) {
         Object value = this.sessionAttributesHandler.retrieveAttribute(request, name);
         if (value == null) {
            throw new HttpSessionRequiredException("Expected session attribute '" + name + "'", name);
         }
         container.addAttribute(name, value);
      }
   }
}

   这里主要是invokeModelAttributeMethods,去执行modelMethods

 13、invokeModelAttributeMethods

private void invokeModelAttributeMethods(NativeWebRequest request, ModelAndViewContainer container)
      throws Exception {

   while (!this.modelMethods.isEmpty()) {
      InvocableHandlerMethod modelMethod = getNextModelMethod(container).getHandlerMethod();
      ModelAttribute ann = modelMethod.getMethodAnnotation(ModelAttribute.class);
      if (container.containsAttribute(ann.name())) {
         if (!ann.binding()) {
            container.setBindingDisabled(ann.name());
         }
         continue;
      }

      Object returnValue = modelMethod.invokeForRequest(request, container);
      if (!modelMethod.isVoid()){
         String returnValueName = getNameForReturnValue(returnValue, modelMethod.getReturnType());
         if (!ann.binding()) {
            container.setBindingDisabled(returnValueName);
         }
         if (!container.containsAttribute(returnValueName)) {
            container.addAttribute(returnValueName, returnValue);
         }
      }
   }
}
boolean binding() default true;
public boolean containsAttribute(String name) {
   return getModel().containsAttribute(name);
}

    要更好的理解整个地方,可以去看下前面写的这篇文章的demo部分,这里就不多赘叙了。这里再加一种情况来说明整个情况,就是有返回的:

@ModelAttribute
public StudentVo modelAttributeMethodResult(@RequestParam("age") Integer age
        , @RequestParam("type") Short type, Model model)
{    
    StudentVo studentVo = new StudentVo();
    studentVo.setAge(age);
    return studentVo;
}

这里如果主动设置binding为false,如果当前ModelAttribute注解的name在container的model中有,将其设置到container的Model中,直接return。如果还没有,就进行下面的invokeForRequest方法直接执行该方法。

   我们想看前一篇的demo在这里的设置:

         

   这里是返回void,所以没有下面的操作。下面来看执行的第二个方法,有返回的:

   

   获取默认名称,如果没有,将其添加的model中,供以后去获取

   这里的initModel方法完成后,就是AsyncWebRequest,这个是与异步相关的,SpringMVC不会主动去处理,这里就先跳过。

  14、invocableMethod.invokeAndHandle

    这个方法也在前面文章的前置知识点有单独提取处理,这个就是去执行MethodHandler的,这里就不再过多赘述。

  15、getModelAndView

     执行完MethodHandler后,就是去获取ModelAndView

private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
      ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {

   modelFactory.updateModel(webRequest, mavContainer);
   if (mavContainer.isRequestHandled()) {
      return null;
   }
   ModelMap model = mavContainer.getModel();
   ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model);
   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;
}

  这里主要是两个点,一个isRequestHandled,这个我们再以前梳理HandlerMapping的时候有设置,现在可以知道这个设置是干什么的了,就是表示不需要再往下,去处理与View相关的内容了(简单来说就是不需要使用ModelAndView )。第二个就是通过mavContainer去获取创建ModelAndView。

      总结

    至此,关于HandlerAdapter的的父子结构与源码梳理就完成了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值