springMVC 源码解剖 解析过程

 springMVC 解析过程

首先要知道web项目启动完毕,spring容器会初始化完毕,针对一些单例controller已经创建好了。已经对这个类的BeanDefinition 对象
也已经创建完成,不知道BeanDefinition 的可以看
springMVC本质就是一个servlet 
 
springMVC 处理请求的大致过程:
           核心Servlet: DispatcherServlet
           核心方法:    doDispatch
           第一步:根据URL解析出映射字符串str与@@RequestMapping("/index.action") 这里面的字符进行匹配,不成功则报404
           第二部:根据str 获得 HandlerMethod对象
           第三步: 将HandlerMethod对象 重新封装一个新的HandlerMethod对象 并加入controller对象
           第四部: 根据HandlerMethod对象 获得 适配器 HandlerAdapter
           第五步: 适配器开始调用 handle 方法
           第六步: 根据controller中的方法参数名字,获得请求对应信息
           第七步: 根据controller中的方法参数的类型,将获得的信息数据 进行类型转换并将转后的数据返回
           第八部: 开始利用第七部返回的参数开始反射调用我们的controller中的方法 此时线程就已经到我们自己写的controller方法了。
           
           以上是大致过程:下面是我自己画的uml 图,看图时根据上面写的过程去看, 你会受益匪浅的。

   

 下面是我copy的关键代码。也可以 参考。

    @Override
    protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest webRequest) throws Exception {
        HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
        MultipartHttpServletRequest multipartRequest =
                WebUtils.getNativeRequest(servletRequest, MultipartHttpServletRequest.class);
        Object arg;

        if (MultipartFile.class == parameter.getParameterType()) {
            assertIsMultipartRequest(servletRequest);
            Assert.notNull(multipartRequest, "Expected MultipartHttpServletRequest: is a MultipartResolver configured?");
            arg = multipartRequest.getFile(name);
        }
        else if (isMultipartFileCollection(parameter)) {
            assertIsMultipartRequest(servletRequest);
            Assert.notNull(multipartRequest, "Expected MultipartHttpServletRequest: is a MultipartResolver configured?");
            arg = multipartRequest.getFiles(name);
        }
        else if (isMultipartFileArray(parameter)) {
            assertIsMultipartRequest(servletRequest);
            Assert.notNull(multipartRequest, "Expected MultipartHttpServletRequest: is a MultipartResolver configured?");
            List<MultipartFile> multipartFiles = multipartRequest.getFiles(name);
            arg = multipartFiles.toArray(new MultipartFile[multipartFiles.size()]);
        }
        else if ("javax.servlet.http.Part".equals(parameter.getParameterType().getName())) {
            assertIsMultipartRequest(servletRequest);
            arg = servletRequest.getPart(name);
        }
        else if (isPartCollection(parameter)) {
            assertIsMultipartRequest(servletRequest);
            arg = new ArrayList<Object>(servletRequest.getParts());
        }
        else if (isPartArray(parameter)) {
            assertIsMultipartRequest(servletRequest);
            arg = RequestPartResolver.resolvePart(servletRequest);
        }
        else {
            arg = null;
            if (multipartRequest != null) {
                List<MultipartFile> files = multipartRequest.getFiles(name);
                if (!files.isEmpty()) {
                    arg = (files.size() == 1 ? files.get(0) : files);
                }
            }
            if (arg == null) {
                String[] paramValues = webRequest.getParameterValues(name);
                if (paramValues != null) {
                    arg = (paramValues.length == 1 ? paramValues[0] : paramValues);
                }
            }
        }

        return arg;
    }
 
 
 binder.setConversionService(this.conversionService);设置类型转换器,帮助前台数据与方法参数的类型转换(这里都是springmvc的默认转换器)
 conversionService:封装了大量的类型转换器
 ConversionService converters =
    @org.springframework.format.annotation.DateTimeFormat java.lang.Long -> java.lang.String: org.springframework.format.datetime.DateTimeFormatAnnotationFormatterFactory@c2edc29,@org.springframework.format.annotation.NumberFormat java.lang.Long -> java.lang.String: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@473397bc
    @org.springframework.format.annotation.DateTimeFormat java.util.Calendar -> java.lang.String: org.springframework.format.datetime.DateTimeFormatAnnotationFormatterFactory@c2edc29
    @org.springframework.format.annotation.DateTimeFormat java.util.Date -> java.lang.String: org.springframework.format.datetime.DateTimeFormatAnnotationFormatterFactory@c2edc29
    @org.springframework.format.annotation.NumberFormat java.lang.Byte -> java.lang.String: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@473397bc
    @org.springframework.format.annotation.NumberFormat java.lang.Double -> java.lang.String: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@473397bc
    @org.springframework.format.annotation.NumberFormat java.lang.Float -> java.lang.String: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@473397bc
    @org.springframework.format.annotation.NumberFormat java.lang.Integer -> java.lang.String: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@473397bc
    @org.springframework.format.annotation.NumberFormat java.lang.Short -> java.lang.String: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@473397bc
    @org.springframework.format.annotation.NumberFormat java.math.BigDecimal -> java.lang.String: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@473397bc
    @org.springframework.format.annotation.NumberFormat java.math.BigInteger -> java.lang.String: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@473397bc
    java.lang.Boolean -> java.lang.String : org.springframework.core.convert.support.ObjectToStringConverter@674cc3f2
    java.lang.Character -> java.lang.Number : org.springframework.core.convert.support.CharacterToNumberFactory@2345f554
    java.lang.Character -> java.lang.String : org.springframework.core.convert.support.ObjectToStringConverter@b0ff5e1
    java.lang.Enum -> java.lang.String : org.springframework.core.convert.support.EnumToStringConverter@1d8bc739
    java.lang.Long -> java.util.Calendar : org.springframework.format.datetime.DateFormatterRegistrar$LongToCalendarConverter@13b7d136
    java.lang.Long -> java.util.Date : org.springframework.format.datetime.DateFormatterRegistrar$LongToDateConverter@3d83bc2f
    java.lang.Number -> java.lang.Character : org.springframework.core.convert.support.NumberToCharacterConverter@44d78c73
    java.lang.Number -> java.lang.Number : org.springframework.core.convert.support.NumberToNumberConverterFactory@3682db4
    java.lang.Number -> java.lang.String : org.springframework.core.convert.support.ObjectToStringConverter@445887e8
    java.lang.String -> @org.springframework.format.annotation.DateTimeFormat java.lang.Long: org.springframework.format.datetime.DateTimeFormatAnnotationFormatterFactory@c2edc29,java.lang.String -> @org.springframework.format.annotation.NumberFormat java.lang.Long: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@473397bc
    java.lang.String -> @org.springframework.format.annotation.DateTimeFormat java.util.Calendar: org.springframework.format.datetime.DateTimeFormatAnnotationFormatterFactory@c2edc29
    java.lang.String -> @org.springframework.format.annotation.DateTimeFormat java.util.Date: org.springframework.format.datetime.DateTimeFormatAnnotationFormatterFactory@c2edc29
    java.lang.String -> @org.springframework.format.annotation.NumberFormat java.lang.Byte: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@473397bc
    java.lang.String -> @org.springframework.format.annotation.NumberFormat java.lang.Double: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@473397bc
    java.lang.String -> @org.springframework.format.annotation.NumberFormat java.lang.Float: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@473397bc
    java.lang.String -> @org.springframework.format.annotation.NumberFormat java.lang.Integer: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@473397bc
    java.lang.String -> @org.springframework.format.annotation.NumberFormat java.lang.Short: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@473397bc
    java.lang.String -> @org.springframework.format.annotation.NumberFormat java.math.BigDecimal: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@473397bc
    java.lang.String -> @org.springframework.format.annotation.NumberFormat java.math.BigInteger: org.springframework.format.number.NumberFormatAnnotationFormatterFactory@473397bc
    java.lang.String -> java.lang.Boolean : org.springframework.core.convert.support.StringToBooleanConverter@45ed6fe3
    java.lang.String -> java.lang.Character : org.springframework.core.convert.support.StringToCharacterConverter@1042b366
    java.lang.String -> java.lang.Enum : org.springframework.core.convert.support.StringToEnumConverterFactory@60d479d9
    java.lang.String -> java.lang.Number : org.springframework.core.convert.support.StringToNumberConverterFactory@2c90862b
    java.lang.String -> java.nio.charset.Charset : org.springframework.core.convert.support.StringToCharsetConverter@55686678
    java.lang.String -> java.util.Currency : org.springframework.core.convert.support.StringToCurrencyConverter@420ba5a6
    java.lang.String -> java.util.Locale : org.springframework.core.convert.support.StringToLocaleConverter@43c47e56
    java.lang.String -> java.util.Properties : org.springframework.core.convert.support.StringToPropertiesConverter@31f28bdd
    java.lang.String -> java.util.UUID : org.springframework.core.convert.support.StringToUUIDConverter@3a55a70a
    java.nio.charset.Charset -> java.lang.String : org.springframework.core.convert.support.ObjectToStringConverter@391f7c16
    java.util.Calendar -> java.lang.Long : org.springframework.format.datetime.DateFormatterRegistrar$CalendarToLongConverter@2a9581e8
    java.util.Calendar -> java.util.Date : org.springframework.format.datetime.DateFormatterRegistrar$CalendarToDateConverter@1a27cb52
    java.util.Currency -> java.lang.String : org.springframework.core.convert.support.ObjectToStringConverter@aa8572a
    java.util.Date -> java.lang.Long : org.springframework.format.datetime.DateFormatterRegistrar$DateToLongConverter@58780dfe
    java.util.Date -> java.util.Calendar : org.springframework.format.datetime.DateFormatterRegistrar$DateToCalendarConverter@31decc12
    java.util.Locale -> java.lang.String : org.springframework.core.convert.support.ObjectToStringConverter@194262dc
    java.util.Properties -> java.lang.String : org.springframework.core.convert.support.PropertiesToStringConverter@2abc73c9
    java.util.UUID -> java.lang.String : org.springframework.core.convert.support.ObjectToStringConverter@4d499f71
    org.springframework.core.convert.support.ArrayToArrayConverter@eb531fe
    org.springframework.core.convert.support.ArrayToCollectionConverter@1c82db5b
    org.springframework.core.convert.support.ArrayToObjectConverter@1033edfe
    org.springframework.core.convert.support.ArrayToStringConverter@3cdd08b6
    org.springframework.core.convert.support.ByteBufferConverter@40bc74a0
    org.springframework.core.convert.support.ByteBufferConverter@40bc74a0
    org.springframework.core.convert.support.ByteBufferConverter@40bc74a0
    org.springframework.core.convert.support.ByteBufferConverter@40bc74a0
    org.springframework.core.convert.support.CollectionToArrayConverter@530f41fc
    org.springframework.core.convert.support.CollectionToCollectionConverter@19e5223d
    org.springframework.core.convert.support.CollectionToObjectConverter@6fb1667b
    org.springframework.core.convert.support.CollectionToStringConverter@59443425
    org.springframework.core.convert.support.FallbackObjectToStringConverter@d6497f2
    org.springframework.core.convert.support.IdToEntityConverter@148cd594,org.springframework.core.convert.support.ObjectToObjectConverter@2a19f216
    org.springframework.core.convert.support.MapToMapConverter@122ae013
    org.springframework.core.convert.support.ObjectToArrayConverter@414dc701
    org.springframework.core.convert.support.ObjectToCollectionConverter@67bf4e86
    org.springframework.core.convert.support.StringToArrayConverter@536703f1
    org.springframework.core.convert.support.StringToCollectionConverter@cbb96ec

 
 
 //TypeConverterDelegate 类中: 真是转换类型的逻辑。
 public <T> T convertIfNecessary(String propertyName, Object oldValue, Object newValue,
            Class<T> requiredType, TypeDescriptor typeDescriptor) throws IllegalArgumentException {

        // Custom editor for this type?
        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;

        // Value not of required type?
        if (editor != null || (requiredType != null && !ClassUtils.isAssignableValue(requiredType, convertedValue))) {
            if (requiredType != null && Collection.class.isAssignableFrom(requiredType) && convertedValue instanceof String) {
                TypeDescriptor elementType = typeDescriptor.getElementTypeDescriptor();
                if (elementType != null && Enum.class.isAssignableFrom(elementType.getType())) {
                    convertedValue = StringUtils.commaDelimitedListToStringArray((String) convertedValue);
                }
            }
            if (editor == null) {
                editor = findDefaultEditor(requiredType);
            }
            convertedValue = doConvertValue(oldValue, convertedValue, requiredType, editor);
        }

        boolean standardConversion = false;

        if (requiredType != null) {
            // Try to apply some standard type conversion rules if appropriate.

            if (convertedValue != null) {
                if (Object.class == requiredType) {
                    return (T) convertedValue;
                }
                else if (requiredType.isArray()) {
                    // Array required -> apply appropriate conversion of elements.
                    if (convertedValue instanceof String && Enum.class.isAssignableFrom(requiredType.getComponentType())) {
                        convertedValue = StringUtils.commaDelimitedListToStringArray((String) convertedValue);
                    }
                    return (T) convertToTypedArray(convertedValue, propertyName, requiredType.getComponentType());
                }
                else if (convertedValue instanceof Collection) {
                    // Convert elements to target type, if determined.
                    convertedValue = convertToTypedCollection(
                            (Collection<?>) convertedValue, propertyName, requiredType, typeDescriptor);
                    standardConversion = true;
                }
                else if (convertedValue instanceof Map) {
                    // Convert keys and values to respective target type, if determined.
                    convertedValue = convertToTypedMap(
                            (Map<?, ?>) convertedValue, propertyName, requiredType, typeDescriptor);
                    standardConversion = true;
                }
                if (convertedValue.getClass().isArray() && Array.getLength(convertedValue) == 1) {
                    convertedValue = Array.get(convertedValue, 0);
                    standardConversion = true;
                }
                if (String.class == requiredType && ClassUtils.isPrimitiveOrWrapper(convertedValue.getClass())) {
                    // We can stringify any primitive value...
                    return (T) convertedValue.toString();
                }
                else if (convertedValue instanceof String && !requiredType.isInstance(convertedValue)) {
                    if (conversionAttemptEx == null && !requiredType.isInterface() && !requiredType.isEnum()) {
                        try {
                            Constructor<T> strCtor = requiredType.getConstructor(String.class);
                            return BeanUtils.instantiateClass(strCtor, convertedValue);
                        }
                        catch (NoSuchMethodException ex) {
                            // proceed with field lookup
                            if (logger.isTraceEnabled()) {
                                logger.trace("No String constructor found on type [" + requiredType.getName() + "]", ex);
                            }
                        }
                        catch (Exception ex) {
                            if (logger.isDebugEnabled()) {
                                logger.debug("Construction via String failed for type [" + requiredType.getName() + "]", ex);
                            }
                        }
                    }
                    String trimmedValue = ((String) convertedValue).trim();
                    if (requiredType.isEnum() && "".equals(trimmedValue)) {
                        // It's an empty enum identifier: reset the enum value to null.
                        return null;
                    }
                    convertedValue = attemptToConvertStringToEnum(requiredType, trimmedValue, convertedValue);
                    standardConversion = true;
                }
                else if (convertedValue instanceof Number && Number.class.isAssignableFrom(requiredType)) {
                    convertedValue = NumberUtils.convertNumberToTargetClass(
                            (Number) convertedValue, (Class<Number>) requiredType);
                    standardConversion = true;
                }
            }
            else {
                // convertedValue == null
                if (javaUtilOptionalEmpty != null && requiredType.equals(javaUtilOptionalEmpty.getClass())) {
                    convertedValue = javaUtilOptionalEmpty;
                }
            }

            if (!ClassUtils.isAssignableValue(requiredType, convertedValue)) {
                if (conversionAttemptEx != null) {
                    // Original exception from former ConversionService call above...
                    throw conversionAttemptEx;
                }
                else if (conversionService != null) {
                    // ConversionService not tried before, probably custom editor found
                    // but editor couldn't produce the required type...
                    TypeDescriptor sourceTypeDesc = TypeDescriptor.forObject(newValue);
                    if (conversionService.canConvert(sourceTypeDesc, typeDescriptor)) {
                        return (T) conversionService.convert(newValue, sourceTypeDesc, typeDescriptor);
                    }
                }

                // Definitely doesn't match: throw IllegalArgumentException/IllegalStateException
                StringBuilder msg = new StringBuilder();
                msg.append("Cannot convert value of type [").append(ClassUtils.getDescriptiveType(newValue));
                msg.append("] to required type [").append(ClassUtils.getQualifiedName(requiredType)).append("]");
                if (propertyName != null) {
                    msg.append(" for property '").append(propertyName).append("'");
                }
                if (editor != null) {
                    msg.append(": PropertyEditor [").append(editor.getClass().getName()).append(
                            "] returned inappropriate value of type [").append(
                            ClassUtils.getDescriptiveType(convertedValue)).append("]");
                    throw new IllegalArgumentException(msg.toString());
                }
                else {
                    msg.append(": no matching editors or conversion strategy found");
                    throw new IllegalStateException(msg.toString());
                }
            }
        }

        if (conversionAttemptEx != null) {
            if (editor == null && !standardConversion && requiredType != null && Object.class != requiredType) {
                throw conversionAttemptEx;
            }
            logger.debug("Original ConversionService attempt failed - ignored since " +
                    "PropertyEditor based conversion eventually succeeded", conversionAttemptEx);
        }

        return (T) convertedValue;
    }
 
 
看看源码,做开发的时候才能游刃有余。也能学到很多知识。springmvc的渲染过程,下次再与大家分享。

猜你喜欢

转载自blog.csdn.net/qq_29499107/article/details/83791735
今日推荐