SpringMVC源码分析----HandlerAdapter

HandlerAdapter的结构图:

       如上所示:总共五个实现类,有一个还被摒弃了,除了RequestMappingHandlerAdapter适配器,其他都很简单,只需要调用各自的方法就可以了。HttpReqeustHandlerAdapter、SimpleServletHandlerAdapter和SimpleControllerHandlerAdapter分别适配HttpRequestHandler、Servlet和Controller类型的Handler。方法很简单,源码举例一个其他类似。如下:

   public class SimpleControllerHandlerAdapter implements HandlerAdapter {
    public SimpleControllerHandlerAdapter() {
    }

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

    @Nullable
    public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return ((Controller)handler).handleRequest(request, response);
    }

    public long getLastModified(HttpServletRequest request, Object handler) {
        return handler instanceof LastModified ? ((LastModified)handler).getLastModified(request) : -1L;
    }
}

一、RequestMappingHandlerAdapter概述

          主要分析RequestMappingAdapter类,RequestMappingAdapter继承AbstractHandlerMethodAdapter,后者分别调用三个模板方法由子类实现,其中supportsInternal还多加了一个判断Handler是否是HandlerMethod类型。源码:

   public abstract class AbstractHandlerMethodAdapter extends WebContentGenerator implements HandlerAdapter, Ordered {
    private int order = 2147483647;

    public AbstractHandlerMethodAdapter() {
        super(false);
    }

    public void setOrder(int order) {
        this.order = order;
    }

    public int getOrder() {
        return this.order;
    }

    public final boolean supports(Object handler) {
            //这里多加了是否是HandlerMethod方法,其他都使用模板方法
        return handler instanceof HandlerMethod && this.supportsInternal((HandlerMethod)handler); 
    }

    protected abstract boolean supportsInternal(HandlerMethod var1);

    @Nullable
    public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return this.handleInternal(request, response, (HandlerMethod)handler);
    }

    @Nullable
    protected abstract ModelAndView handleInternal(HttpServletRequest var1, HttpServletResponse var2, HandlerMethod var3) throws Exception;

    public final long getLastModified(HttpServletRequest request, Object handler) {
        return this.getLastModifiedInternal(request, (HandlerMethod)handler);
    }

    protected abstract long getLastModifiedInternal(HttpServletRequest var1, HandlerMethod var2);
}

    接下来就看RequestMappingHandlerAdapter,这个可以说是SpringMVC中最复杂的组件它的supportsInternal直接返回true,只需要满足父类中的HandlerMethod类型的要求就可以了。getLastModifiedInternal直接返回-1;最重要的就是handlerInternal方法了,就是这个方法实际使用Handler处理请求。具体步骤有如下三步:

  • 备好处理器所需要的参数(这个最难,参数的不确定性)
  • 使用处理器处理请求  (这个比较简单,直接用反射调用handleMethod处理就可以了)
  • 处理返回值,也就是将不同类型的返回值统一处理成ModelAndView类

1.备好处理器所需要的参数

      1.1.备好参数需要考虑的问题:

  • 1)都有哪些参数需要绑定?

           解答:除了方法确定的参数,还有两个方法的参数需要绑定,那就是当前处理器相对应注释了@ModelAttribute和注释了@InitBinder的方法

  • 2)参数的值的来源?

            解答:有六个参数的来源:

                               request中相关的参数,主要包括url中的参数、post中过来的参数,以及请求头包含的值;

                               cookie中的参数

                               session中给的参数

                               设置到FlashMap中的参数,这种参数用于redirect的参数传递

                               SessionAttribute传递的参数,这类参数通过@SessionAttribute注释传递

                               通过相应的注释了@ModelAttribute的方法设置的参数

  • 3)具体进行绑定的方法?

  1.2 参数具体的解析

      参数解析使用HandlerMethodArgumentResolver类型的组件完成的,不同类型的使用不同的ArgumentResolver来解析。有的Resolver内部使用了WebDataBinder,可以通过注释了@InitBinder的方法来初始化,注释了@InitBinder的方法也需要绑定参数,而且也是不确定的,所以@InitBinder注释的方法也需要ArgumentResolver来解析参数,使用的和Handler不同的一套ArgumentResolver,另外注释了ModelAttribute的方法也需要绑定参数,使用的和Handler使用的是同一套ArgumentResolver。

二、RequestMappingHandlerAdapter之器

         主要是在方法afterProperties中,RequestMappingAdapter实现了InitializaingBean接口,所以在初始化这个bean时,会调用这个方法,这个方法主要初始化了argumentResolver,initBinderArgumentResolvers,returnVAlueHandlers以及@ControllerAdvice注释的类相关的modelAttributeAdviceCache、initBinderAdviceCache和responseBodyAdvice这六个属性。

知识集锦:

  • argumentResolvers:用于处理器方法和注释了@ModelAttribute的方法设置参数
  • initBinderArgumentResolvers:用于给注释了@initBinder的方法设置参数
  • returnValueHandlers:用于将处理器的返回值处理为ModelAndView的类型
  • modelAttributeAdviceCache和initBinderAdviceCache:分别用于缓存@ControllerAdvice注释的类里面注释了@ModelAttribute和@InitBinder方法,也就是全局的@ModelAttribute和InitBinder方法。
  • requestResponseBodyAdvice:用来保存前面介绍过的实现了RequestBodyAdvice和ResponseBodyAdvice接口,可以修改接受到参数的类和返回的ResponseBody的类。

源码分析:

public void afterPropertiesSet() {
        //初始化注释了@ControllerAdvice的类的三个属性
        this.initControllerAdviceCache();
        List handlers;
        if (this.argumentResolvers == null) {
            //初始化argumentResolvers 
            handlers = this.getDefaultArgumentResolvers();
            this.argumentResolvers = (new HandlerMethodArgumentResolverComposite()).addResolvers(handlers);
        }

        if (this.initBinderArgumentResolvers == null) {
            //初始化initBinderArgumentResolvers 
            handlers = this.getDefaultInitBinderArgumentResolvers();
            this.initBinderArgumentResolvers = (new HandlerMethodArgumentResolverComposite()).addResolvers(handlers);
        }

        if (this.returnValueHandlers == null) {
             //初始化returnValueHandlers 
            handlers = this.getDefaultReturnValueHandlers();
            this.returnValueHandlers = (new HandlerMethodReturnValueHandlerComposite()).addHandlers(handlers);
        }

    }
    
    //获取注释了@ControllerAdvice全局的属性
    private void initControllerAdviceCache() {
        if (this.getApplicationContext() != null) {
            if (this.logger.isInfoEnabled()) {
                this.logger.info("Looking for @ControllerAdvice: " + this.getApplicationContext());
            }
            //获取到所有注释了@ControllerAdvice的bean
            List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(this.getApplicationContext());
            //根据order排序
            AnnotationAwareOrderComparator.sort(adviceBeans);
            List<Object> requestResponseBodyAdviceBeans = new ArrayList();
            Iterator var3 = adviceBeans.iterator();

            while(var3.hasNext()) {
                ControllerAdviceBean adviceBean = (ControllerAdviceBean)var3.next();
                Class<?> beanType = adviceBean.getBeanType();
                if (beanType == null) {
                    throw new IllegalStateException("Unresolvable type for ControllerAdviceBean: " + adviceBean);
                }
                //查找注释了@ModelAttribute而且没有注释@RequestMapping的方法
                Set<Method> attrMethods = MethodIntrospector.selectMethods(beanType, MODEL_ATTRIBUTE_METHODS);
                if (!attrMethods.isEmpty()) {
                    this.modelAttributeAdviceCache.put(adviceBean, attrMethods);
                    if (this.logger.isInfoEnabled()) {
                        this.logger.info("Detected @ModelAttribute methods in " + adviceBean);
                    }
                }
                //查找注释了@InitBinder的方法
                Set<Method> binderMethods = MethodIntrospector.selectMethods(beanType, INIT_BINDER_METHODS);
                if (!binderMethods.isEmpty()) {
                    this.initBinderAdviceCache.put(adviceBean, binderMethods);
                    if (this.logger.isInfoEnabled()) {
                        this.logger.info("Detected @InitBinder methods in " + adviceBean);
                    }
                }
                //查找实现了RequestBodyAdvice接口的类
                if (RequestBodyAdvice.class.isAssignableFrom(beanType)) {
                    requestResponseBodyAdviceBeans.add(adviceBean);
                    if (this.logger.isInfoEnabled()) {
                        this.logger.info("Detected RequestBodyAdvice bean in " + adviceBean);
                    }
                }
                //查找实现了ResponseBodyAdvice接口的类
                if (ResponseBodyAdvice.class.isAssignableFrom(beanType)) {
                    requestResponseBodyAdviceBeans.add(adviceBean);
                    if (this.logger.isInfoEnabled()) {
                        this.logger.info("Detected ResponseBodyAdvice bean in " + adviceBean);
                    }
                }
            }
            //将查找的RequestBodyAdvice和ResponseBodyAdvice接口的类添加到requestResponseBodyAdvice属性中    
            if (!requestResponseBodyAdviceBeans.isEmpty()) {
                this.requestResponseBodyAdvice.addAll(0, requestResponseBodyAdviceBeans);
            }

        }
    }

     另外有三个getDefaultXXX方法,在和我三个方法都是十分相似的,看一个即可,如getDEfaultArgumentResolver,这个是用来设置ArgumentResolver属性,这是一个非常核心的属性。

源码:

private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
        List<HandlerMethodArgumentResolver> resolvers = new ArrayList();

        //添加按注释解析参数的解析器,例如@RequestParam,@PathVariable等
        resolvers.add(new RequestParamMethodArgumentResolver(this.getBeanFactory(), false));
        resolvers.add(new RequestParamMapMethodArgumentResolver());
        resolvers.add(new PathVariableMethodArgumentResolver());
        resolvers.add(new PathVariableMapMethodArgumentResolver());
        resolvers.add(new MatrixVariableMethodArgumentResolver());
        resolvers.add(new MatrixVariableMapMethodArgumentResolver());
        resolvers.add(new ServletModelAttributeMethodProcessor(false));
        resolvers.add(new RequestResponseBodyMethodProcessor(this.getMessageConverters(), this.requestResponseBodyAdvice));
        resolvers.add(new RequestPartMethodArgumentResolver(this.getMessageConverters(), this.requestResponseBodyAdvice));
        resolvers.add(new RequestHeaderMethodArgumentResolver(this.getBeanFactory()));
        resolvers.add(new RequestHeaderMapMethodArgumentResolver());
        resolvers.add(new ServletCookieValueMethodArgumentResolver(this.getBeanFactory()));
        resolvers.add(new ExpressionValueMethodArgumentResolver(this.getBeanFactory()));

        添加按类型解析的解析器
        resolvers.add(new SessionAttributeMethodArgumentResolver());
        resolvers.add(new RequestAttributeMethodArgumentResolver());
        resolvers.add(new ServletRequestMethodArgumentResolver());
        resolvers.add(new ServletResponseMethodArgumentResolver());
        resolvers.add(new HttpEntityMethodProcessor(this.getMessageConverters(), this.requestResponseBodyAdvice));
        resolvers.add(new RedirectAttributesMethodArgumentResolver());
        resolvers.add(new ModelMethodProcessor());
        resolvers.add(new MapMethodProcessor());
        resolvers.add(new ErrorsMethodArgumentResolver());
        resolvers.add(new SessionStatusMethodArgumentResolver());
        resolvers.add(new UriComponentsBuilderMethodArgumentResolver());

        //添加自定义参数解析器,主要用于解析自定义的类型,这个一般都用不上
        if (this.getCustomArgumentResolvers() != null) {
            resolvers.addAll(this.getCustomArgumentResolvers());
        }
        
        //这两个解析器可以解析所有类型的参数
        resolvers.add(new RequestParamMethodArgumentResolver(this.getBeanFactory(), true));
        resolvers.add(new ServletModelAttributeMethodProcessor(true));
        return resolvers;
    }

二、RequestMappingHandlerAdapter之用

        RequestMappingHandlerAdapter的入口方法是handlerInternal,源码如下:

protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse 
    response, HandlerMethod handlerMethod) throws Exception {
        this.checkRequest(request);
        ModelAndView mav;
        if (this.synchronizeOnSession) {
            HttpSession session = request.getSession(false);
            if (session != null) {
                Object mutex = WebUtils.getSessionMutex(session);
                synchronized(mutex) {
                    mav = this.invokeHandlerMethod(request, response, handlerMethod);
                }
            } else {
                mav = this.invokeHandlerMethod(request, response, handlerMethod);
            }
        } else {
            mav = this.invokeHandlerMethod(request, response, handlerMethod);
        }

        if (!response.containsHeader("Cache-Control")) {
            //判断是否有@SessionAttribute注释的参数
            if (this.getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
                this.applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
            } else {
                this.prepareResponse(response);
            }
        }

        return mav;
    }

上面主要是invokeHandlerMethod方法和applyCacheSeconds,prepareResponse方法,

invokeHandlerMethod方法首先通过request和Response创建了ServletWebRequest类型的webRequest,在ArgumentResolver解析参数时使用的是webRequest。接着对WebDataBinderFactory、ModelFactory、ServletInvocableHandlerMethod这三个类的变量进行定义和初始化。源码:

 protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
        ServletWebRequest webRequest = new ServletWebRequest(request, response);

        Object result;
        try {
            WebDataBinderFactory binderFactory = this.getDataBinderFactory(handlerMethod);
            ModelFactory modelFactory = this.getModelFactory(handlerMethod, binderFactory);
            ServletInvocableHandlerMethod invocableMethod = this.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);
            asyncManager.setAsyncWebRequest(asyncWebRequest);
            asyncManager.registerCallableInterceptors(this.callableInterceptors);
            asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
            if (asyncManager.hasConcurrentResult()) {
                result = asyncManager.getConcurrentResult();
                mavContainer = (ModelAndViewContainer)asyncManager.getConcurrentResultContext()[0];
                asyncManager.clearConcurrentResult();
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("Found concurrent result value [" + result + "]");
                }

                invocableMethod = invocableMethod.wrapConcurrentResult(result);
            }

            invocableMethod.invokeAndHandle(webRequest, mavContainer, new Object[0]);
            if (!asyncManager.isConcurrentHandlingStarted()) {
                ModelAndView var15 = this.getModelAndView(mavContainer, modelFactory, webRequest);
                return var15;
            }

            result = null;
        } finally {
            webRequest.requestCompleted();
        }

        return (ModelAndView)result;
    }

知识集锦:

WebDataBinderFactory:用来创建WebDataBinder------用于参数绑定,主要功能是实现参数跟String之间的类型转换,ArgumentResolver在进行参数解析过程中会用到WebDataBinder,另外ModelFactory更新Model时也会用到它。WebDataBinderFactory的创建过程就是讲符合条件的注释了@InitBinder的方法找出来,并使用他们新建出ServletRequestDataBinderFactory类型的WebDataBinderFactory。这里的InitBinder包含在@ControllerAdvice中和处理器自己包含的两种情况。

ModelFactory:用来处理Model的,主要包含两个功能:

    在处理器具体处理器之前对Model进行初始化(将原来的SEssionAttributes中的值设置到Model;执行相应注释了@ModelAttribute的方法并设置到Model中;处理器注释了@ModelAttribute的参数如果同时在SessionAttributes中也配置了,而且mavContainer中还没有值,则ongoing全部SessionAttribute中查找并设置进去);

     在处理完请求后对Model参数进行更新(先对SessionAttributes进行设置,设置跪着是如果处理器调用了SessionStatus#setComplete浙江SessionAttribute清空)

ServletInvocableHandlerMethod:它继承HandlerMethod,并且可以直接执行,实际的请求就是通过它来处理的,参数绑定、处理请求以及返回值处理都是在它里面完成的。

猜你喜欢

转载自blog.csdn.net/weixin_40792878/article/details/81836708
今日推荐