【Spring】关于Spring 的类型转换 ConversionService TypeConverter 等

前言

Spring 框架层面的转换能力,主要一部分都是由 ConversionService 提供,本章节简单聊一下 Spring 转换服务相关:

  • 转换器 APIConverter ConverterFactory GenericConverter
  • 转换服务:ConversionService 系列
  • FormatterConverter 的整合
  • 统一转换服务出口 TypeConverter

转换器 API

Converter

@FunctionalInterface
public interface Converter<S, T> {

	@Nullable
	T convert(S source);

}
  • 很简单的一个函数式接口,S 转换为 T
  • 示例略

ConverterFactory

public interface ConverterFactory<S, R> {

	<T extends R> Converter<S, T> getConverter(Class<T> targetType);

}
  • 允许 S 转换为 R 子类集合,即 一对多 的转换
  • 可参考官方提供的实现如 NumberToNumberConverterFactory

ConditionalConverter

public interface ConditionalConverter {

	boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType);

}
  • matches 基于类型判断是否匹配
  • 后文提到的 GenericConverter 会大量使用该接口

GenericConverter

public interface GenericConverter {

	@Nullable
	Set<ConvertiblePair> getConvertibleTypes();

	@Nullable
	Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType);

	final class ConvertiblePair {

		private final Class<?> sourceType;

		private final Class<?> targetType;

		// ...
		
	}

}
  • 这是最灵活最复杂的一个转换器接口,因为它支持 多对多 的转换服务
  • 具体的转换类型由内部类 ConvertiblePair 维护,方法 getConvertibleTypes 返回该转换器支持的转换类型集合

转换服务

ConversionService

public interface ConversionService {

	boolean canConvert(@Nullable Class<?> sourceType, Class<?> targetType);
	boolean canConvert(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType);

	@Nullable
	<T> T convert(@Nullable Object source, Class<T> targetType);
	@Nullable
	Object convert(@Nullable Object source, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType);

}
  • canConvert,是否支持目标类型的转换
  • convert 由转换服务(选择对应的转换器)进行转换

ConverterRegistry

public interface ConverterRegistry {

	void addConverter(Converter<?, ?> converter);

	<S, T> void addConverter(Class<S> sourceType, Class<T> targetType, Converter<? super S, ? extends T> converter);
	
	void addConverter(GenericConverter converter);

	void addConverterFactory(ConverterFactory<?, ?> factory);

	void removeConvertible(Class<?> sourceType, Class<?> targetType);

}
  • XXXRegistry,注册(管理)中心的模式
  • 提供对 转换器 的注册与管理

ConfigurableConversionService

public interface ConfigurableConversionService extends ConversionService, ConverterRegistry {

}
  • 它的子类是一个 ConversionService,负责选择转换器进行对应类型的转换
  • 它的子类是一个 ConverterRegistry,负责维护一组 转换器

GenericConversionService

  • 转换服务的所有逻辑基本在这个类实现:转换器的维护、指定类型的转换等
  • 它的实现是否精巧,借助两个内部类:
    • Converts 维护 ConvertiblePairConvertersForPair 关系,即根据转换数据的类型获取 转换器 集合
    • ConvertersForPair 维护对应的 转换器 集合,即获取唯一一个 转换器 实例进行转换操作,这里获取的就是 符合条件 (比如 match 方法)的第一个 转换器
  • 细节过多就不展开了,感兴趣可以自己看下

DefaultConversionService

  • ConversionService 的默认实现
  • 没什么额外的逻辑,主要是默认注册了很多 转换器,基本可以应对所有普通的转换类型

格式化与类型转换的整合

Printer

@FunctionalInterface
public interface Printer<T> {

	String print(T object, Locale locale);

}

Parser

@FunctionalInterface
public interface Parser<T> {

	T parse(String text, Locale locale) throws ParseException;

}

Formatter

public interface Formatter<T> extends Printer<T>, Parser<T> {

}
  • 格式化,其实就可以看作一种类型转换:StringT 之间的转换
  • 所有可以理解为一个 Formatter 对应两个 转换器

FormatterRegistry

public interface FormatterRegistry extends ConverterRegistry {

	void addPrinter(Printer<?> printer);
	void addParser(Parser<?> parser);

	void addFormatter(Formatter<?> formatter);
	void addFormatterForFieldType(Class<?> fieldType, Formatter<?> formatter);
	void addFormatterForFieldType(Class<?> fieldType, Printer<?> printer, Parser<?> parser);
	void addFormatterForFieldAnnotation(AnnotationFormatterFactory<? extends Annotation> annotationFormatterFactory);

}
  • Formatter 的注册中心,它同时还是一个 ConverterRegistry,这里其实是一个组合的关系
  • 支持 PrinterParser 的单独注册以及 Formatter 的注册

FormattingConversionService

public class FormattingConversionService extends GenericConversionService
		implements FormatterRegistry, EmbeddedValueResolverAware {

	// ...

	// 对于 Printer 适配成 PrinterConverter 注册
	@Override
	public void addPrinter(Printer<?> printer) {
		Class<?> fieldType = getFieldType(printer, Printer.class);
		addConverter(new PrinterConverter(fieldType, printer, this));
	}

	// 对于 Parser 适配成 ParserConverter 注册
	@Override
	public void addParser(Parser<?> parser) {
		Class<?> fieldType = getFieldType(parser, Parser.class);
		addConverter(new ParserConverter(fieldType, parser, this));
	}

	// 一个 Formatter 对于两个 Converter
	@Override
	public void addFormatterForFieldType(Class<?> fieldType, Formatter<?> formatter) {
		addConverter(new PrinterConverter(fieldType, formatter, this));
		addConverter(new ParserConverter(fieldType, formatter, this));
	}

	// ...

}
  • 之前提到,Formatter 可以理解为 TString 类型的 ConverterFormattingConversionService 就依赖这个思想实现
  • 对于 PrinterParser 分别适配成 PrinterConverterParserConverter 注册,适配器设计模式 的经典场景
  • 注册方法 addConverter 由父类 GenericConversionService 提供,组合设计模式 的经典场景

DefaultFormattingConversionService

  • DefaultConversionService 的思路一样,同时也是 DefaultConversionService 的子类
  • DefaultConversionService 注册的转换器之上,再注册一些默认的 Formatter

TypeConverter

public interface TypeConverter {

	@Nullable
	<T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType) throws TypeMismatchException;
	@Nullable
	<T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType,
			@Nullable MethodParameter methodParam) throws TypeMismatchException;
	@Nullable
	<T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType, @Nullable Field field)
			throws TypeMismatchException;
	@Nullable
	default <T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType,
			@Nullable TypeDescriptor typeDescriptor) throws TypeMismatchException {
		throw new UnsupportedOperationException("TypeDescriptor resolution not supported");
	}

}
  • 除了 转换服务JDK 提供的 PropertyEditor 也提供类似的机制,TypeConverter 统一上述所有转换的出口
  • 子类 TypeConverterSupport 作为抽象基类,把上述方法的实现都委托给 TypeConverterDelegate
  • TypeConverterDelegate 再往下就是基于 PropertyEditorConversionService 进行转换了,细节不再深入
  • Spring 容器中的默认 TypeConverter 实例为 SimpleTypeConverter

总结

Spring 的数据转换在体现在方方面面:

  • 单纯的类型转换,比如 BeanFactory#getBean 方法的类型转换等
  • 数据绑定,比如 DataBinder 绑定数据时,必然也涉及类型的转换
  • 等等
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
TypeConverter是C#中一个非常有用的工具类,它可以将一个类型转换成另一个类型。ConvertFrom方法是TypeConverter类中的一个方法,可以将一个字符串表示的值转换成目标类型。下面是一个示例代码,演示了如何使用TypeConverter和ConvertFrom方法将字符串转换成枚举、泛型、颜色和字体属性: ```csharp using System; using System.ComponentModel; using System.Drawing; class Program { static void Main(string[] args) { // 将字符串转换成枚举类型 string enumValue = "Red"; Color color = (Color)TypeDescriptor.GetConverter(typeof(Color)).ConvertFrom(enumValue); Console.WriteLine(color); // 将字符串转换成泛型类型 string genericValue = "123"; int number = (int)TypeDescriptor.GetConverter(typeof(int)).ConvertFrom(genericValue); Console.WriteLine(number); // 将字符串转换成颜色类型 string colorValue = "255,0,0"; Color color2 = (Color)TypeDescriptor.GetConverter(typeof(Color)).ConvertFrom(colorValue); Console.WriteLine(color2); // 将字符串转换成字体类型 string fontValue = "Arial, 12pt"; Font font = (Font)TypeDescriptor.GetConverter(typeof(Font)).ConvertFrom(fontValue); Console.WriteLine(font.Name + ", " + font.Size); } } ``` 在上述代码中,我们首先使用TypeDescriptor获取Color、int、Font类的TypeConverter,并使用ConvertFrom方法将字符串转换成相应的类型。需要注意的是,在将字符串转换成泛型类型时,需要将字符串表示的值与目标类型的类型参数匹配。如果类型不匹配,将会抛出异常。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值