• handlerAdapter与方法调用(参数的解析)


    前提:当找到handler以后,那么就要让handler发挥作用,这个时候handlerAdapter就派上用场了
    
    
    这里面比较复杂就是requestMappingHandlerAdapter了,其他的由于handler比较固定,基本上之前调用他们实现的接口的方法。
    
    @Override
        public final boolean supports(Object handler) {
            return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
        }
    supportsInternal方法子类实现,用于扩展,但在requestMappingHandlerAdapter子类中并没有做什么,直接返回true。
    
    @Override
        public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
                throws Exception {
    
            return handleInternal(request, response, (HandlerMethod) handler);
        }
    
    handleInternal方法也有子类实现。在调用handler之前,会做一些数据绑定,比如会查找@ControllerAdvice注解,查找@InitBinder,@ModuleAttribute,查找实现了RequestBodyAdvice的类等等。
    初始化一些参数解析器,校验器
    
    RequestMappingHandlerAdapter实现了InitializingBean接口,所以在初始化这个adapter并且设置了相应的属性之后就会调用afterPropertiesSet方法
    @Override
        public void afterPropertiesSet() {
            // Do this first, it may add ResponseBody advice beans
    //初始化@ControllerAdvice标注的类
            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);
            }
        }
    
    
    
    private void initControllerAdviceCache() {
            if (getApplicationContext() == null) {
                return;
            }
            if (logger.isInfoEnabled()) {
                logger.info("Looking for @ControllerAdvice: " + getApplicationContext());
            }
    //在applicationContext容器中找到被@controllerAdvice标注的bean,并排序
            List<ControllerAdviceBean> beans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
            AnnotationAwareOrderComparator.sort(beans);
    //创建实现了@responseBodyAdvice的bean
            List<Object> requestResponseBodyAdviceBeans = new ArrayList<Object>();
    
            for (ControllerAdviceBean bean : beans) {
    //查找被@ModelAttribute注解标注的方法
                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);
                    }
                }
    //查找被@InitBinder注解标注的方法
                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);
                    }
                }
    //查找父类是RequestBodyAdvice的bean
                if (RequestBodyAdvice.class.isAssignableFrom(bean.getBeanType())) {
                    requestResponseBodyAdviceBeans.add(bean);
                    if (logger.isInfoEnabled()) {
                        logger.info("Detected RequestBodyAdvice bean in " + bean);
                    }
                }
    //查找父类是ResponseBodyAdvice的bean
                if (ResponseBodyAdvice.class.isAssignableFrom(bean.getBeanType())) {
                    requestResponseBodyAdviceBeans.add(bean);
                    if (logger.isInfoEnabled()) {
                        logger.info("Detected ResponseBodyAdvice bean in " + bean);
                    }
                }
            }
    if (!requestResponseBodyAdviceBeans.isEmpty()) {
    //将使用@ControllerAdvice注解找的bean放到最前面
                this.requestResponseBodyAdvice.addAll(0, requestResponseBodyAdviceBeans);
            }
    
    方法返回后
    接下来就开始初始化解析器了
    if (this.argumentResolvers == null) {
                List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
                this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
            }
    
    
    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()));
    
            // 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;
        }
    
    准备就绪之后,开始调用handleInternal方法
    
    @Override
        protected ModelAndView handleInternal(HttpServletRequest request,
                HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    
            ModelAndView mav;
    //检查是否支持当前请求的方法,检查session是否为必须的
            checkRequest(request);
    
            // Execute invokeHandlerMethod in synchronized block if required.
    //执行session同步
            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;
        }
    
    
    
    protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
                HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
    
            ServletWebRequest webRequest = new ServletWebRequest(request, response);
    //创建data绑定工厂,数据绑定是用来与String进行参数转换的
            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);
        }
    
    
    
    
    private WebDataBinderFactory getDataBinderFactory(HandlerMethod handlerMethod) throws Exception {
            Class<?> handlerType = handlerMethod.getBeanType();
    //从缓存中查找是否已经存在这个类型对应的@InitBinder方法
            Set<Method> methods = this.initBinderCache.get(handlerType);
            if (methods == null) {
    //如果为空,就对当前handler进行遍历查找@InitBinder的方法
                methods = MethodIntrospector.selectMethods(handlerType, INIT_BINDER_METHODS);
    //保存到缓存中
                this.initBinderCache.put(handlerType, methods);
            }
            List<InvocableHandlerMethod> initBinderMethods = new ArrayList<InvocableHandlerMethod>();
            // Global methods first遍历全局(也就是@ControllerAdvice标注的类的@InitBinder方法,这个在adapter的afterPropertiesSet方法中初始化的)
            for (Entry<ControllerAdviceBean, Set<Method>> entry : this.initBinderAdviceCache.entrySet()) {
                if (entry.getKey().isApplicableToBeanType(handlerType)) {
                    Object bean = entry.getKey().resolveBean();
                    for (Method method : entry.getValue()) {
    //创建InvocableHandlerMethod对象并添加
                        initBinderMethods.add(createInitBinderMethod(bean, method));
                    }
                }
            }
    //添加完全局的之后,再添加当前处理器的
            for (Method method : methods) {
                Object bean = handlerMethod.getBean();
                initBinderMethods.add(createInitBinderMethod(bean, method));
            }
            return createDataBinderFactory(initBinderMethods);
        }
    
    
    public boolean isApplicableToBeanType(Class<?> beanType) {
    //如果@controllerAdvice什么属性都没有写,说明将所有配置的方法应用到所有的handler中
            if (!hasSelectors()) {
                return true;
            }
            else if (beanType != null) {
                for (String basePackage : this.basePackages) {
                    if (beanType.getName().startsWith(basePackage)) {
                        return true;
                    }
                }
                for (Class<?> clazz : this.assignableTypes) {
                    if (ClassUtils.isAssignable(clazz, beanType)) {
                        return true;
                    }
                }
                for (Class<? extends Annotation> annotationClass : this.annotations) {
                    if (AnnotationUtils.findAnnotation(beanType, annotationClass) != null) {
                        return true;
                    }
                }
            }
            return false;
        }
    
    private InvocableHandlerMethod createInitBinderMethod(Object bean, Method method) {
    //InvocableHandlerMethod 是handlerMethod的子类
            InvocableHandlerMethod binderMethod = new InvocableHandlerMethod(bean, method);
            binderMethod.setHandlerMethodArgumentResolvers(this.initBinderArgumentResolvers);
            binderMethod.setDataBinderFactory(new DefaultDataBinderFactory(this.webBindingInitializer));
            binderMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
            return binderMethod;
        }
    
    最后返回一个createDataBinderFactory(initBinderMethods);
    
    回到invokeHandlerMethod方法,创建了DataBinderFactory后,接下来就是创建ModelFactory了
    
    private ModelFactory getModelFactory(HandlerMethod handlerMethod, WebDataBinderFactory binderFactory) {
    //获取SessionAttributesHandler,这个处理器用来处理@SessionAttributes注解的方法
            SessionAttributesHandler sessionAttrHandler = getSessionAttributesHandler(handlerMethod);
            Class<?> handlerType = handlerMethod.getBeanType();
    //获取标注了@ModelAttribute的方法
            Set<Method> methods = this.modelAttributeCache.get(handlerType);
            if (methods == null) {
    //如果缓存中没有就重新查找当前标注了@ModelAttribute的方法,并存到缓存中
                methods = MethodIntrospector.selectMethods(handlerType, MODEL_ATTRIBUTE_METHODS);
                this.modelAttributeCache.put(handlerType, methods);
            }
            List<InvocableHandlerMethod> attrMethods = new ArrayList<InvocableHandlerMethod>();
            // Global methods first添加全局的@ModelAttribute注解的方法
            for (Entry<ControllerAdviceBean, Set<Method>> entry : this.modelAttributeAdviceCache.entrySet()) {
                if (entry.getKey().isApplicableToBeanType(handlerType)) {
                    Object bean = entry.getKey().resolveBean();
                    for (Method method : entry.getValue()) {
                        attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
                    }
                }
            }
            for (Method method : methods) {
                Object bean = handlerMethod.getBean();
                attrMethods.add(createModelAttributeMethod(binderFactory, bean, method));
            }
    //创建ModelFactory工厂
            return new ModelFactory(attrMethods, binderFactory, sessionAttrHandler);
        }
    
    //第一个参数传入的是标记了@ModelAttribute的方法,第二个参数数据绑定,第三个是@SessionAttributes注解对应的处理器
    public ModelFactory(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;
        }
    
    private ModelMethod(InvocableHandlerMethod handlerMethod) {
                this.handlerMethod = handlerMethod;
                for (MethodParameter parameter : handlerMethod.getMethodParameters()) {
                    if (parameter.hasParameterAnnotation(ModelAttribute.class)) {
                        this.dependencies.add(getNameForParameter(parameter));
                    }
                }
            }
    
    
    当缓存什么的都弄好了之后就开始处理当前handleMethod了
    ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
            invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
            invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
            invocableMethod.setDataBinderFactory(binderFactory);
            invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
    
    ModelAndViewContainer mavContainer = new ModelAndViewContainer();
    //将FlashMap中的属性添加到mav容器中
            mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
            modelFactory.initModel(webRequest, mavContainer, invocableMethod);
            mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
    
    
    public void initModel(NativeWebRequest request, ModelAndViewContainer container,
                HandlerMethod handlerMethod) throws Exception {
    //从sessionAttribute中回复参数到mavContainer中
            Map<String, ?> sessionAttributes = this.sessionAttributesHandler.retrieveAttributes(request);
    //合并参数,因为sessionAttribute中的参数可能会与flashmap中的参数冲突,但不会覆盖原来的参数
            container.mergeAttributes(sessionAttributes);
    //调用modelAttribute注解的方法
            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 + "'");
                    }
                    container.addAttribute(name, value);
                }
            }
        }
    
    invokeModelAttributeMethods(request, container);
    
    private void invokeModelAttributeMethods(NativeWebRequest request, ModelAndViewContainer container)
                throws Exception {
    
            while (!this.modelMethods.isEmpty()) {
    //获取第一个modelMethod方法,并将其移除,等下次调用的时候就就是第二个modelMethod,如果参数有@ModelAttribute,则优先处理
                InvocableHandlerMethod modelMethod = getNextModelMethod(container).getHandlerMethod();
    //获取模型值,即属性key值
                String modelName = modelMethod.getMethodAnnotation(ModelAttribute.class).value();
    //如果已经存在了就不再调用
                if (container.containsAttribute(modelName)) {
                    continue;
                }
    //调用方法
                Object returnValue = modelMethod.invokeForRequest(request, container);
                if (!modelMethod.isVoid()){
                    String returnValueName = getNameForReturnValue(returnValue, modelMethod.getReturnType());
                    if (!container.containsAttribute(returnValueName)) {
                        container.addAttribute(returnValueName, returnValue);
                    }
                }
            }
        }
    
    
    private ModelMethod getNextModelMethod(ModelAndViewContainer container) {
    //遍历所有的modelmethod,如果他们的依赖存在,就优先使用这个方法参数与中有@ModelAttribute注解的modelmethod方法,否则就直接返回第一个modelmethod
            for (ModelMethod modelMethod : this.modelMethods) {
                if (modelMethod.checkDependencies(container)) {
                    if (logger.isTraceEnabled()) {
                        logger.trace("Selected @ModelAttribute method " + modelMethod);
                    }
                    this.modelMethods.remove(modelMethod);
                    return modelMethod;
                }
            }
    //获取第一个modelmethod,并将它已移除
            ModelMethod modelMethod = this.modelMethods.get(0);
            if (logger.isTraceEnabled()) {
                logger.trace("Selected @ModelAttribute method (not present: " +
                        modelMethod.getUnresolvedDependencies(container)+ ") " + modelMethod);
            }
            this.modelMethods.remove(modelMethod);
            return modelMethod;
        }
    
    
    //
    public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,
                Object... providedArgs) throws Exception {
    //获取方法参数值
            Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
            if (logger.isTraceEnabled()) {
                StringBuilder sb = new StringBuilder("Invoking [");
                sb.append(getBeanType().getSimpleName()).append(".");
                sb.append(getMethod().getName()).append("] method with arguments ");
                sb.append(Arrays.asList(args));
                logger.trace(sb.toString());
            }
            Object returnValue = doInvoke(args);
            if (logger.isTraceEnabled()) {
                logger.trace("Method [" + getMethod().getName() + "] returned [" + returnValue + "]");
            }
            return returnValue;
        }
    
    
    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);
    //给当前参数封装对象设置参数类型
                GenericTypeResolver.resolveParameterType(parameter, getBean().getClass());
    //尝试从给定的providedArgs参数查找对应类型的参数,如果找到就设置这个值到args数组中,这个providedArgs在这里是没有传递任何值的
                args[i] = resolveProvidedArgument(parameter, providedArgs);
    //如果不为空就continue,表示已经有值了
                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("Error resolving argument", i), ex);
                        }
                        throw ex;
                    }
                }
                if (args[i] == null) {
                    String msg = getArgumentResolutionErrorMessage("No suitable resolver for argument", i);
                    throw new IllegalStateException(msg);
                }
            }
            return args;
        }
    
    (this.argumentResolvers.supportsParameter(parameter)
    private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
    //先从缓存中找,如果没有找到,在遍历所有的解析器,这个解析器集合保存在一个解析器Composite类中,SpringMVC中这样的类一般是使用的责任链模式
            HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
            if (result == null) {
                for (HandlerMethodArgumentResolver methodArgumentResolver : this.argumentResolvers) {
                    if (logger.isTraceEnabled()) {
                        logger.trace("Testing if argument resolver [" + methodArgumentResolver + "] supports [" +
                                parameter.getGenericParameterType() + "]");
                    }
                    if (methodArgumentResolver.supportsParameter(parameter)) {
                        result = methodArgumentResolver;
                        this.argumentResolverCache.put(parameter, result);
                        break;
                    }
                }
            }
            return result;
        }
    
    
     this.argumentResolvers.resolveArgument(
                                parameter, mavContainer, request, this.dataBinderFactory);方法体如下
    
    @Override
        public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
                NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
    //获取参数解析器,如果没有获取到就抛出错误
            HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
            if (resolver == null) {
                throw new IllegalArgumentException("Unknown parameter type [" + parameter.getParameterType().getName() + "]");
            }
            return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
        }
    
    HandlerMethodArgumentResolver的实现类有很多,这里选几个分析一下
    
    
    首先先分析一下RequestResponseBodyMethodProcessor,这是一个集argumentResolve和handlerReturnValue于一身的类
    
    直接看解析方法resolveArgument:
    
    @Override
        public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
                NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
    //使用转化器进行参数的转换
            Object arg = readWithMessageConverters(webRequest, parameter, parameter.getGenericParameterType());
            String name = Conventions.getVariableNameForParameter(parameter);
    
            WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
            if (arg != null) {
                validateIfApplicable(binder, parameter);
                if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
                    throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
                }
            }
            mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
    
            return arg;
        }
    
    
    
    protected <T> Object readWithMessageConverters(NativeWebRequest webRequest, MethodParameter methodParam,
                Type paramType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {
    
            HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
            ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(servletRequest);
    
            Object arg = readWithMessageConverters(inputMessage, methodParam, paramType);
            if (arg == null) {
                if (methodParam.getParameterAnnotation(RequestBody.class).required()) {
                    throw new HttpMessageNotReadableException("Required request body is missing: " +
                            methodParam.getMethod().toGenericString());
                }
            }
            return arg;
        }
    
    
    readWithMessageConverters方法
    protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter param,
                Type targetType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {
    
            MediaType contentType;
            boolean noContentType = false;
            try {
    //获取请求的ContentType
                contentType = inputMessage.getHeaders().getContentType();
            }
            catch (InvalidMediaTypeException ex) {
                throw new HttpMediaTypeNotSupportedException(ex.getMessage());
            }
            if (contentType == null) {
                noContentType = true;
    //设置默认的contentType
                contentType = MediaType.APPLICATION_OCTET_STREAM;
            }
    //获取类的类型
            Class<?> contextClass = (param != null ? param.getContainingClass() : null);
    //获取的参数的泛型类型
            Class<T> targetClass = (targetType instanceof Class<?> ? (Class<T>) targetType : null);
    //如果没有就再次尝试设置一遍
            if (targetClass == null) {
                ResolvableType resolvableType = (param != null ?
                        ResolvableType.forMethodParameter(param) : ResolvableType.forType(targetType));
                targetClass = (Class<T>) resolvableType.resolve();
            }
    //获取请求方法
            HttpMethod httpMethod = ((HttpRequest) inputMessage).getMethod();
            Object body = NO_VALUE;
    
            try {
                inputMessage = new EmptyBodyCheckingHttpInputMessage(inputMessage);
    //遍历这个解析器中的所有的converter,判断是否是泛化的转换器
                for (HttpMessageConverter<?> converter : this.messageConverters) {
                    Class<HttpMessageConverter<?>> converterType = (Class<HttpMessageConverter<?>>) converter.getClass();
                    if (converter instanceof GenericHttpMessageConverter) {
                        GenericHttpMessageConverter<?> genericConverter = (GenericHttpMessageConverter<?>) converter;
    //判断是否能够进行解析
                        if (genericConverter.canRead(targetType, contextClass, contentType)) {
                            if (logger.isDebugEnabled()) {
                                logger.debug("Read [" + targetType + "] as "" + contentType + "" with [" + converter + "]");
                            }
                            if (inputMessage.getBody() != null) {
    //如果请求体有值,那么就尝试调用实现了RequestAdvice的类,对请求体进行预先处理
                                inputMessage = getAdvice().beforeBodyRead(inputMessage, param, targetType, converterType);
    //使用converter进行转化
                                body = genericConverter.read(targetType, contextClass, inputMessage);
    //对处理完的body进行后置处理,就是使用实现了ResponseAdvice的类进行处理
                                body = getAdvice().afterBodyRead(body, inputMessage, param, targetType, converterType);
                            }
                            else {
                                body = null;
    //处理空请求体
                                body = getAdvice().handleEmptyBody(body, inputMessage, param, targetType, converterType);
                            }
                            break;
                        }
                    }
    //如果不是泛化的转换器,那么就判断目标class是否为空。
                    else if (targetClass != null) {
                        if (converter.canRead(targetClass, contentType)) {
                            if (logger.isDebugEnabled()) {
                                logger.debug("Read [" + targetType + "] as "" + contentType + "" with [" + converter + "]");
                            }
                            if (inputMessage.getBody() != null) {
                                inputMessage = getAdvice().beforeBodyRead(inputMessage, param, targetType, converterType);
                                body = ((HttpMessageConverter<T>) converter).read(targetClass, inputMessage);
                                body = getAdvice().afterBodyRead(body, inputMessage, param, targetType, converterType);
                            }
                            else {
                                body = null;
                                body = getAdvice().handleEmptyBody(body, inputMessage, param, targetType, converterType);
                            }
                            break;
                        }
                    }
                }
            }
            catch (IOException ex) {
                throw new HttpMessageNotReadableException("Could not read document: " + ex.getMessage(), ex);
            }
    //如果body没有被处理过
            if (body == NO_VALUE) {
                if (httpMethod == null || !SUPPORTED_METHODS.contains(httpMethod) ||
                        (noContentType && inputMessage.getBody() == null)) {
                    return null;
                }
                throw new HttpMediaTypeNotSupportedException(contentType, this.allSupportedMediaTypes);
        }
    
    canRead,判断是否可以处理这个请求类型的数据,对于json来说text/html肯定是不能进行处理的
    protected boolean canRead(MediaType mediaType) {
            if (mediaType == null) {
                return true;
            }
            for (MediaType supportedMediaType : getSupportedMediaTypes()) {
                if (supportedMediaType.includes(mediaType)) {
                    return true;
                }
            }
            return false;
        }
    
    
    解析好后继续
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
                NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
    
            Object arg = readWithMessageConverters(webRequest, parameter, parameter.getGenericParameterType());
    //如果指定的参数名为URL,连续两个大写字母的那么就保持它原来的样子,其他的就把第一个字母变成小写,如果是集合类的那么将泛型类型加上list字符串
            String name = Conventions.getVariableNameForParameter(parameter);
    //创建数据绑定器
            WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
            if (arg != null) {
    //对参数进行校验
                validateIfApplicable(binder, parameter);
    //查看是否发生了异常
                if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
    //抛出参数校验不通过的异常
                    throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
                }
            }
    //保存绑定数据后的结果信息
            mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
    
            return arg;
        }
    
    
    
    public static String getVariableNameForParameter(MethodParameter parameter) {
            Assert.notNull(parameter, "MethodParameter must not be null");
            Class<?> valueClass;
            boolean pluralize = false;
    
            if (parameter.getParameterType().isArray()) {
    //获取数组的元素类型
                valueClass = parameter.getParameterType().getComponentType();
                pluralize = true;
            }
            else if (Collection.class.isAssignableFrom(parameter.getParameterType())) {
    //获取集合的泛型参数类型
                valueClass = GenericCollectionTypeResolver.getCollectionParameterType(parameter);
                if (valueClass == null) {
                    throw new IllegalArgumentException(
                            "Cannot generate variable name for non-typed Collection parameter type");
                }
    //设置为TRUE
                pluralize = true;
            }
            else {
                valueClass = parameter.getParameterType();
            }
    //获取名字,出去包名
            String name = ClassUtils.getShortNameAsProperty(valueClass);
    //如果pluralize为true,那么就在名字候命加上list字符串
            return (pluralize ? pluralize(name) : name);
        }
    
    
    @Override
        public final WebDataBinder createBinder(NativeWebRequest webRequest, Object target, String objectName)
                throws Exception {
    //创建webdata 绑定
            WebDataBinder dataBinder = createBinderInstance(target, objectName, webRequest);
            if (this.initializer != null) {
                this.initializer.initBinder(dataBinder, webRequest);
            }
    //开始调用绑定方法
            initBinder(dataBinder, webRequest);
            return dataBinder;
        }
    initBinder方法
    
    public void initBinder(WebDataBinder binder, NativeWebRequest request) throws Exception {
            for (InvocableHandlerMethod binderMethod : this.binderMethods) {
                if (isBinderMethodApplicable(binderMethod, binder)) {
    //跟前面调用方法是一样的,不过这次传入了一个提供的参数,那就是webDataBinder的实例,所以我们可以在@initBinder方法中添加一些校验器,编辑器等等操作。
                    Object returnValue = binderMethod.invokeForRequest(request, null, binder);
                    if (returnValue != null) {
                        throw new IllegalStateException("@InitBinder methods should return void: " + binderMethod);
                    }
                }
            }
        }
    
    
    创建了webDataBinder之后,并且如果我们在@initBinder注解的方法中做了一些事情,比如添加了校验器啥的,接下来的代码如下
    if (arg != null) {
                validateIfApplicable(binder, parameter);
                if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
                    throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
                }
            }
            mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
    
    //校验
    protected void validateIfApplicable(WebDataBinder binder, MethodParameter methodParam) {
            Annotation[] annotations = methodParam.getParameterAnnotations();
            for (Annotation ann : annotations) {
    //只有注释了@valid的参数才会进行校验
                Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class);
                if (validatedAnn != null || ann.annotationType().getSimpleName().startsWith("Valid")) {
    //获取注解中value值,这些值可以最为校验分组用,SpringMVC的校验使用的JSR303校验和自定义校验器
                    Object hints = (validatedAnn != null ? validatedAnn.value() : AnnotationUtils.getValue(ann));
                    Object[] validationHints = (hints instanceof Object[] ? (Object[]) hints : new Object[] {hints});
    //开始校验
                    binder.validate(validationHints);
                    break;
                }
            }
        }
    
    
    //遍历校验器进行校验
    public void validate(Object... validationHints) {
            for (Validator validator : getValidators()) {
    //使用JSR303的方式校验
                if (!ObjectUtils.isEmpty(validationHints) && validator instanceof SmartValidator) {
                    ((SmartValidator) validator).validate(getTarget(), getBindingResult(), validationHints);
                }
                else if (validator != null) {
    //使用自定义校验器校验
                    validator.validate(getTarget(), getBindingResult());
                }
            }
        }
    
    
    好了,对于RequestBody注解的参数就是这么解析的。
    
    来研究一下ModelAttributeMethodProcessor是怎么解析的
    
    @Override
        public boolean supportsParameter(MethodParameter parameter) {
    //判断参数是否有@ModelAttribute注解
            if (parameter.hasParameterAnnotation(ModelAttribute.class)) {
                return true;
            }
            else if (this.annotationNotRequired) {
                return !BeanUtils.isSimpleProperty(parameter.getParameterType());
            }
            else {
                return false;
            }
        }
    
    //解析参数
    public final Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
                NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
    //获取参数名,先从注解的指定的名称找,如果没有就用Conventions.getVariableNameForParameter(parameter)方法获取参数名,这个在前面就已经使用过了
            String name = ModelFactory.getNameForParameter(parameter);
    //判断这个参数是否在MavContainer中已经存在了,如果存在就直接获取这个参数值,如果没有找到就去request中寻找参数
            Object attribute = (mavContainer.containsAttribute(name) ?
                    mavContainer.getModel().get(name) : createAttribute(name, parameter, binderFactory, webRequest));
    //创建WebDataBinder ,调用@initBinder注解的绑定方法
            WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);
            if (binder.getTarget() != null) {
    //这里是绑定请求的参数
                bindRequestParameters(binder, webRequest);
                validateIfApplicable(binder, parameter);
                if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
                    throw new BindException(binder.getBindingResult());
                }
            }
    
            // Add resolved attribute and BindingResult at the end of the model
            Map<String, Object> bindingResultModel = binder.getBindingResult().getModel();
            mavContainer.removeAttributes(bindingResultModel);
            mavContainer.addAllAttributes(bindingResultModel);
    
            return binder.convertIfNecessary(binder.getTarget(), parameter.getParameterType(), parameter);
        }
    
    
    protected void bindRequestParameters(WebDataBinder binder, NativeWebRequest request) {
            ServletRequest servletRequest = request.getNativeRequest(ServletRequest.class);
            ServletRequestDataBinder servletBinder = (ServletRequestDataBinder) binder;
            servletBinder.bind(servletRequest);
        }
    
    
    public void bind(ServletRequest request) {
    //解析创建成一个MutablePropertyValues
            MutablePropertyValues mpvs = new ServletRequestParameterPropertyValues(request);
    //判断是否为MultipartRequest 类型,如果是就获取这种类型的请求
            MultipartRequest multipartRequest = WebUtils.getNativeRequest(request, MultipartRequest.class);
            if (multipartRequest != null) {
                bindMultipart(multipartRequest.getMultiFileMap(), mpvs);
            }
    //获取url中的变量Map用url定义的参数值,如果已经在mpvs存在的参数将不会覆盖
            addBindValues(mpvs, request);
    //绑定参数
            doBind(mpvs);
        }
    
    
    //创建MutablePropertyValues时的解析,解析成一个去掉指定前缀的Map,当然这里没有设置前缀
    public static Map<String, Object> getParametersStartingWith(ServletRequest request, String prefix) {
            Assert.notNull(request, "Request must not be null");
            Enumeration<String> paramNames = request.getParameterNames();
            Map<String, Object> params = new TreeMap<String, Object>();
            if (prefix == null) {
                prefix = "";
            }
            while (paramNames != null && paramNames.hasMoreElements()) {
                String paramName = paramNames.nextElement();
                if ("".equals(prefix) || paramName.startsWith(prefix)) {
                    String unprefixed = paramName.substring(prefix.length());
                    String[] values = request.getParameterValues(paramName);
                    if (values == null || values.length == 0) {
                        // Do nothing, no values found at all.
                    }
                    else if (values.length > 1) {
                        params.put(unprefixed, values);
                    }
                    else {
                        params.put(unprefixed, values[0]);
                    }
                }
            }
            return params;
        }
    
    然后在传入这个paramMap到构造器
    public MutablePropertyValues(Map<?, ?> original) {
            // We can optimize this because it's all new:
            // There is no replacement of existing property values.
            if (original != null) {
                this.propertyValueList = new ArrayList<PropertyValue>(original.size());
                for (Map.Entry<?, ?> entry : original.entrySet()) {
    //propertyValueList是一个list,存储着PropertyValue对象,这个对象存着请求参数的名称和对应的值。
                    this.propertyValueList.add(new PropertyValue(entry.getKey().toString(), entry.getValue()));
                }
            }
            else {
                this.propertyValueList = new ArrayList<PropertyValue>(0);
            }
        }
    
    
    protected void bindMultipart(Map<String, List<MultipartFile>> multipartFiles, MutablePropertyValues mpvs) {
            for (Map.Entry<String, List<MultipartFile>> entry : multipartFiles.entrySet()) {
                String key = entry.getKey();
                List<MultipartFile> values = entry.getValue();
                if (values.size() == 1) {
                    MultipartFile value = values.get(0);
    //默认情况下会保存空的MultipartFiles,所以即使你的上传文件框没有上传文件,也会存在空的文件
                    if (isBindEmptyMultipartFiles() || !value.isEmpty()) {
                        mpvs.add(key, value);
                    }
                }
                else {
                    mpvs.add(key, values);
                }
            }
        }
    
    开始绑定参数
    @Override
        protected void doBind(MutablePropertyValues mpvs) {
    //检查有default值前缀的参数
            checkFieldDefaults(mpvs);
    //检查有标记前缀的参数
            checkFieldMarkers(mpvs);
    真正绑定参数的方法
            super.doBind(mpvs);
        }
    
    checkFieldDefaults方法:
    protected void checkFieldDefaults(MutablePropertyValues mpvs) {
    //如果字段默认的前缀不为空,那么就去掉前缀,然后判断这个属性在对应的参数对象中是否可写,并且在mpvs中不存在这个属性参会加入到mvps中,并且移除之前的
            if (getFieldDefaultPrefix() != null) {
                String fieldDefaultPrefix = getFieldDefaultPrefix();
                PropertyValue[] pvArray = mpvs.getPropertyValues();
                for (PropertyValue pv : pvArray) {
                    if (pv.getName().startsWith(fieldDefaultPrefix)) {
                        String field = pv.getName().substring(fieldDefaultPrefix.length());
                        if (getPropertyAccessor().isWritableProperty(field) && !mpvs.contains(field)) {
                            mpvs.add(field, pv.getValue());
                        }
                        mpvs.removePropertyValue(pv);
                    }
                }
            }
        }
    这个方法和上面的是一样的道理
    protected void checkFieldMarkers(MutablePropertyValues mpvs) {
            if (getFieldMarkerPrefix() != null) {
                String fieldMarkerPrefix = getFieldMarkerPrefix();
                PropertyValue[] pvArray = mpvs.getPropertyValues();
                for (PropertyValue pv : pvArray) {
                    if (pv.getName().startsWith(fieldMarkerPrefix)) {
                        String field = pv.getName().substring(fieldMarkerPrefix.length());
                        if (getPropertyAccessor().isWritableProperty(field) && !mpvs.contains(field)) {
                            Class<?> fieldType = getPropertyAccessor().getPropertyType(field);
                            mpvs.add(field, getEmptyValue(field, fieldType));
                        }
                        mpvs.removePropertyValue(pv);
                    }
                }
            }
        }
    
    接下来调用了
    
    protected void doBind(MutablePropertyValues mpvs) {
    //检查是否是运行的字段,这些字段都可以在@initBinder注解的方法中指定
            checkAllowedFields(mpvs);
    //判断是否为必须的字段
            checkRequiredFields(mpvs);
    //应用属性值
            applyPropertyValues(mpvs);
        }
    
    //应用指定的值到对应的对象中
    protected void applyPropertyValues(MutablePropertyValues mpvs) {
            try {
                // Bind request parameters onto target object.
    //绑定请求参数到目标参数中
                getPropertyAccessor().setPropertyValues(mpvs, isIgnoreUnknownFields(), isIgnoreInvalidFields());
            }
            catch (PropertyBatchUpdateException ex) {
                // Use bind error processor to create FieldErrors.
                for (PropertyAccessException pae : ex.getPropertyAccessExceptions()) {
                    getBindingErrorProcessor().processPropertyAccessException(pae, getInternalBindingResult());
                }
            }
        }
    
    接下来就是对参数进行类型转换
    
    return binder.convertIfNecessary(binder.getTarget(), parameter.getParameterType(), parameter);
    
    public <T> T convertIfNecessary(String propertyName, Object oldValue, Object newValue,
                Class<T> requiredType, TypeDescriptor typeDescriptor) throws IllegalArgumentException {
    
            // Custom editor for this type?获取@initBinder注解的方法中自定义的参数编辑器
            PropertyEditor editor = this.propertyEditorRegistry.findCustomEditor(requiredType, propertyName);
    
            ConversionFailedException conversionAttemptEx = null;
    
            // No custom editor but custom ConversionService specified?
            ConversionService conversionService = this.propertyEditorRegistry.getConversionService();
            if (editor == null && conversionService != null && newValue != null && typeDescriptor != null) {
                TypeDescriptor sourceTypeDesc = TypeDescriptor.forObject(newValue);
                if (conversionService.canConvert(sourceTypeDesc, typeDescriptor)) {
                    try {
    //如果可以转换就进行转换
                        return (T) conversionService.convert(newValue, sourceTypeDesc, typeDescriptor);
                    }
                    catch (ConversionFailedException ex) {
                        // fallback to default conversion logic below
                        conversionAttemptEx = ex;
                    }
                }
            }
    
            Object convertedValue = newValue;
    。。。。。。。。。。。。。。。。。。。。。。。(代码较长,省略)
    
    
    当所有的参数都解析完毕后,调用方法
    Object returnValue = doInvoke(args);
    //如果不出例外,就直接使用放射方法调用
    protected Object doInvoke(Object... args) throws Exception {
            ReflectionUtils.makeAccessible(getBridgedMethod());
            try {
                return getBridgedMethod().invoke(getBean(), args);
            }
            catch (IllegalArgumentException ex) {
                assertTargetBean(getBridgedMethod(), getBean(), args);
                String message = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument");
                throw new IllegalStateException(getInvocationErrorMessage(message, args), ex);
            }
            catch (InvocationTargetException ex) {
                // Unwrap for HandlerExceptionResolvers ...
                Throwable targetException = ex.getTargetException();
                if (targetException instanceof RuntimeException) {
                    throw (RuntimeException) targetException;
                }
                else if (targetException instanceof Error) {
                    throw (Error) targetException;
                }
                else if (targetException instanceof Exception) {
                    throw (Exception) targetException;
                }
                else {
                    String msg = getInvocationErrorMessage("Failed to invoke controller method", args);
                    throw new IllegalStateException(msg, targetException);
                }
            }
        }
  • 相关阅读:
    numpy的shuffle函数
    特征值、特征向量
    keras的Embedding层
    自己写着玩的一个天气APP
    使用mbed进行STM32板子的开发
    提高ListView的效率
    自定义ListView里面的Item的内容
    Android控件使用自定义字体
    使用Handler类来更新UI
    MongoDB在Java下的增删查改
  • 原文地址:https://www.cnblogs.com/honger/p/9516927.html
Copyright © 2020-2023  润新知