美文网首页
Spring MVC请求处理(四) - HandlerAdapt

Spring MVC请求处理(四) - HandlerAdapt

作者: buzzerrookie | 来源:发表于2019-03-23 14:21 被阅读0次

    DispatcherServlet的doDispatch方法利用getAdapter根据处理器对象从注册的HandlerAdapter中找到第一个支持该处理器的HandlerAdapter:

    protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
        for (HandlerAdapter ha : this.handlerAdapters) {
            if (logger.isTraceEnabled()) {
                logger.trace("Testing handler adapter [" + ha + "]");
            }
            if (ha.supports(handler)) {
                return ha;
            }
        }
        throw new ServletException("No adapter for handler [" + handler +
                "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
    }
    

    接着调用HandlerAdapter的handle方法去处理请求,那么HandlerAdapter是什么呢?

    // Actually invoke the handler.
    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    

    HandlerAdapter接口

    HandlerAdapter接口是MVC架构的SPI,允许核心MVC工作流的参数化,其类层次结构如下图。


    HandlerAdapter接口的类层次结构.png

    HandlerAdapter接口的代码如下所示,有三个接口方法。

    public interface HandlerAdapter {
    
        boolean supports(Object handler);
    
        ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
    
        long getLastModified(HttpServletRequest request, Object handler);
    }
    
    • supports方法表示该HandlerAdapter是否支持某一处理器,该方法参数是Object类型,Javadoc解释如下

      Note that a handler can be of type Object. This is to enable handlers from other frameworks to be integrated with this framework without custom coding, as well as to allow for annotation-driven handler objects that do not obey any specific Java interface.

    • handle方法使用处理器处理请求。

    AbstractHandlerMethodAdapter类

    从类名可以看出AbstractHandlerMethodAdapter类是支持HandlerMethod类型处理器的HandlerAdapter。

    public abstract class AbstractHandlerMethodAdapter extends WebContentGenerator implements HandlerAdapter, Ordered {
    
        private int order = Ordered.LOWEST_PRECEDENCE;
    
        public AbstractHandlerMethodAdapter() {
            // no restriction of HTTP methods by default
            super(false);
        }
    
        public void setOrder(int order) {
            this.order = order;
        }
    
        @Override
        public int getOrder() {
            return this.order;
        }
    
        @Override
        public final boolean supports(Object handler) {
            return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
        }
    
        protected abstract boolean supportsInternal(HandlerMethod handlerMethod);
    
        @Override
        public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
                throws Exception {
            return handleInternal(request, response, (HandlerMethod) handler);
        }
    
        protected abstract ModelAndView handleInternal(HttpServletRequest request,
                HttpServletResponse response, HandlerMethod handlerMethod) throws Exception;
    
        @Override
        public final long getLastModified(HttpServletRequest request, Object handler) {
            return getLastModifiedInternal(request, (HandlerMethod) handler);
        }
    
        protected abstract long getLastModifiedInternal(HttpServletRequest request, HandlerMethod handlerMethod);
    }
    
    • supports方法是一个模板方法,一个条件是处理器必须是HandlerMethod类型,另一个条件由子类重写supportsInternal抽象方法指定;
    • handle方法也是一个模板方法,需要由子类重写handleInternal抽象方法;
    • getLastModified方法仍然是一个模板方法,需要由子类重写getLastModifiedInternal抽象方法。

    RequestMappingHandlerAdapter类

    RequestMappingHandlerAdapter类继承了AbstractHandlerMethodAdapter类,重写了上述三个抽象方法。

    成员变量

    public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
            implements BeanFactoryAware, InitializingBean {
    
        private List<HandlerMethodArgumentResolver> customArgumentResolvers;
    
        private HandlerMethodArgumentResolverComposite argumentResolvers;
    
        private HandlerMethodArgumentResolverComposite initBinderArgumentResolvers;
    
        private List<HandlerMethodReturnValueHandler> customReturnValueHandlers;
    
        private HandlerMethodReturnValueHandlerComposite returnValueHandlers;
    
        private List<ModelAndViewResolver> modelAndViewResolvers;
    
        private ContentNegotiationManager contentNegotiationManager = new ContentNegotiationManager();
    
        private List<HttpMessageConverter<?>> messageConverters;
    
        private List<Object> requestResponseBodyAdvice = new ArrayList<Object>();
    
        private WebBindingInitializer webBindingInitializer;
    
        private AsyncTaskExecutor taskExecutor = new SimpleAsyncTaskExecutor("MvcAsync");
    
        private Long asyncRequestTimeout;
    
        private CallableProcessingInterceptor[] callableInterceptors = new CallableProcessingInterceptor[0];
    
        private DeferredResultProcessingInterceptor[] deferredResultInterceptors = new DeferredResultProcessingInterceptor[0];
    
        private boolean ignoreDefaultModelOnRedirect = false;
    
        private int cacheSecondsForSessionAttributeHandlers = 0;
    
        private boolean synchronizeOnSession = false;
    
        private SessionAttributeStore sessionAttributeStore = new DefaultSessionAttributeStore();
    
        private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
    
        private ConfigurableBeanFactory beanFactory;
    
    
        private final Map<Class<?>, SessionAttributesHandler> sessionAttributesHandlerCache =
                new ConcurrentHashMap<Class<?>, SessionAttributesHandler>(64);
    
        private final Map<Class<?>, Set<Method>> initBinderCache = new ConcurrentHashMap<Class<?>, Set<Method>>(64);
    
        private final Map<ControllerAdviceBean, Set<Method>> initBinderAdviceCache =
                new LinkedHashMap<ControllerAdviceBean, Set<Method>>();
    
        private final Map<Class<?>, Set<Method>> modelAttributeCache = new ConcurrentHashMap<Class<?>, Set<Method>>(64);
    
        private final Map<ControllerAdviceBean, Set<Method>> modelAttributeAdviceCache =
                new LinkedHashMap<ControllerAdviceBean, Set<Method>>();
    
    
        public RequestMappingHandlerAdapter() {
            StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
            stringHttpMessageConverter.setWriteAcceptCharset(false);  // see SPR-7316
    
            this.messageConverters = new ArrayList<HttpMessageConverter<?>>(4);
            this.messageConverters.add(new ByteArrayHttpMessageConverter());
            this.messageConverters.add(stringHttpMessageConverter);
            this.messageConverters.add(new SourceHttpMessageConverter<Source>());
            this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());
        }
        // setter与geter方法
        // 省略其他方法
    }
    

    RequestMappingHandlerAdapter类的成员变量很多,从变量名可以看出用途:

    • customArgumentResolvers保存自定义参数解析器;
    • argumentResolvers保存默认参数解析器和自定义参数解析器,它的类型是HandlerMethodArgumentResolverComposite,这个类使用了组合模式的设计模式。;
    • initBinderArgumentResolvers保存@InitBinder注解修饰的参数解析器;
    • customReturnValueHandlers保存自定义返回值处理器;
    • returnValueHandlers保存默认返回值处理器和自定义返回值处理器,它的类型是HandlerMethodReturnValueHandlerComposite,这个类也使用了组合模式的设计模式;
    • messageConverters保存消息转换器;
    • requestResponseBodyAdvice保存实现了RequestBodyAdvice或ResponseBodyAdvice接口的bean;
    • modelAttributeAdviceCache的映射关系是从@ControllerAdvice注解修饰的bean到bean中被@ModelAttribute注解修饰但没有被@RequestMapping注解修饰的所有方法;
    • initBinderAdviceCache的映射关系是从@ControllerAdvice注解修饰的bean到bean中被@InitBinder注解修饰的所有方法;
    • ...

    初始化

    RequestMappingHandlerAdapter类实现了InitializingBean接口,其重写的afterPropertiesSet方法如下,从代码可以看到初始化过程主要做了安装参数解析器和返回值处理器等工作。

    @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);
        }
    }
    
    1. 发现@ControllerAdvice

    initControllerAdviceCache方法用于发现上下文中的@ControllerAdvice注解修饰的bean,代码如下所示:

    private void initControllerAdviceCache() {
        if (getApplicationContext() == null) {
            return;
        }
        if (logger.isInfoEnabled()) {
            logger.info("Looking for @ControllerAdvice: " + getApplicationContext());
        }
    
        List<ControllerAdviceBean> beans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
        AnnotationAwareOrderComparator.sort(beans);
    
        List<Object> requestResponseBodyAdviceBeans = new ArrayList<Object>();
    
        for (ControllerAdviceBean bean : beans) {
            Set<Method> attrMethods = MethodIntrospector.selectMethods(bean.getBeanType(), MODEL_ATTRIBUTE_METHODS);
            if (!attrMethods.isEmpty()) {
                this.modelAttributeAdviceCache.put(bean, attrMethods);
                if (logger.isInfoEnabled()) {
                    logger.info("Detected @ModelAttribute methods in " + bean);
                }
            }
            Set<Method> binderMethods = MethodIntrospector.selectMethods(bean.getBeanType(), INIT_BINDER_METHODS);
            if (!binderMethods.isEmpty()) {
                this.initBinderAdviceCache.put(bean, binderMethods);
                if (logger.isInfoEnabled()) {
                    logger.info("Detected @InitBinder methods in " + bean);
                }
            }
            if (RequestBodyAdvice.class.isAssignableFrom(bean.getBeanType())) {
                requestResponseBodyAdviceBeans.add(bean);
                if (logger.isInfoEnabled()) {
                    logger.info("Detected RequestBodyAdvice bean in " + bean);
                }
            }
            if (ResponseBodyAdvice.class.isAssignableFrom(bean.getBeanType())) {
                requestResponseBodyAdviceBeans.add(bean);
                if (logger.isInfoEnabled()) {
                    logger.info("Detected ResponseBodyAdvice bean in " + bean);
                }
            }
        }
    
        if (!requestResponseBodyAdviceBeans.isEmpty()) {
            this.requestResponseBodyAdvice.addAll(0, requestResponseBodyAdviceBeans);
        }
    }
    

    对每个@ControllerAdvice注解修饰的bean:

    • 发现其中被@ModelAttribute注解修饰但没有被@RequestMapping注解修饰的方法,将bean与这些方法的关联加入modelAttributeAdviceCache;
    • 发现其中被@InitBinder注解修饰的方法,将bean与这些方法的关联加入initBinderAdviceCache;
    • 若是RequestBodyAdvice类型则将该bean加入requestResponseBodyAdvice;
    • 若是ResponseBodyAdvice类型则将该bean加入requestResponseBodyAdvice。
    2. 安装默认参数解析器和自定义参数解析器

    若还没有安装参数解析器则安装默认的参数解析器和自定义的参数解析器,这些参数解析器是在getDefaultArgumentResolvers方法中生成的。

    private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
        List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>();
    
        // Annotation-based argument resolution
        resolvers.add(new RequestParamMethodArgumentResolver(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(getMessageConverters(), this.requestResponseBodyAdvice));
        resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice));
        resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
        resolvers.add(new RequestHeaderMapMethodArgumentResolver());
        resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
        resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
        resolvers.add(new SessionAttributeMethodArgumentResolver());
        resolvers.add(new RequestAttributeMethodArgumentResolver());
    
        // Type-based argument resolution
        resolvers.add(new ServletRequestMethodArgumentResolver());
        resolvers.add(new ServletResponseMethodArgumentResolver());
        resolvers.add(new HttpEntityMethodProcessor(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());
    
        // Custom arguments
        if (getCustomArgumentResolvers() != null) {
            resolvers.addAll(getCustomArgumentResolvers());
        }
    
        // Catch-all
        resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
        resolvers.add(new ServletModelAttributeMethodProcessor(true));
    
        return resolvers;
    }
    
    • 默认的参数解析器有基于注解和基于类型两种,基于注解的有解析@RequestParam修饰参数的RequestParamMethodArgumentResolver、解析@PathVariable修饰参数的PathVariableMethodArgumentResolver和解析@RequestBody修饰参数的RequestResponseBodyMethodProcessor等,基于类型的有解析ServletRequest类型参数的ServletRequestMethodArgumentResolver和解析ServletResponse类型参数的ServletResponseMethodArgumentResolver等;
    • 自定义参数解析器可以通过配置类向Spring注册:
      @Configuration
      public class WebMvcConfigurer extends WebMvcConfigurerAdapter {
      
          @Override
          public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
          }
      }
      
    3. 安装@InitBinder注解修饰的参数解析器

    若还没有安装@InitBinder注解修饰的参数解析器则安装默认的InitBinder参数解析器和自定义参数解析器,这些参数解析器是在getDefaultInitBinderArgumentResolvers方法中生成的。

    private List<HandlerMethodArgumentResolver> getDefaultInitBinderArgumentResolvers() {
        List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>();
    
        // Annotation-based argument resolution
        resolvers.add(new RequestParamMethodArgumentResolver(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 ExpressionValueMethodArgumentResolver(getBeanFactory()));
        resolvers.add(new SessionAttributeMethodArgumentResolver());
        resolvers.add(new RequestAttributeMethodArgumentResolver());
    
        // Type-based argument resolution
        resolvers.add(new ServletRequestMethodArgumentResolver());
        resolvers.add(new ServletResponseMethodArgumentResolver());
    
        // Custom arguments
        if (getCustomArgumentResolvers() != null) {
            resolvers.addAll(getCustomArgumentResolvers());
        }
    
        // Catch-all
        resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
    
        return resolvers;
    }
    
    4. 安装默认的返回值处理器

    若还没有安装返回值处理器则安装默认的返回值处理器和自定义的返回值处理器,这些返回值处理器是在getDefaultReturnValueHandlers方法中生成的。

    private List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() {
        List<HandlerMethodReturnValueHandler> handlers = new ArrayList<HandlerMethodReturnValueHandler>();
    
        // Single-purpose return value types
        handlers.add(new ModelAndViewMethodReturnValueHandler());
        handlers.add(new ModelMethodProcessor());
        handlers.add(new ViewMethodReturnValueHandler());
        handlers.add(new ResponseBodyEmitterReturnValueHandler(getMessageConverters()));
        handlers.add(new StreamingResponseBodyReturnValueHandler());
        handlers.add(new HttpEntityMethodProcessor(getMessageConverters(),
                this.contentNegotiationManager, this.requestResponseBodyAdvice));
        handlers.add(new HttpHeadersReturnValueHandler());
        handlers.add(new CallableMethodReturnValueHandler());
        handlers.add(new DeferredResultMethodReturnValueHandler());
        handlers.add(new AsyncTaskMethodReturnValueHandler(this.beanFactory));
    
        // Annotation-based return value types
        handlers.add(new ModelAttributeMethodProcessor(false));
        handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(),
                this.contentNegotiationManager, this.requestResponseBodyAdvice));
    
        // Multi-purpose return value types
        handlers.add(new ViewNameMethodReturnValueHandler());
        handlers.add(new MapMethodProcessor());
    
        // Custom return value types
        if (getCustomReturnValueHandlers() != null) {
            handlers.addAll(getCustomReturnValueHandlers());
        }
    
        // Catch-all
        if (!CollectionUtils.isEmpty(getModelAndViewResolvers())) {
            handlers.add(new ModelAndViewResolverMethodReturnValueHandler(getModelAndViewResolvers()));
        }
        else {
            handlers.add(new ModelAttributeMethodProcessor(true));
        }
    
        return handlers;
    }
    
    • 默认的返回值处理器有处理@ModelAttribute修饰返回值的ModelAttributeMethodProcessor、处理@RequestBody修饰返回值的RequestResponseBodyMethodProcessor和HttpEntityMethodProcessor等;
    • 自定义返回值处理器也可以通过配置类向Spring注册:
      @Configuration
      public class WebMvcConfigurer extends WebMvcConfigurerAdapter {
      
          @Override
          public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {
          }
      }
      

    supportsInternal方法

    RequestMappingHandlerAdapter类重写的supportsInternal方法如下,因为总是返回true,所以其支持的处理器必须是HandlerMethod类型。

    @Override
    protected boolean supportsInternal(HandlerMethod handlerMethod) {
        return true;
    }
    

    handleInternal方法处理请求

    RequestMappingHandlerAdapter类重写了AbstractHandlerMethodAdapter类的handleInternal方法以处理请求,其中参数handlerMethod就是doDispatch中getHandler方法返回的匹配请求的HandlerExecutionChain封装的HandlerMethod。

    @Override
    protected ModelAndView handleInternal(HttpServletRequest request,
            HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
        ModelAndView mav;
        checkRequest(request);
        // Execute invokeHandlerMethod in synchronized block if required.
        if (this.synchronizeOnSession) {
            HttpSession session = request.getSession(false);
            if (session != null) {
                Object mutex = WebUtils.getSessionMutex(session);
                synchronized (mutex) {
                    mav = invokeHandlerMethod(request, response, handlerMethod);
                }
            }
            else {
                // No HttpSession available -> no mutex necessary
                mav = invokeHandlerMethod(request, response, handlerMethod);
            }
        }
        else {
            // No synchronization on session demanded at all...
            mav = invokeHandlerMethod(request, response, handlerMethod);
        }
    
        if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
            if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
                applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
            }
            else {
                prepareResponse(response);
            }
        }
    
        return mav;
    }
    

    可以看到不管走哪个分支最后都会调用invokeHandlerMethod这个函数:

    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);
            invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
            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()) {
                Object result = asyncManager.getConcurrentResult();
                mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
                asyncManager.clearConcurrentResult();
                if (logger.isDebugEnabled()) {
                    logger.debug("Found concurrent result value [" + result + "]");
                }
                invocableMethod = invocableMethod.wrapConcurrentResult(result);
            }
    
            invocableMethod.invokeAndHandle(webRequest, mavContainer);
            if (asyncManager.isConcurrentHandlingStarted()) {
                return null;
            }
    
            return getModelAndView(mavContainer, modelFactory, webRequest);
        }
        finally {
            webRequest.requestCompleted();
        }
    }
    

    这个函数的处理流程如下:

    1. @InitBinder增强

    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<InvocableHandlerMethod>();
        // Global methods first
        for (Entry<ControllerAdviceBean, Set<Method>> entry : this.initBinderAdviceCache.entrySet()) {
            if (entry.getKey().isApplicableToBeanType(handlerType)) {
                Object bean = entry.getKey().resolveBean();
                for (Method method : entry.getValue()) {
                    initBinderMethods.add(createInitBinderMethod(bean, method));
                }
            }
        }
        for (Method method : methods) {
            Object bean = handlerMethod.getBean();
            initBinderMethods.add(createInitBinderMethod(bean, method));
        }
        return createDataBinderFactory(initBinderMethods);
    }
    
    private InvocableHandlerMethod createInitBinderMethod(Object bean, Method method) {
        InvocableHandlerMethod binderMethod = new InvocableHandlerMethod(bean, method);
        binderMethod.setHandlerMethodArgumentResolvers(this.initBinderArgumentResolvers);
        binderMethod.setDataBinderFactory(new DefaultDataBinderFactory(this.webBindingInitializer));
        binderMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
        return binderMethod;
    }
    
    protected InitBinderDataBinderFactory createDataBinderFactory(List<InvocableHandlerMethod> binderMethods)
            throws Exception {
        return new ServletRequestDataBinderFactory(binderMethods, getWebBindingInitializer());
    }
    
    • 首先获得定义HandlerMethod的bean(对@RequestMapping来说即是某一Controller)的类型,然后找出其中@InitBinder注解修饰的方法,这里使用了initBinderCache加速以后同类型的查找过程;
    • 然后检查每个@ControllerAdvice注解修饰的bean是否能增强该bean,若能则将@ControllerAdvice注解修饰的bean的每个@InitBinder注解修饰的方法加入InitBinder方法集;
    • 将该bean中@InitBinder注解修饰的方法也加入InitBinder方法集;
    • 利用InitBinder方法集创建WebDataBinderFactory对象供后续参数解析时使用,这就是能在Controller中使用@InitBinder注解自定义数据绑定的原理。
    2. @ModelAttribute增强

    getModelFactory与getDataBinderFactory相似,增强@ModelAttribute注解修饰的方法。

    3. 创建新的处理方法

    createInvocableHandlerMethod将传入的HandlerMethod对象包装成一个ServletInvocableHandlerMethod对象作为新的处理方法,并为其添加HandlerAdapter已安装的参数解析器和返回值处理器。

    4. 解析参数并调用方法

    调用ServletInvocableHandlerMethod类的invokeAndHandle方法解析参数,其代码如下,providedArgs表示调用者提供的能直接使用的参数值,在本文的场景中均没有能直接使用的参数值。

    public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
        Object... providedArgs) throws Exception {
        Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
        setResponseStatus(webRequest);
        if (returnValue == null) {
            if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
                mavContainer.setRequestHandled(true);
                return;
            }
        }
        else if (StringUtils.hasText(getResponseStatusReason())) {
            mavContainer.setRequestHandled(true);
            return;
        }
        mavContainer.setRequestHandled(false);
        try {
            this.returnValueHandlers.handleReturnValue(
                returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
        }
        catch (Exception ex) {
            if (logger.isTraceEnabled()) {
                logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);
            }
            throw ex;
        }
    }
    

    invokeForRequest方法在ServletInvocableHandlerMethod的父类InvocableHandlerMethod中定义:

    public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,
            Object... providedArgs) throws Exception {
        Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
        if (logger.isTraceEnabled()) {
            logger.trace("Invoking '" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
                    "' with arguments " + Arrays.toString(args));
        }
        Object returnValue = doInvoke(args);
        if (logger.isTraceEnabled()) {
            logger.trace("Method [" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
                    "] returned [" + returnValue + "]");
        }
        return returnValue;
    }
    

    该方法主要做了两件事:

    1. getMethodArgumentValues解析被包装Java方法的参数并返回解析后的参数。
      private Object[] getMethodArgumentValues(NativeWebRequest request, ModelAndViewContainer mavContainer,
              Object... providedArgs) throws Exception {
          MethodParameter[] parameters = getMethodParameters();
          Object[] args = new Object[parameters.length];
          for (int i = 0; i < parameters.length; i++) {
              MethodParameter parameter = parameters[i];
              parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
              args[i] = resolveProvidedArgument(parameter, providedArgs);
              if (args[i] != null) {
                  continue;
              }
              if (this.argumentResolvers.supportsParameter(parameter)) {
                  try {
                      args[i] = this.argumentResolvers.resolveArgument(
                              parameter, mavContainer, request, this.dataBinderFactory);
                      continue;
                  }
                  catch (Exception ex) {
                      if (logger.isDebugEnabled()) {
                          logger.debug(getArgumentResolutionErrorMessage("Failed to resolve", i), ex);
                      }
                      throw ex;
                  }
              }
              if (args[i] == null) {
                  throw new IllegalStateException("Could not resolve method parameter at index " +
                          parameter.getParameterIndex() + " in " + parameter.getExecutable().toGenericString() +
                          ": " + getArgumentResolutionErrorMessage("No suitable resolver for", i));
              }
          }
          return args;
      }
      
      • getMethodParameters方法返回被包装Java方法的所有形参;
      • 对每个形参,尝试在直接提供的参数值(providedArgs)中按类型去匹配,若没有匹配则检查安装的所有参数解析器是否支持该形参,安装的所有参数解析器包括了向Spring注册的自定义参数解析器;
      • 若支持该形参则用匹配的参数解析器从请求中解析参数值。若Controller使用了@InitBinder注解修饰方法做类型转换,那么上文创建的WebDataBinderFactory对象即在这里成为resolveArgument方法的第四个参数;
      • 若解析参数失败或不能解析某一形参则报错。
    2. getMethodArgumentValues返回的args数组已经与真正要调用的Controller方法的参数相匹配,doInvoke使用Java反射的invoke去调用Controller方法。
      protected Object doInvoke(Object... args) throws Exception {
          ReflectionUtils.makeAccessible(getBridgedMethod());
          try {
              return getBridgedMethod().invoke(getBean(), args);
          }
          catch (IllegalArgumentException ex) {
              // 省略一些代码
          }
          catch (InvocationTargetException ex) {
              // 省略一些代码
          }
      }
      
    5. 处理返回值

    参数解析后,Controller方法被调用,最后处理返回值。在ServletInvocableHandlerMethod类的invokeAndHandle方法中,有一行代码如下:

    this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
    

    该行代码会遍历给ServletInvocableHandlerMethod添加的返回值处理器去处理返回值,委托给HandlerMethodReturnValueHandlerComposite:

    @Override
    public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
            ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
    
        HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
        if (handler == null) {
            throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
        }
        handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
    }
    
    @Nullable
    private HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameter returnType) {
        boolean isAsyncValue = isAsyncReturnValue(value, returnType);
        for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
            if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) {
                continue;
            }
            if (handler.supportsReturnType(returnType)) {
                return handler;
            }
        }
        return null;
    }
    

    从上述代码可以看到自定义HandlerMethodReturnValueHandler实现Controller方法自定义返回值处理器是如何实现的,这里就是RequestMappingHandlerAdapter初始化自定义返回值处理器发挥作用的地方。

    • @RequestBody和@ResponseBody

    @RequestBody是如何将JSON绑定到参数,@ResponseBody又是如何将对象转换成JSON的呢?这是由RequestResponseBodyMethodProcessor完成的,它同时实现了HandlerMethodArgumentResolver接口和HandlerMethodReturnValueHandler接口:

    RequestResponseBodyMethodProcessor.png

    在具体处理时resolveArgument方法和handleReturnValue方法都使用了适当的HttpMessageConverter,RequestMappingHandlerAdapter构造函数中添加了一些内置的HttpMessageConverter,更多HttpMessageConverter请参看Spring Boot的自动配置,如果还不满足需要则可以自定义实现注册到Spring中。

    @Configuration
    public class WebMvcConfigurer extends WebMvcConfigurerAdapter {
    
        @Override
        public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        }
    
        @Override
        public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        }
    }
    

    Spring 4.1增加了ResponseBodyAdvice接口,允许自定义带有@ResponseBody注解的Controller方法的返回值,可参阅官方文档

    6. 生成ModelAndView

    getModelAndView生成ModelAndView并返回,暂时略。

    参考文献

    SpringMVC源码剖析(五)-消息转换器HttpMessageConverter

    相关文章

      网友评论

          本文标题:Spring MVC请求处理(四) - HandlerAdapt

          本文链接:https://www.haomeiwen.com/subject/vxtsvqtx.html