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

原文地址:https://www.cnblogs.com/honger/p/9516927.html

时间: 2024-10-11 23:38:11

handlerAdapter与方法调用(参数的解析)的相关文章

Atitit &#160;记录方法调用参数上下文arguments

Atitit  记录方法调用参数上下文arguments 1.1. java  java8  新的对象Parameter LocalVariableTable 本地变量表 MethodParameters 方法参数表1 1.2. Js arguments1 1.3. 1 1.4. C#1 2. Php的解决方案2 2.1. func_num_args() 返回传递给该函数参数的个数  2 2.2. func_get_arg(int $arg_num) 取得指定位置的参数值 2 2.3.  3.f

jQuery.ajax()方法中参数详细解析

前言 在项目开发中,为了实现异步向服务端发起请求,最经常使用的就是jQuery.ajax方法了.刚开始需求比较简单,调用jQuery.ajax方法时要传的参数也就那几个常见的参数:url/data/dataType/type/cache/timeout.当时感觉这个接口使用起来很简单,直到最近项目中要实现一个发送 formData数据到服务端的需求时,我发现自己错了....原来jQuery.ajax方法中除了我用过的那几个外,还有如此之多!!于是我决定要去jQuery官网好好看看都有哪些我不知道

关于Cocos2d-x中addchild和removeChild方法的参数的解析

一.addchild virtual void addchild( Node * child , int localZOrder , int tag )添加一个子节点到容器中,有Z轴顺序和一个标记. 1.如果子节点被添加到了一个“running(活动着的)”节点,那么'onEnter'和 'onEnterTransitionDidFinish' 将会立即调用. 2.参数解析 addChild:是指要添加的子成员(Node *类型,可移式Sprite, Layer等等): z:是指添加的ZOrde

SetACL 使用方法详细参数中文解析

示例: SetACL.exe c:\nihao /dir /deny everyone /read_ex 设置E:\wxDesktop 文件夹 everyone 用户为读取和运行权限 SetACL MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run /registry /deny administrator /read 设置注册表键值Run 为完全控制权限 ------------------------------------------

java类加载机制及方法调用

类加载机制 概述 类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载(Loading).验证(Verification).准备(Preparation).解析(Resolution).初始化(Initialization).使用(Using)和卸载(Unloading)7个阶段.其中验证.准备.解析3个部分统称为连接(Linking) 于初始化阶段,虚拟机规范则是严格规定了有且只有5种情况必须立即对类进行"初始化"(而加载.验证.准备自然需要在此之前开始): 1

JVM(十二):方法调用

JVM(十二):方法调用 在 JVM(七):JVM内存结构 中,我们说到了方法执行在何种内存结构上执行:Java 方法活动在虚拟机栈中的栈帧上,栈帧的具体结构在内存结构中已经详细讲解过了,下面就让我们来看一下 方法是如何调用的. 方法调用 首先,我们要明白一个基础性概念:方法调用并不是方法执行.其只是确定该调用哪一个方法而已(多态的影响,选择方法的不同版本).并且因为 Java 调用的动态性,有些方法需要在类加载阶段动态解析,这也为 JVM 解析符号引用成直接引用提供了难度. 解析 在 JVM(

多态方法调用的解析和分派

方法调用并不等同于方法执行,方法调用阶段唯一的任务就是确定被调用方法的版本(即调用哪一个方法),暂时还不涉及方法内部的具体运行过程.在程序运行时,进行方法调用是最普遍.最频繁的操作,Class文件的编译过程中不包含传统编译中的连接步骤,一切方法调用在Class文件里面存储的都只是符号引用,而不是方法在实际运行时内存布局中的入口地址(相当于之前说的直接引用).这个特性给Java带来了更强大的动态扩展能力,但也使得Java方法调用过程变得相对复杂起来,需要在类加载期间,甚至到运行期间才能确定目标方法

7、SpringMVC源码分析(2):分析HandlerAdapter.handle方法,了解handler方法的调用细节以及@ModelAttribute注解

从上一篇 SpringMVC源码分析(1) 中我们了解到在DispatcherServlet.doDispatch方法中会通过 mv = ha.handle(processedRequest, response, mappedHandler.getHandler()) 这样的方式来执行request的handler方法. 先来分析一下ha.handle方法的调用过程:HandlerAdapter接口有一个抽象实现类AbstractHandlerMethodAdapter,在该抽象类中通过具体方法

IOS调用WCF提供的服务方法,但是方法的参数是WCF那边自定义的对象,这样有办法调用么,如果可以IOS应该怎么传参呢?请问有了解的么,

最近做一个项目后端使用WCF接收Android手机拍照并带其它参数保存到服务器里:刚好把最近学习的WCF利用上,本以为是个比较简单的功能应该很好实现,没想到其中碰到不少问题,在网上搜索很久一直没有想到的解决方案,最后实现对数据流的分段写入然后后端再来解析流实现的此功能:后端运用WCF中的REST来接收数据:REST还是比较简单的知识,若是不懂可以简单网上了解一下:下面我们先了解一些本次运用到的理论知识: 一:理论知识 由于低层协议特性限制,WCF的流模式只支持如下四种:1:BasicHttpBi