Spring 源码解析 | 类型转换

648 阅读1分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

Spring 内部,有很多地方可能需要将 String 转换为其他类型,今天我们一起来学习一下 PropertyEditor、 ConversionService、TypeConverter 三种类型转换的使用。

PropertyEditor

PropertyEditor 是 JDK 提供的类型转换器,首先创建 bean :

@Service
public class OrderItemService {

	@Value("orderVal")
	private Order order;

	public void test() {
		System.out.println("test order : " + order);
	}
}

创建类型转换器,将字符串转换为 Order 实例对象。

public class String2ObjectPropertyEditor extends PropertyEditorSupport implements PropertyEditor {

	@Override
	public void setAsText(String text) throws IllegalArgumentException {
		Order order = new Order();
		order.setName("haha");
		order.setAge(12);
		this.setValue(order);
	}
}

注册转换器以及测试代码:

@Import({OrderItemService.class})
@Configuration
public class PropertyEditorTest {


	@Bean
	public CustomEditorConfigurer customEditorConfigurer() {
		Map<Class<?>, Class<? extends PropertyEditor>> customEditors = new HashMap<>();
		customEditors.put(Order.class, String2ObjectPropertyEditor.class);

		CustomEditorConfigurer customEditorConfigurer = new CustomEditorConfigurer();
		customEditorConfigurer.setCustomEditors(customEditors);

		return customEditorConfigurer;
	}

	public static void main(String[] args) {
		ApplicationContext applicationContext = new AnnotationConfigApplicationContext(PropertyEditorTest.class);
		OrderItemService orderItemService = applicationContext.getBean(OrderItemService.class);
		orderItemService.test();
	}

}

ConversionService

ConversionService 是 Sprign 中提供的类型转换器,它比 PrppertyEditor 功能更加强大。 定义转换器:

public class String2ObjectConversionService implements ConditionalGenericConverter {

	@Override
	public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
		return
				Objects.equals(sourceType.getType(), String.class)
						&&
						Objects.equals(targetType.getType(), Order.class);
	}

	@Override
	public Set<ConvertiblePair> getConvertibleTypes() {
		return Collections.singleton(new ConvertiblePair(String.class, Order.class));
	}


	@Override
	public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
		return new Order("haha", 32);
	}
}

在 Spring 中使用:

@Bean
public ConversionServiceFactoryBean conversionService() {

    ConversionServiceFactoryBean conversionServiceFactoryBean = new ConversionServiceFactoryBean();
    conversionServiceFactoryBean.setConverters(Collections.singleton(new String2ObjectConversionService()));

    return conversionServiceFactoryBean;
}

Bean 的注入和调用代码:

// 测试和注入
@Service
public class OrderItemService {

    //通过 @Value 注入
	@Value("orderVal")
	private Order order;

	public void test() {
		System.out.println("test order : " + order);
	}
}


// 调用代码
ApplicationContext appliciton = new AnnotationConfigApplicationContext(ConvertTest.class);
OrderItemService orderItemService = appliciton.getBean(OrderItemService.class);
orderItemService.test();

TypeConverter

TypeConverter 整合了 PropertyEditor 和 ConversionService, 在 Spring 内部使用:

SimpleTypeConverter typeConverter = new SimpleTypeConverter();
typeConverter.registerCustomEditor(Order.class, new String2ObjectPropertyEditor());
Order order = typeConverter.convertIfNecessary("orderVal", Order.class);
System.out.println(order);

比如在 AbstractBeanFacotry#adaptBeanInstance 中也有用到:

// AbstractBeanFacotry.java

<T> T adaptBeanInstance(String name, Object bean, @Nullable Class<?> requiredType) {
    // Check if required type matches the type of the actual bean instance.
    // 如果转换类型不为空,并且 bean 类型与目标类型不匹配
    if (requiredType != null && !requiredType.isInstance(bean)) {
        try {
            // 尝试转换
            Object convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
            if (convertedBean == null) {
                throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
            }
            return (T) convertedBean;
        }
        catch (TypeMismatchException ex) {
            if (logger.isTraceEnabled()) {
                logger.trace("Failed to convert bean '" + name + "' to required type '" +
                             ClassUtils.getQualifiedName(requiredType) + "'", ex);
            }
            throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
        }
    }
    return (T) bean;
}

参考资料