zoukankan      html  css  js  c++  java
  • Spring源码追踪1——doGetBean(为什么org.springframework.data.redis.core.RedisTemplate的实例可以注入为ListOperations)

    类org.springframework.beans.factory.support.AbstractBeanFactory
    方法T doGetBean(final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)

    这里requiredType是获取的实例要转换成的类型,转换通过org.springframework.beans.TypeConverter进行。

    if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
        try {
            return getTypeConverter().convertIfNecessary(bean, requiredType);
        }
        catch (TypeMismatchException ex) {
            if (logger.isDebugEnabled()) {
                logger.debug("Failed to convert bean '" + name + "' to required type [" +
                        ClassUtils.getQualifiedName(requiredType) + "]", ex);
            }
            throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
        }
    }

    类org.springframework.beans.TypeConverterDelegate

    TypeConverter调用java.beans.PropertyEditor。

    public <T> T convertIfNecessary(String propertyName, Object oldValue, Object newValue,
            Class<T> requiredType, TypeDescriptor typeDescriptor) throws IllegalArgumentException {
    
        Object convertedValue = newValue;
    
        // Custom editor for this type?
        PropertyEditor editor = this.propertyEditorRegistry.findCustomEditor(requiredType, propertyName);
    
        ConversionFailedException firstAttemptEx = null;
    
        // No custom editor but custom ConversionService specified?
        ConversionService conversionService = this.propertyEditorRegistry.getConversionService();
        if (editor == null && conversionService != null && convertedValue != null && typeDescriptor != null) {
            TypeDescriptor sourceTypeDesc = TypeDescriptor.forObject(newValue);
            TypeDescriptor targetTypeDesc = typeDescriptor;
            if (conversionService.canConvert(sourceTypeDesc, targetTypeDesc)) {
                try {
                    return (T) conversionService.convert(convertedValue, sourceTypeDesc, targetTypeDesc);
                }
                catch (ConversionFailedException ex) {
                    // fallback to default conversion logic below
                    firstAttemptEx = ex;
                }
            }
        }
    
        // 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); // redis进入的是此分支路径
            }
            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.equals(requiredType)) {
                    return (T) convertedValue;
                }
                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.equals(requiredType) && ClassUtils.isPrimitiveOrWrapper(convertedValue.getClass())) {
                    // We can stringify any primitive value...
                    return (T) convertedValue.toString();
                }
                else if (convertedValue instanceof String && !requiredType.isInstance(convertedValue)) {
                    if (firstAttemptEx == 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;
                }
            }
    
            if (!ClassUtils.isAssignableValue(requiredType, convertedValue)) {
                if (firstAttemptEx != null) {
                    throw firstAttemptEx;
                }
                // 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 (firstAttemptEx != null) {
            if (editor == null && !standardConversion && requiredType != null && !Object.class.equals(requiredType)) {
                throw firstAttemptEx;
            }
            logger.debug("Original ConversionService attempt failed - ignored since " +
                    "PropertyEditor based conversion eventually succeeded", firstAttemptEx);
        }
    
        return (T) convertedValue;
    }

    类org.springframework.beans.BeanUtils
    方法PropertyEditor findEditorByConvention(Class<?> targetType)

    spring会自动获取type对应的editor

    String editorName = targetType.getName() + "Editor";
    try {
        Class<?> editorClass = cl.loadClass(editorName);
        if (!PropertyEditor.class.isAssignableFrom(editorClass)) {
            if (logger.isWarnEnabled()) {
                logger.warn("Editor class [" + editorName +
                        "] does not implement [java.beans.PropertyEditor] interface");
            }
            unknownEditorTypes.put(targetType, Boolean.TRUE);
            return null;
        }
        return (PropertyEditor) instantiateClass(editorClass);
    }

    例如对org.springframework.data.redis.core.ListOperations则有org.springframework.data.redis.core.ListOperationsEditor

    class ListOperationsEditor extends PropertyEditorSupport {
    
        public void setValue(Object value) {
            if (value instanceof RedisOperations) {
                super.setValue(((RedisOperations) value).opsForList());
            } else {
                throw new java.lang.IllegalArgumentException("Editor supports only conversion of type " + RedisOperations.class);
            }
        }
    }
  • 相关阅读:
    开发流程之功能设计
    spring security之web应用安全
    feign架构原理解析
    负载均衡之ribbon
    服务发现之eureka
    JavaScript的内置对象
    JavaScript的流程控制语句以及函数
    JavaScript的基础语法及DOM元素和事件
    CSS的基础使用
    盒子模型
  • 原文地址:https://www.cnblogs.com/chanedi/p/4135303.html
Copyright © 2011-2022 走看看