手写简易版Spring框架(十五):数据类型转换

目标

其实实现到本章节,关于IOC、AOP在日常使用中高频出现的技术点都该涵盖了。那么为了补全整个框架内容的结构,方便读者后续在阅读 Spring 时不至于对类型转换的知识体系陌生,这里再添加一些关于此类知识的实现。

类型转换也可以叫做数据转换,比如从String到Integer、从String到Date、从Dubbo到Long等等,但这些操作不能在已经使用框架的情况下还需要手动处理,所以我们要把这样的功能扩展到Spring框架中。

设计

如果我们来把只是看上去一个简单的类型转换操作抽象成框架,那么它就需要一个标准的接口,谁实现这个接口就具备类型转换的具体实现,提供类型转换的能力。那么在有了这样接口后,还需要类型转换服务的注册、工厂等内容,才可以把类型转换抽象成一个组件服务。

首先从工厂出发我们需要实现一个 ConversionServiceFactoryBean 来对类型转换服务进行操作。而实现类型转换的服务,需要定义 Converter 转换类型、ConverterRegistry 注册类型转换功能,另外转换类型的操作较多,所以这里也会需要定义一个类型转换工厂 ConverterFactory 各个具体的转换操作来实现这个工厂接口。

实现

定义类型转换接口

package com.qingyun.springframework.core.convert.converter;

/**
 * @description: 数据类型转换器
 * @author: 張青云
 * @create: 2021-08-28 21:02
 **/
public interface Converter<S, T>  {
    
    

    /** 数据类型转换,从S到T */
    T convert(S source);

}

package com.qingyun.springframework.core.convert.converter;

/**
 * @description: 类型转化工厂
 * @author: 張青云
 * @create: 2021-08-28 21:05
 **/
public interface ConverterFactory<S, R>{
    
    

    /**
     * 获取一个类型转换器,将S转换成T(T实现了R)
     */
    <T extends R> Converter<S, T> getConverter(Class<T> targetType);

}

package com.qingyun.springframework.core.convert.converter;

/**
 * @description: 类型转换注册接口
 * @author: 張青云
 * @create: 2021-08-28 21:08
 **/
public interface ConverterRegistry {
    
    

    /**
     * 向注册表中注册一个转换器
     */
    void addConverter(Converter<?, ?> converter);

    /**
     * 添加一个通用注册器
     */
    void addConverter(GenericConverter converter);

    /**
     * 增加一个类型转换工厂
     */
    void addConverterFactory(ConverterFactory<?, ?> converterFactory);

}

Converter 、 ConverterFactory 、 ConverterRegistry ,都是用于定义类型转换操作的相关接口,后续所有的实现都需要围绕这些接口来实现,具体的代码功能可以进行调试验证。

实现类型转换服务

package com.qingyun.springframework.core.convert.converter;

import cn.hutool.core.lang.Assert;

import java.util.Set;

/**
 * @description: 通用的类型转换器
 * @author: 張青云
 * @create: 2021-08-28 21:17
 **/
public interface GenericConverter {
    
    

    /**
     * 获取这个类型转换器可以完成的类型转换类型
     */
    Set<ConvertiblePair> getConvertibleTypes();

    /**
     * 进行数据类型转换
     */
    Object convert(Object source, Class sourceType, Class targetType);


    final class ConvertiblePair {
    
    
        private final Class<?> sourceType;

        private final Class<?> targetType;

        public ConvertiblePair(Class<?> sourceType, Class<?> targetType) {
    
    
            Assert.notNull(sourceType, "Source type must not be null");
            Assert.notNull(targetType, "Target type must not be null");
            this.sourceType = sourceType;
            this.targetType = targetType;
        }

        public Class<?> getSourceType() {
    
    
            return this.sourceType;
        }

        public Class<?> getTargetType() {
    
    
            return this.targetType;
        }

        @Override
        public boolean equals(Object obj) {
    
    
            if (this == obj) {
    
    
                return true;
            }
            if (obj == null || obj.getClass() != ConvertiblePair.class) {
    
    
                return false;
            }
            ConvertiblePair other = (ConvertiblePair) obj;
            return this.sourceType.equals(other.sourceType) && this.targetType.equals(other.targetType);

        }

        @Override
        public int hashCode() {
    
    
            return this.sourceType.hashCode() * 31 + this.targetType.hashCode();
        }
    }

}

package com.qingyun.springframework.core.convert.support;

import com.qingyun.springframework.core.convert.ConversionService;
import com.qingyun.springframework.core.convert.ConvertException;
import com.qingyun.springframework.core.convert.converter.Converter;
import com.qingyun.springframework.core.convert.converter.ConverterFactory;
import com.qingyun.springframework.core.convert.converter.ConverterRegistry;
import com.qingyun.springframework.core.convert.converter.GenericConverter;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;

/**
 * @description:
 * @author: 張青云
 * @create: 2021-08-28 21:30
 **/
public class GenericConversionService implements ConversionService, ConverterRegistry {
    
    

    //  保存类型转换器
    private Map<GenericConverter.ConvertiblePair, GenericConverter> converters = new HashMap<>();

    @Override
    public boolean canConvert(Class<?> sourceType, Class<?> targetType) {
    
    
        GenericConverter converter = getConverter(sourceType, targetType);
        return converter != null;
    }

    @Override
    public <T> T convert(Object source, Class<T> targetType) {
    
    
        Class<?> sourceType = source.getClass();
        GenericConverter converter = getConverter(sourceType, targetType);
        if (converter == null) {
    
    
            throw new ConvertException(sourceType + "无法转换成" + targetType);
        }
        return (T) converter.convert(source, sourceType, targetType);
    }

    @Override
    public void addConverter(Converter<?, ?> converter) {
    
    
        GenericConverter.ConvertiblePair typeInfo = getRequiredTypeInfo(converter);
        ConverterAdapter converterAdapter = new ConverterAdapter(typeInfo, converter);
        for (GenericConverter.ConvertiblePair convertibleType : converterAdapter.getConvertibleTypes()) {
    
    
            converters.put(convertibleType, converterAdapter);
        }
    }

    @Override
    public void addConverterFactory(ConverterFactory<?, ?> converterFactory) {
    
    
        GenericConverter.ConvertiblePair typeInfo = getRequiredTypeInfo(converterFactory);
        ConverterFactoryAdapter converterFactoryAdapter = new ConverterFactoryAdapter(typeInfo, converterFactory);
        for (GenericConverter.ConvertiblePair convertibleType : converterFactoryAdapter.getConvertibleTypes()) {
    
    
            converters.put(convertibleType, converterFactoryAdapter);
        }
    }

    @Override
    public void addConverter(GenericConverter converter) {
    
    
        for (GenericConverter.ConvertiblePair convertibleType : converter.getConvertibleTypes()) {
    
    
            converters.put(convertibleType, converter);
        }
    }

    /**获取类型转换器的一些信息*/
    private GenericConverter.ConvertiblePair getRequiredTypeInfo(Object object) {
    
    
        //  通过泛型来确定原类型和目的类型
        Type[] types = object.getClass().getGenericInterfaces();
        ParameterizedType parameterized = (ParameterizedType) types[0];
        Type[] actualTypeArguments = parameterized.getActualTypeArguments();
        Class sourceType = (Class) actualTypeArguments[0];
        Class targetType = (Class) actualTypeArguments[1];
        return new GenericConverter.ConvertiblePair(sourceType, targetType);
    }

    /**
     * 获取从类型sourceType到类型targetType的转换器
     */
    protected GenericConverter getConverter(Class<?> sourceType, Class<?> targetType) {
    
    
        List<Class<?>> sourceCandidates = getClassHierarchy(sourceType);
        List<Class<?>> targetCandidates = getClassHierarchy(targetType);
        for (Class<?> sourceCandidate : sourceCandidates) {
    
    
            for (Class<?> targetCandidate : targetCandidates) {
    
    
                GenericConverter.ConvertiblePair convertiblePair = new GenericConverter.ConvertiblePair(sourceCandidate, targetCandidate);
                GenericConverter converter = converters.get(convertiblePair);
                if (converter != null) {
    
    
                    return converter;
                }
            }
        }
        return null;
    }

    /**
     * 获取clazz的类型
     */
    private List<Class<?>> getClassHierarchy(Class<?> clazz) {
    
    
        List<Class<?>> hierarchy = new ArrayList<>();
        while (clazz != null) {
    
    
            hierarchy.add(clazz);
            clazz = clazz.getSuperclass();
        }
        return hierarchy;
    }

    private final class ConverterAdapter implements GenericConverter {
    
    

        private final ConvertiblePair typeInfo;

        private final Converter<Object, Object> converter;

        public ConverterAdapter(ConvertiblePair typeInfo, Converter<?, ?> converter) {
    
    
            this.typeInfo = typeInfo;
            this.converter = (Converter<Object, Object>) converter;
        }

        @Override
        public Set<ConvertiblePair> getConvertibleTypes() {
    
    
            return Collections.singleton(typeInfo);
        }

        @Override
        public Object convert(Object source, Class sourceType, Class targetType) {
    
    
            return converter.convert(source);
        }
    }

    private final class ConverterFactoryAdapter implements GenericConverter {
    
    

        private final ConvertiblePair typeInfo;

        private final ConverterFactory<Object, Object> converterFactory;

        public ConverterFactoryAdapter(ConvertiblePair typeInfo, ConverterFactory<?, ?> converterFactory) {
    
    
            this.typeInfo = typeInfo;
            this.converterFactory = (ConverterFactory<Object, Object>) converterFactory;
        }

        @Override
        public Set<ConvertiblePair> getConvertibleTypes() {
    
    
            return Collections.singleton(typeInfo);
        }

        @Override
        public Object convert(Object source, Class sourceType, Class targetType) {
    
    
            return converterFactory.getConverter(targetType).convert(source);
        }
    }

}

package com.qingyun.springframework.core.convert.support;

import com.qingyun.springframework.core.convert.converter.ConverterRegistry;

/**
 * @description:
 * @author: 張青云
 * @create: 2021-08-28 21:29
 **/
public class DefaultConversionService extends GenericConversionService{
    
    

    public DefaultConversionService() {
    
    
        addDefaultConverters(this);
    }

    public static void addDefaultConverters(ConverterRegistry converterRegistry) {
    
    
        // 添加各类的转换器和类型转换工厂
        converterRegistry.addConverterFactory(new StringToNumberConverterFactory());
        converterRegistry.addConverter(new StringToIntegerConverter());
    }

}

DefaultConversionService 是继承 GenericConversionService 的实现类,GenericConversionService 实现了 ConversionService, ConverterRegistry 两个接口,用于 canConvert 判断和转换接口 convert 操作。

创建类型转换工厂

package com.qingyun.springframework.context.support;

import com.qingyun.springframework.beans.factory.FactoryBean;
import com.qingyun.springframework.beans.factory.InitializingBean;
import com.qingyun.springframework.core.convert.ConversionService;
import com.qingyun.springframework.core.convert.converter.Converter;
import com.qingyun.springframework.core.convert.converter.ConverterFactory;
import com.qingyun.springframework.core.convert.converter.ConverterRegistry;
import com.qingyun.springframework.core.convert.converter.GenericConverter;
import com.qingyun.springframework.core.convert.support.DefaultConversionService;
import com.qingyun.springframework.core.convert.support.GenericConversionService;
import com.sun.istack.internal.Nullable;

import java.util.Set;

/**
 * @description: 提供创建 ConversionService 工厂
 * @author: 張青云
 * @create: 2021-08-28 21:37
 **/
public class ConversionServiceFactoryBean implements FactoryBean<ConversionService>, InitializingBean {
    
    

    //  类型转换器集合
    @Nullable
    private Set<?> converters;

    @Nullable
    private GenericConversionService conversionService;

    @Override
    public ConversionService getObject() throws Exception {
    
    
        return conversionService;
    }

    @Override
    public Class<?> getObjectType() {
    
    
        return conversionService.getClass();
    }

    @Override
    public boolean isSingleton() {
    
    
        return true;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
    
    
        this.conversionService = new DefaultConversionService();
        //  添加默认的类型转换器
        DefaultConversionService.addDefaultConverters(this.conversionService);
        //  添加用户自定义的类型转换器
        registerConverters(converters, conversionService);
    }

    private void registerConverters(Set<?> converters, ConverterRegistry registry) {
    
    
        if (converters != null) {
    
    
            for (Object converter : converters) {
    
    
                if (converter instanceof GenericConverter) {
    
    
                    registry.addConverter((GenericConverter) converter);
                } else if (converter instanceof Converter<?, ?>) {
    
    
                    registry.addConverter((Converter<?, ?>) converter);
                } else if (converter instanceof ConverterFactory<?, ?>) {
    
    
                    registry.addConverterFactory((ConverterFactory<?, ?>) converter);
                } else {
    
    
                    throw new IllegalArgumentException("Each converter object must implement one of the " +
                            "Converter, ConverterFactory, or GenericConverter interfaces");
                }
            }
        }
    }

    public void setConverters(Set<?> converters) {
    
    
        this.converters = converters;
    }

}

有了 FactoryBean 的实现就可以完成工程对象的操作,可以提供出转换对象的服务 GenericConversionService ,另外在 afterPropertiesSet 中调用了注册转换操作的类。最终这个类会被配置到 spring.xml 中在启动的过程加载。

类型转换服务使用

AbstractAutowireCapableBeanFactory类:

protected void applyPropertyValues(String beanName, Object bean, BeanDefinition beanDefinition) {
    
    
        try {
    
    
            PropertyValues propertyValues = beanDefinition.getPropertyValues();
            for (PropertyValue propertyValue: propertyValues.getPropertyValues()) {
    
    
                String name = propertyValue.getName();
                Object value = propertyValue.getValue();

                if (value instanceof BeanReference) {
    
    
                    //  TODO 没有解决循环依赖问题
                    //  A依赖B,获取B的实例
                    BeanReference beanReference = (BeanReference) value;
                    value = getBean(beanReference.getBeanName());
                    //  如果是FactoryBean则需要再getBean一次,因为上一次只是将FactoryBean当作工厂进行了实例化,
                    //  再来一次才是通过FactoryBean获取期待的对象
                    if (value instanceof FactoryBean) {
    
    
                        value = getBean(beanReference.getBeanName());
                    }
                } else {
    
      // 类型转换
                    Class<?> sourceType = value.getClass();
                    Class<?> targetType = (Class<?>) TypeUtil.getFieldType(bean.getClass(), name);
                    ConversionService conversionService = getConversionService();
                    if (conversionService != null) {
    
    
                        if (conversionService.canConvert(sourceType, targetType)) {
    
    
                            value = conversionService.convert(value, targetType);
                        }
                    }
                }
                // 属性填充,通过反射设置属性值
                BeanUtil.setFieldValue(bean, name, value);
            }
        } catch (Exception e) {
    
    
            throw new BeansException("Error setting property values:" + beanName);
        }
    }

在 AbstractAutowireCapableBeanFact ory#applyPropertyValues 填充属性的操作中,具体使用了类型转换的功能。在 AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues 也有同样的属性类型转换操作。

将ConversionService融入到上下文中

AbstractApplicationContext类:

    public void refresh() throws BeansException {
    
    
        // 1. 创建BeanFactory,并加载、注册BeanDefinition
        refreshBeanFactory();

        // 2. 获取 BeanFactory
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();

        // 3. 添加 ApplicationContextAwareProcessor,让继承自 ApplicationContextAware 的 Bean 对象都能感知所属的 ApplicationContext
        beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

        // 4. 在 Bean 实例化之前,执行 BeanFactoryPostProcessor
        invokeBeanFactoryPostProcessors(beanFactory);

        // 5. BeanPostProcessor 需要提前于其他 Bean 对象实例化之前执行注册操作
        //  然后在接下来的每一个Bean创建的时候都会将这些BeanPostProcessor过一遍
        registerBeanPostProcessors(beanFactory);

        // 6. 初始化事件发布者
        initApplicationEventMulticaster();

        // 7. 注册事件监听器
        registerListeners();

        // 8. 设置类型转换器、提前实例化单例Bean对象
        finishBeanFactoryInitialization(beanFactory);

        // 9. 发布容器刷新完成事件
        finishRefresh();
    }

    protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
    
    
        // 设置类型转换器
        if (beanFactory.containsBean("conversionService")) {
    
    
            Object conversionService = beanFactory.getBean("conversionService");
            if (conversionService instanceof FactoryBean) {
    
    
                conversionService = beanFactory.getBean("conversionService");
            }
            if (conversionService instanceof ConversionService) {
    
    
                beanFactory.setConversionService((ConversionService) conversionService);
            }
        }

        // 提前实例化单例Bean对象
        beanFactory.preInstantiateSingletons();
    }

测试

准备

package com.qingyun.springframework.context.test.type;

import java.time.LocalDate;

/**
 * @description:
 * @author: 張青云
 * @create: 2021-08-28 21:57
 **/
public class Husband {
    
    

    private String wifiName;

    private LocalDate marriageDate;

    public String getWifiName() {
    
    
        return wifiName;
    }

    public void setWifiName(String wifiName) {
    
    
        this.wifiName = wifiName;
    }

    public LocalDate getMarriageDate() {
    
    
        return marriageDate;
    }

    public void setMarriageDate(LocalDate marriageDate) {
    
    
        this.marriageDate = marriageDate;
    }

    @Override
    public String toString() {
    
    
        return "Husband{" +
                "wifiName='" + wifiName + '\'' +
                ", marriageDate=" + marriageDate +
                '}';
    }

}

自定义类型转换器

package com.qingyun.springframework.context.test.type;

import com.qingyun.springframework.core.convert.converter.Converter;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

/**
 * @description:
 * @author: 張青云
 * @create: 2021-08-28 21:58
 **/
public class StringToLocalDateConverter implements Converter<String, LocalDate> {
    
    

    private final DateTimeFormatter DATE_TIME_FORMATTER;

    public StringToLocalDateConverter(String pattern) {
    
    
        DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern(pattern);
    }

    @Override
    public LocalDate convert(String source) {
    
    
        return LocalDate.parse(source, DATE_TIME_FORMATTER);
    }

}

提供自定义类型转换器的集合

package com.qingyun.springframework.context.test.type;

import com.qingyun.springframework.beans.factory.FactoryBean;

import java.util.HashSet;
import java.util.Set;

/**
 * @description:
 * @author: 張青云
 * @create: 2021-08-28 21:57
 **/
public class ConvertersFactoryBean implements FactoryBean<Set<?>> {
    
    

    @Override
    public Set<?> getObject() throws Exception {
    
    
        HashSet<Object> converters = new HashSet<>();
        StringToLocalDateConverter stringToLocalDateConverter = new StringToLocalDateConverter("yyyy-MM-dd");
        converters.add(stringToLocalDateConverter);
        return converters;
    }

    @Override
    public Class<?> getObjectType() {
    
    
        return Set.class;
    }

    @Override
    public boolean isSingleton() {
    
    
        return true;
    }
}

XML配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
	         http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="husband" class="com.qingyun.springframework.context.test.type.Husband">
        <property name="wifiName" value="你猜"/>
        <property name="marriageDate" value="2021-08-08"/>
    </bean>

    <bean id="conversionService" class="com.qingyun.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters" ref="converters"/>
    </bean>

    <!--用户自定义类型转换器的集合-->
    <bean id="converters" class="com.qingyun.springframework.context.test.type.ConvertersFactoryBean"/>

</beans>

单元测试

    @Test
    public void test_convert() {
    
    
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:type-test.xml");
        Husband husband = applicationContext.getBean("husband", Husband.class);
        System.out.println("测试结果:" + husband);
    }

结果

在这里插入图片描述
可以发现类型转换成功!

扫描二维码关注公众号,回复: 13282279 查看本文章

猜你喜欢

转载自blog.csdn.net/zhang_qing_yun/article/details/119979086