Spring MVC请求处理(四) - HandlerAdapter

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,376评论 6 491
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,126评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,966评论 0 347
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,432评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,519评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,792评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,933评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,701评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,143评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,488评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,626评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,292评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,896评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,742评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,977评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,324评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,494评论 2 348

推荐阅读更多精彩内容