Spring中的ConversionService源码解析

 更新时间:2023年11月30日 09:45:16   作者:啊几  
这篇文章主要介绍了Spring中的ConversionService源码解析,ConversionService是类型转换服务的接口,从名字就可以看出ConverterRegistry是要实现转换器注册表的接口,添加和移除Converter和GenericConverter,需要的朋友可以参考下

ConversionService是什么

ConversionService是类型转换服务的接口,最涉及的类有以下:

在这里插入图片描述

学习类型转换服务之前我们先看看各个接口是做什么的

ConversionService接口

ConversionService接口的方法很简单,就是判断是否可以两种类型是否可以转换,和转换方法

在这里插入图片描述

ConversionRegistry接口

从名字就可以看出ConverterRegistry是要实现转换器注册表的接口,添加和移除Converter和GenericConverter。

在这里插入图片描述

FormatterRegistry接口

FormatterRegistry接口是ConverterRegistry的子接口

在这里插入图片描述

在这里插入图片描述

在学这个接口之前要先了解Formatter是什么?

Formatter是什么?

Formatter是一种用于格式化和解析对象的接口,它可以将一个对象转化为字符串,或将一个字符串转化为特定类型的对象。在Spring MVC中,Formatter通常用于将HTTP请求中的参数绑定到Java对象上,或将Java对象转化为HTTP响应中的数据。

在这里插入图片描述

Formatter接口继承了Printer和Parse两个接口

public interface Printer<T> {

	String print(T object, Locale locale);
	
}
public interface Parser<T> {

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

}

Printer接口就是对象转换为String类型的接口,Parse接口就是将String类型转换为特定类型对象的接口。在Spring中Formatter接口的实现也是非常多

在这里插入图片描述

所以如果不需要使用String类型和对象类型的转换,使用GenericConversionService或DefaultConversionService就可以了

ConfigurableConversionService接口

ConfigurableConversionService继承了ConversionService和ConversionRegistry接口,从类型转换服务涉及的类可以看出ConversionService类型转换服务都是需要和ConverterRegistry转换器注册表接口配合使用的。所以ConversionService的实现类都是实现了ConfigurableConversionService接口的。

在这里插入图片描述

Converter和GenericConverter的区别

Converter是一个通用的类型转换器,它可以将一个类型转换为另一个类型。它只能转换一种类型,因此需要为每种类型都定义一个Converter。

GenericConverter是一个更通用的类型转换器,它可以将多种类型转换为多种类型。它可以处理多种不同的类型转换场景,因此可以减少定义Converter的数量。GenericConverter可以在转换过程中使用类型信息来决定如何转换。

总的来说,Converter适用于单一类型转换,而GenericConverter适用于多种类型转换。 GenericConversionService也提供了一个内部类ConverterAdapter,用来将Converter适配成GenericConverter,这里用了适配器模式

ConversionService的各个实现类有什么区别?又该如何选择呢?

首先看DefaultFormattingConversionService的构造方法,里面通过DefaultConversionService的静态方法添加了默认的一些Converter还有一些默认的Formatter,可以猜测到DefaultFormattingConversionService比DefaultConversionService多添加了默认的Formatter

public DefaultFormattingConversionService(
			@Nullable StringValueResolver embeddedValueResolver, boolean registerDefaultFormatters) {

		if (embeddedValueResolver != null) {
			setEmbeddedValueResolver(embeddedValueResolver);
		}
		DefaultConversionService.addDefaultConverters(this);
		if (registerDefaultFormatters) {
			addDefaultFormatters(this);
		}
	}

下面是默认添加的一些Converter

	public static void addDefaultConverters(ConverterRegistry converterRegistry) {
		addScalarConverters(converterRegistry);
		addCollectionConverters(converterRegistry);

		converterRegistry.addConverter(new ByteBufferConverter((ConversionService) converterRegistry));
		converterRegistry.addConverter(new StringToTimeZoneConverter());
		converterRegistry.addConverter(new ZoneIdToTimeZoneConverter());
		converterRegistry.addConverter(new ZonedDateTimeToCalendarConverter());

		converterRegistry.addConverter(new ObjectToObjectConverter());
		converterRegistry.addConverter(new IdToEntityConverter((ConversionService) converterRegistry));
		converterRegistry.addConverter(new FallbackObjectToStringConverter());
		converterRegistry.addConverter(new ObjectToOptionalConverter((ConversionService) converterRegistry));
	}

下面是默认添加的一些Formatter

	public static void addDefaultFormatters(FormatterRegistry formatterRegistry) {
		// Default handling of number values
		formatterRegistry.addFormatterForFieldAnnotation(new NumberFormatAnnotationFormatterFactory());

		// Default handling of monetary values
		if (jsr354Present) {
			formatterRegistry.addFormatter(new CurrencyUnitFormatter());
			formatterRegistry.addFormatter(new MonetaryAmountFormatter());
			formatterRegistry.addFormatterForFieldAnnotation(new Jsr354NumberFormatAnnotationFormatterFactory());
		}

		// Default handling of date-time values

		// just handling JSR-310 specific date and time types
		new DateTimeFormatterRegistrar().registerFormatters(formatterRegistry);

		if (jodaTimePresent) {
			// handles Joda-specific types as well as Date, Calendar, Long
			new org.springframework.format.datetime.joda.JodaTimeFormatterRegistrar().registerFormatters(formatterRegistry);
		}
		else {
			// regular DateFormat-based Date, Calendar, Long converters
			new DateFormatterRegistrar().registerFormatters(formatterRegistry);
		}
	}

所以如果要使用Spring自带的一些Formatter和Converter可以使用DefaultFormattingConversionService比DefaultConversionService,如果不需要可以使用FormatterConversionService或GenericConversionService。

ConversionService的使用示例

	public static void main(String[] args) {

		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
		UserService userService = (UserService) applicationContext.getBean("userService");

		FormattingConversionService conversionService = new DefaultFormattingConversionService();
		
		//String -> ArrayList
		System.out.println(conversionService.convert("1,2,3,4", ArrayList.class));
		
		//boolean -> String
		System.out.println(conversionService.convert(true,String.class));
		
		//自定义了一个格式化器,OrderService -> String ,String -> OrderService
		conversionService.addFormatter(new Formatter<OrderService>() {
			private ObjectMapper objectMapper = new ObjectMapper();
			@Override
			public String print(OrderService object, Locale locale) {
				try {
					return objectMapper.writeValueAsString(object);
				} catch (JsonProcessingException e) {
					throw new RuntimeException(e);
				}
			}

			@Override
			public OrderService parse(String text, Locale locale) throws ParseException {
				try {
					return  objectMapper.readValue(text,OrderService.class);
				} catch (JsonProcessingException e) {
					throw new RuntimeException(e);
				}
			}
		});
		String result = conversionService.convert(userService.getOrderService(),String.class);
		System.out.println(result);
		OrderService orderService = conversionService.convert(result, OrderService.class);
		System.out.println(orderService);
	}


测试结果

[1, 2, 3, 4]
true
{"user":{}}
com.zhouyu.service.OrderService@2bbf180e

到此这篇关于Spring中的ConversionService源码解析的文章就介绍到这了,更多相关ConversionService源码解析内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java中checkbox实现跨页多选的方法

    Java中checkbox实现跨页多选的方法

    最近做了一个项目其中遇到这样的需求,要实现checkbox跨页多选功能,经过小编整理,顺利解决,今天小编给大家分享Java中checkbox实现跨页多选的方法,需要的的朋友参考下
    2017-01-01
  • Java如何获取视频文件的视频时长

    Java如何获取视频文件的视频时长

    文章介绍了如何使用Java获取视频文件的视频时长,包括导入maven依赖和代码案例,同时,也讨论了在运行过程中遇到的SLF4J加载问题,并给出了解决方案
    2025-02-02
  • 使用Java实现验证码程序

    使用Java实现验证码程序

    这篇文章主要为大家详细介绍了使用Java实现验证码程序,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-04-04
  • MybatisPlus代码生成器含XML文件详解

    MybatisPlus代码生成器含XML文件详解

    这篇文章主要介绍了MybatisPlus代码生成器含XML文件详解,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-01-01
  • Java中字符编码问题的解决方法详解

    Java中字符编码问题的解决方法详解

    在日常 Java 开发中,字符编码问题是一个非常常见却又特别容易踩坑的地方,这篇文章就带你一步一步看清楚字符编码的来龙去脉,并结合可运行的代码,看看如何在 Java 项目里彻底解决编码不一致的问题
    2025-09-09
  • java中throws与try...catch的区别点

    java中throws与try...catch的区别点

    在本篇文章里小编给大家整理了一篇关于java中throws与try...catch的区别点的内容,需要的朋友们跟着学习下。
    2020-02-02
  • JDK8中String的intern()方法实例详细解读

    JDK8中String的intern()方法实例详细解读

    String字符串在我们日常开发中最常用的,当然还有他的两个兄弟StringBuilder和StringBuilder,接下来通过本文给大家介绍JDK8中String的intern()方法详细解读,需要的朋友可以参考下
    2022-09-09
  • SpringCloud使用logback日志框架教程详解

    SpringCloud使用logback日志框架教程详解

    Logback是一个功能强大的日志框架,它是一个基于slf4j的日志系统,提供了可靠的日志服务,比log4j更快,更灵活,更容易使用。本文将教会你快速让你的项目集成logback日志框架,需要的朋友可以参考下
    2023-05-05
  • Mybatis-plus数据权限DataPermissionInterceptor实现

    Mybatis-plus数据权限DataPermissionInterceptor实现

    本文主要介绍了Mybatis-plus数据权限DataPermissionInterceptor实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-07-07
  • Java HashMap从链表到红黑树的"进化"过程详解

    Java HashMap从链表到红黑树的"进化"过程详解

    在Java集合框架中,HashMap的底层实现在JDK 1.8迎来了一次重大革新:引入了红黑树,本文将结合底层源码,带你彻底搞懂HashMap是在什么条件下、如何进行树化的,感兴趣的朋友跟随小编一起看看吧
    2026-02-02

最新评论