SpringMVC源码解析(二)——执行目标方法(详)

目录

(一) 首先设置几个参数的值,便于后面的理解

(二)确定方法运行时使用的每一个参数的值

(三)目标方法确定参数总结

(四)附加:解析普通参数resolveCommonArgument


(一) 首先设置几个参数的值,便于后面的理解

@RequestMapping("/updateBook")

    public String updateBook(
                @RequestParam(value="author")String author,
                Map<String, Object> model,
                HttpServletRequest request,
                @ModelAttribute("haha")Book book)
        {
            return "liangwangshou";
        }

(二)确定方法运行时使用的每一个参数的值

解析参数:Object[] args = resolveHandlerArguments(attributeMethodToInvoke, handler, webRequest, implicitModel)

先让大家浏览一下大概的层次结构,根据这个结构来更好学习下面的方法

标了注解:

          保存时哪个注解的详细信息;

          如果参数有ModelAttribute注解;

               拿到ModelAttribute注解的值让attrName保存

                    attrName="haha"

没标注解:

          1)、先看是否普通参数(是否原生API)

               再看是否Model或者Map,如果是就传入隐含模型;

          2)、自定义类型的参数没有ModelAttribute 注解

                    1)、先看是否原生API

                    2)、再看是否Model或者Map

                    3)、再看是否是其他类型的比如SessionStatus、HttpEntity、Errors

                    4)、再看是否简单类型的属性;比如是否Integer,String,基本类型

                            如果是paramName=“”

                    5)、attrName="";

如果是自定义类型对象,最终会产生两个效果;

     1)、如果这个参数标注了ModelAttribute注解就给attrName赋值为这个注解的value值

     2)、如果这个参数没有标注ModelAttribute注解就给attrName赋值"";

这个方法很长很长,但是就大致分为三部分并不难(每一部分我会用红色标出便于观察),我会尽量说的明白,后面还会有总结提供理解。

private Object[] resolveHandlerArguments(Method handlerMethod, Object handler,

            NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception {

        Class<?>[] paramTypes = handlerMethod.getParameterTypes();

          //创建了一个和参数个数一样多的数组,会用来保存每一个参数的值

        Object[] args = new Object[paramTypes.length];

        for (int i = 0; i < args.length; i++) {

            MethodParameter methodParam = new MethodParameter(handlerMethod, i);

            methodParam.initParameterNameDiscovery(this.parameterNameDiscoverer);

            GenericTypeResolver.resolveParameterType(methodParam, handler.getClass());

            String paramName = null;

            String headerName = null;

            boolean requestBodyFound = false;

            String cookieName = null;

            String pathVarName = null;

            String attrName = null;

            boolean required = false;

            String defaultValue = null;

            boolean validate = false;

            Object[] validationHints = null;

            int annotationsFound = 0;

            Annotation[] paramAnns = methodParam.getParameterAnnotations();

            

            //第一部分:找到目标方法这个参数的所有注解,如果有注解就解析并保存注解的信息;并且注解的数量annotationsFound ++

            for (Annotation paramAnn : paramAnns) {

                if (RequestParam.class.isInstance(paramAnn)) {//判断参数是否带@RequestParam注解

                    RequestParam requestParam = (RequestParam) paramAnn;

                    paramName = requestParam.value();

                    required = requestParam.required();

                    defaultValue = parseDefaultValueAttribute(requestParam.defaultValue());

                    annotationsFound++;

                }

                else if (RequestHeader.class.isInstance(paramAnn)) {//判断参数是否带@RequestHeader注解

                    RequestHeader requestHeader = (RequestHeader) paramAnn;

                    headerName = requestHeader.value();

                    required = requestHeader.required();

                    defaultValue = parseDefaultValueAttribute(requestHeader.defaultValue());

                    annotationsFound++;

                }

                else if (RequestBody.class.isInstance(paramAnn)) {//判断参数是否带@RequestBody注解

                    requestBodyFound = true;

                    annotationsFound++;

                }

                else if (CookieValue.class.isInstance(paramAnn)) {//判断参数是否带@CookieValue注解

                    CookieValue cookieValue = (CookieValue) paramAnn;

                    cookieName = cookieValue.value();

                    required = cookieValue.required();

                    defaultValue = parseDefaultValueAttribute(cookieValue.defaultValue());

                    annotationsFound++;

                }

                else if (PathVariable.class.isInstance(paramAnn)) {//判断参数是否带@PathVariable注解

                    PathVariable pathVar = (PathVariable) paramAnn;

                    pathVarName = pathVar.value();

                    annotationsFound++;

                }

                else if (ModelAttribute.class.isInstance(paramAnn)) {//判断参数是否带@ModelAttribute注解

                    ModelAttribute attr = (ModelAttribute) paramAnn;

                    attrName = attr.value();

                    annotationsFound++;

                }

                else if (Value.class.isInstance(paramAnn)) {//判断参数是否带@Value注解

                    defaultValue = ((Value) paramAnn).value();

                }

                else if (paramAnn.annotationType().getSimpleName().startsWith("Valid")) {

                    validate = true;

                    Object value = AnnotationUtils.getValue(paramAnn);

                    validationHints = (value instanceof Object[] ? (Object[]) value : new Object[] {value});

                }

            }

            if (annotationsFound > 1) {//判断注解的数量是否大于1,如果大于1说明该参数有两个注解,则会抛出错误

                throw new IllegalStateException("Handler parameter annotations are exclusive choices - " +

                        "do not specify more than one such annotation on the same parameter: " + handlerMethod);

            }

             // 第二部分:没有找到注解的情况;

            if (annotationsFound == 0) {

                //解析普通参数   会进入resolveStandardArgument(解析标准参数,后面会有补充)

                Object argValue = resolveCommonArgument(methodParam, webRequest);

                

                if (argValue != WebArgumentResolver.UNRESOLVED) {

                    args[i] = argValue;

                }

                else if (defaultValue != null) {

                    args[i] = resolveDefaultValue(defaultValue);

                }

                else {

                    Class<?> paramType = methodParam.getParameterType();

                    //判断是否是Model或者是Map旗下的,如果是将之前创建的隐含模型直接赋值给这个参数

                   if (Model.class.isAssignableFrom(paramType) || Map.class.isAssignableFrom(paramType)) {

                        if (!paramType.isAssignableFrom(implicitModel.getClass())) {

                            throw new IllegalStateException("Argument [" +   paramType.getSimpleName() + "] is of type " +

                                    "Model or Map but is not assignable from the actual model. You may need to switch " +

                                    "newer MVC infrastructure classes to use this argument.");

                        }

                        args[i] = implicitModel;

                    }

                    else if (SessionStatus.class.isAssignableFrom(paramType)) {是否是SessionStatus类型参数

                        args[i] = this.sessionStatus;

                    }

                    else if (HttpEntity.class.isAssignableFrom(paramType)) {是否是HttpEntity类型参数

                        args[i] = resolveHttpEntityRequest(methodParam, webRequest);

                    }

                    else if (Errors.class.isAssignableFrom(paramType)) {是否是Errors类型参数

                        throw new IllegalStateException("Errors/BindingResult argument declared " +

                                "without preceding model attribute. Check your handler method signature!");

                    }

                    else if (BeanUtils.isSimpleProperty(paramType)) {//是否是基本类型参数

                        paramName = "";

                    }

                    else {

                        attrName = "";

                    }

                }

            }

               //第三部分:确定值的环节

            if (paramName != null) {

                args[i] = resolveRequestParam(paramName, required, defaultValue, methodParam, webRequest, handler);

            }

            else if (headerName != null) {

                args[i] = resolveRequestHeader(headerName, required, defaultValue, methodParam, webRequest, handler);

            }

            else if (requestBodyFound) {

                args[i] = resolveRequestBody(methodParam, webRequest, handler);

            }

            else if (cookieName != null) {

                args[i] = resolveCookieValue(cookieName, required, defaultValue, methodParam, webRequest, handler);

            }

            else if (pathVarName != null) {

                args[i] = resolvePathVariable(pathVarName, methodParam, webRequest, handler);

            }

            else if (attrName != null) { //确定自定义类型参数的值;还要将请求中的每一个参数赋值给这个对象

                WebDataBinder binder = resolveModelAttribute(attrName, methodParam, implicitModel, webRequest, handler);

                boolean assignBindingResult = (args.length > i + 1 && Errors.class.isAssignableFrom(paramTypes[i + 1]));

                if (binder.getTarget() != null) {

                    //[将请求参数中提交的每一个属性和javaBean进行绑定]

                    doBind(binder, webRequest, validate, validationHints, !assignBindingResult);

                }

                args[i] = binder.getTarget();

                if (assignBindingResult) {

                    args[i + 1] = binder.getBindingResult();

                    i++;

                }

加入到隐含模型中

                implicitModel.putAll(binder.getBindingResult().getModel());

            }

        }

        return args;

   }

SpringMVC确定POJO值的三步;

1、如果隐含模型中有这个key(标了ModelAttribute注解就是注解指定的value,没标就是参数类型的首字母小写)指定的值;

     如果有将这个值赋值给bindObject;

2、如果是SessionAttributes标注的属性,就从session中拿;

3、如果都不是就利用反射创建对象;

private WebDataBinder resolveModelAttribute(String attrName, MethodParameter methodParam,  ExtendedModelMap implicitModel, NativeWebRequest webRequest, Object handler) throws Exception {

        // Bind request parameter onto object...  

        String name = attrName;

        if ("".equals(name)) {

               //如果attrName是空串;就将参数类型的首字母小写作为值

                //跟参数名无关  例如Book book123456,它的值还是book

            name = Conventions.getVariableNameForParameter(methodParam);

        }

        Class<?> paramType = methodParam.getParameterType();

        Object bindObject;

    

            //确定目标对象的值

        if (implicitModel.containsKey(name)) {

            bindObject = implicitModel.get(name);

        }

        else if (this.methodResolver.isSessionAttribute(name, paramType)) {

        //如果是SessionAttributes标注的属性,就从session中拿

            bindObject = this.sessionAttributeStore.retrieveAttribute(webRequest, name);

            if (bindObject == null) {

                raiseSessionRequiredException("Session attribute '" + name + "' required - not found in session");

            }

        }

        else {//如果都不是就利用反射创建对象

            bindObject = BeanUtils.instantiateClass(paramType);

        }

        WebDataBinder binder = createBinder(webRequest, bindObject, name);

        initBinder(handler, name, binder, webRequest);

        return binder;

(三)目标方法确定参数总结:

确定方法每个参数的值;
    1.标注解:保存注解的信息;最终得到这个注解应该对应解析的值;
    2.没标注解:
        1.看是否是原生API;
        2.看是否是Model或者是Map, SessionStatus、 HttpEntity、 Errors...
        3.看是否是简单类型; paramName=""
        4.给attrName赋值; attrName (参数标了@ModelAttribte(")就是指定的,没标就是"")
            1. attrName使用参数的类型首字母小写;或者使用之前@ModelAttributet(")的值
            2.先看隐含模型中有每个这个attrName作为key对应的值;如果有就从隐含模型中获取并赋值
            3.看是否是@SessionAttributes(value="haha");标注的属性,如果是从session中拿;
            4.不是@SessionAttributes标注的,利用反射创建一个对象;
            5.不是@SessionAttributes标注的,利用反射创建一个对象;

(四)附加:解析普通参数resolveCommonArgument)

即确定当前的参数是否是原生API;

 @Override
        protected Object resolveStandardArgument(Class<?> parameterType, NativeWebRequest webRequest) throws Exception {
            HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
            HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);


            if (ServletRequest.class.isAssignableFrom(parameterType) ||
                    MultipartRequest.class.isAssignableFrom(parameterType)) {
                Object nativeRequest = webRequest.getNativeRequest(parameterType);
                if (nativeRequest == null) {
                    throw new IllegalStateException(
                            "Current request is not of type [" + parameterType.getName() + "]: " + request);
                }
                return nativeRequest;
            }
            else if (ServletResponse.class.isAssignableFrom(parameterType)) {
                this.responseArgumentUsed = true;
                Object nativeResponse = webRequest.getNativeResponse(parameterType);
                if (nativeResponse == null) {
                    throw new IllegalStateException(
                            "Current response is not of type [" + parameterType.getName() + "]: " + response);
                }
                return nativeResponse;
            }
            else if (HttpSession.class.isAssignableFrom(parameterType)) {
                return request.getSession();
            }
            else if (Principal.class.isAssignableFrom(parameterType)) {
                return request.getUserPrincipal();
            }
            else if (Locale.class.equals(parameterType)) {
                return RequestContextUtils.getLocale(request);
            }
            else if (InputStream.class.isAssignableFrom(parameterType)) {
                return request.getInputStream();
            }
            else if (Reader.class.isAssignableFrom(parameterType)) {
                return request.getReader();
            }
            else if (OutputStream.class.isAssignableFrom(parameterType)) {
                this.responseArgumentUsed = true;
                return response.getOutputStream();
            }
            else if (Writer.class.isAssignableFrom(parameterType)) {
                this.responseArgumentUsed = true;
                return response.getWriter();
            }
            return super.resolveStandardArgument(parameterType, webRequest);
        }

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值