美文网首页
spring笔记-参数解析(HandlerMethodArgum

spring笔记-参数解析(HandlerMethodArgum

作者: 兴浩 | 来源:发表于2018-06-03 22:00 被阅读101次

    1.示例代码

    public class User {
    
        private String name;
    
        private Integer age;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Integer getAge() {
            return age;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    }
        @RequestMapping(value = "/test",method = RequestMethod.GET)
        public String getUpToken(User user,String name){
            User u=new User();
            return "t";
        }
    

    2.入口分析

    我们从InvocableHandlerMethod的invokeForRequest方法分析,
    getMethodArgumentValues方法是我们重点想要的分析

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

    3. getMethodArgumentValues

    这里可以看到,对参数的解析,其实是由HandlerMethodArgumentResolver完成的

        private Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
                Object... providedArgs) throws Exception {
    
            MethodParameter[] parameters = getMethodParameters();
            Object[] args = new Object[parameters.length];
            for (int i = 0; i < parameters.length; i++) {
                MethodParameter parameter = parameters[i];
                parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
                args[i] = resolveProvidedArgument(parameter, providedArgs);
                if (args[i] != null) {
                    continue;
                }
                if (this.argumentResolvers.supportsParameter(parameter)) {
                    try {
                        args[i] = this.argumentResolvers.resolveArgument(
                                parameter, mavContainer, request, this.dataBinderFactory);
                        continue;
                    }
                    catch (Exception ex) {
                        if (logger.isDebugEnabled()) {
                            logger.debug(getArgumentResolutionErrorMessage("Failed to resolve", i), ex);
                        }
                        throw ex;
                    }
                }
                if (args[i] == null) {
                    throw new IllegalStateException("Could not resolve method parameter at index " +
                            parameter.getParameterIndex() + " in " + parameter.getExecutable().toGenericString() +
                            ": " + getArgumentResolutionErrorMessage("No suitable resolver for", i));
                }
            }
            return args;
        }
    

    4.HandlerMethodArgumentResolver

    内置由很多Resolver组成

    /**
     * Strategy interface for resolving method parameters into argument values in
     * the context of a given request.
     */
    public interface HandlerMethodArgumentResolver {
    
        boolean supportsParameter(MethodParameter parameter);
    
        Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
                NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;
    
    }
    

    比如如下参数
    1.name由RequestParamMethodArgumentResolver负责解析
    2.test由RequestParamMapMethodArgumentResolver负责解析

        @RequestMapping(value = "/test",method = RequestMethod.GET)
        public String getUpToken(String name,@RequestParam("name") String test){
            return "t";
        }
    

    4.解析单个参数流程

        public final Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
                NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
    
            Assert.state(mavContainer != null, "ModelAttributeMethodProcessor requires ModelAndViewContainer");
            Assert.state(binderFactory != null, "ModelAttributeMethodProcessor requires WebDataBinderFactory");
    
            String name = ModelFactory.getNameForParameter(parameter);
            ModelAttribute ann = parameter.getParameterAnnotation(ModelAttribute.class);
            if (ann != null) {
                mavContainer.setBinding(name, ann.binding());
            }
    
            Object attribute = null;
            BindingResult bindingResult = null;
    
            if (mavContainer.containsAttribute(name)) {
                attribute = mavContainer.getModel().get(name);
            }
            else {
                // Create attribute instance
                try {
                    attribute = createAttribute(name, parameter, binderFactory, webRequest);
                }
                catch (BindException ex) {
                    if (isBindExceptionRequired(parameter)) {
                        // No BindingResult parameter -> fail with BindException
                        throw ex;
                    }
                    // Otherwise, expose null/empty value and associated BindingResult
                    if (parameter.getParameterType() == Optional.class) {
                        attribute = Optional.empty();
                    }
                    bindingResult = ex.getBindingResult();
                }
            }
    
            if (bindingResult == null) {
                // Bean property binding and validation;
                // skipped in case of binding failure on construction.
                WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);
                if (binder.getTarget() != null) {
                    if (!mavContainer.isBindingDisabled(name)) {
                        bindRequestParameters(binder, webRequest);
                    }
                    validateIfApplicable(binder, parameter);
                    if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
                        throw new BindException(binder.getBindingResult());
                    }
                }
                // Value type adaptation, also covering java.util.Optional
                if (!parameter.getParameterType().isInstance(attribute)) {
                    attribute = binder.convertIfNecessary(binder.getTarget(), parameter.getParameterType(), parameter);
                }
                bindingResult = binder.getBindingResult();
            }
    
            // Add resolved attribute and BindingResult at the end of the model
            Map<String, Object> bindingResultModel = bindingResult.getModel();
            mavContainer.removeAttributes(bindingResultModel);
            mavContainer.addAllAttributes(bindingResultModel);
    
            return attribute;
        }
    

    当参数是非简单类型时,则会ServletModelAttributeMethodProcessor流程

    1.首先为WebDataBinder准备参数 name是MethodParameter的名字, attribute是为参数化实例
    2.WebDataBinderFactory创建WebDataBinder对象
    3.执行WebDataBinder绑定ServletRequest参数流程
    4.返回参数化实例attribute

    5.自定义HandlerMethodArgumentResolver

    基础WebMvcConfigurationSupport重写addArgumentResolvers方法

        public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
           
        }
    

    参考:
    https://www.jianshu.com/p/f0a6aefa2706
    SpringMVC 4.3 源码分析之 HandlerMethodArgumentResolver

    相关文章

      网友评论

          本文标题:spring笔记-参数解析(HandlerMethodArgum

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