18. Spring类型转换之ConversionService

2023-11-20 23:30

本文主要是介绍18. Spring类型转换之ConversionService,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

简介

前面我们讲了PropertyEditor,是jdk提供的类型转换,spring也有自己的类型转换器,比PropertyEditor稍微强大一点

快速使用

public class User {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}
}@Component
public class UserBean {@Value("xx")private User user;public User getUser() {return user;}
}public class String2UserConverter implements ConditionalGenericConverter {@Overridepublic boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {return sourceType.getType().equals(String.class) && targetType.getType().equals(User.class);}@Overridepublic Set<ConvertiblePair> getConvertibleTypes() {return Collections.singleton(new ConvertiblePair(String.class, User.class));}@Overridepublic Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {User user = new User();user.setName((String) source);return user;}
}@Configuration
public class ConvertConfig {@Beanpublic ConversionServiceFactoryBean conversionService() {ConversionServiceFactoryBean factoryBean = new ConversionServiceFactoryBean();factoryBean.setConverters(Collections.singleton(new String2UserConverter()));return factoryBean;}
}

定义如上类,值得注意的是ConversionServiceFactoryBean的方法名一定要是 conversionService

测试

public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);UserBean userBean = context.getBean("userBean", UserBean.class);System.out.println(userBean);System.out.println(userBean.getUser());System.out.println(userBean.getUser().getName());
}输出 com.shura.beans.UserBean@7225790e
com.shura.convert.User@54a097cc
xx

从上面的结果来看 ConversionService 也能做到类型转换

实现的地方跟PropertyEditor也差不多,下面看源码分析

源码分析

与PropertyEditor一样,也是在BeanWrapper中实现

// ConstructorResolver类
public BeanWrapper instantiateUsingFactoryMethod({BeanWrapperImpl bw = new BeanWrapperImpl();this.beanFactory.initBeanWrapper(bw);...
}// AbstractBeanFactory类
protected void initBeanWrapper(BeanWrapper bw) {bw.setConversionService(getConversionService()); // 下节分析registerCustomEditors(bw); // 注册PropertyEditor 
}

上面可以看出可以从beanFactory获取ConversionService到BeanWrapper

同样也是在 TypeConverterDelegate 判断是否有ConversionService

public <T> T convertIfNecessary(@Nullable String propertyName, @Nullable Object oldValue, @Nullable Object newValue,@Nullable Class<T> requiredType, @Nullable TypeDescriptor typeDescriptor) throws IllegalArgumentException {ConversionService conversionService = this.propertyEditorRegistry.getConversionService();if (editor == null && conversionService != null && newValue != null && typeDescriptor != null) {TypeDescriptor sourceTypeDesc = TypeDescriptor.forObject(newValue);if (conversionService.canConvert(sourceTypeDesc, typeDescriptor)) {try {return (T) conversionService.convert(newValue, sourceTypeDesc, typeDescriptor);}catch (ConversionFailedException ex) {// fallback to default conversion logic belowconversionAttemptEx = ex;}}}}

上面就是ConversionService的处理逻辑,那么ConversionService应该也有默认的类型转换器,在哪里设置的呢

进入ConversionServiceFactoryBean,它是一个FactoryBean,真正的对象是getObject返回的GenericConversionService,该属性由createConversionService方法创建,实际上就是实例化了一个DefaultConversionService

public class ConversionServiceFactoryBean implements FactoryBean<ConversionService>, InitializingBean {@Nullableprivate Set<?> converters;@Nullableprivate GenericConversionService conversionService;public void setConverters(Set<?> converters) {this.converters = converters;}@Overridepublic void afterPropertiesSet() {this.conversionService = createConversionService();ConversionServiceFactory.registerConverters(this.converters, this.conversionService);}protected GenericConversionService createConversionService() {return new DefaultConversionService();}@Override@Nullablepublic ConversionService getObject() {return this.conversionService;}@Overridepublic Class<? extends ConversionService> getObjectType() {return GenericConversionService.class;}}

那么DefaultConversionService做了什么呢

public class DefaultConversionService extends GenericConversionService {@Nullableprivate static volatile DefaultConversionService sharedInstance;public DefaultConversionService() {addDefaultConverters(this);}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));}public static void addCollectionConverters(ConverterRegistry converterRegistry) {ConversionService conversionService = (ConversionService) converterRegistry;converterRegistry.addConverter(new ArrayToCollectionConverter(conversionService));converterRegistry.addConverter(new CollectionToArrayConverter(conversionService));converterRegistry.addConverter(new ArrayToArrayConverter(conversionService));converterRegistry.addConverter(new CollectionToCollectionConverter(conversionService));converterRegistry.addConverter(new MapToMapConverter(conversionService));converterRegistry.addConverter(new ArrayToStringConverter(conversionService));converterRegistry.addConverter(new StringToArrayConverter(conversionService));converterRegistry.addConverter(new ArrayToObjectConverter(conversionService));converterRegistry.addConverter(new ObjectToArrayConverter(conversionService));converterRegistry.addConverter(new CollectionToStringConverter(conversionService));converterRegistry.addConverter(new StringToCollectionConverter(conversionService));converterRegistry.addConverter(new CollectionToObjectConverter(conversionService));converterRegistry.addConverter(new ObjectToCollectionConverter(conversionService));converterRegistry.addConverter(new StreamConverter(conversionService));}private static void addScalarConverters(ConverterRegistry converterRegistry) {converterRegistry.addConverterFactory(new NumberToNumberConverterFactory());converterRegistry.addConverterFactory(new StringToNumberConverterFactory());converterRegistry.addConverter(Number.class, String.class, new ObjectToStringConverter());converterRegistry.addConverter(new StringToCharacterConverter());converterRegistry.addConverter(Character.class, String.class, new ObjectToStringConverter());converterRegistry.addConverter(new NumberToCharacterConverter());converterRegistry.addConverterFactory(new CharacterToNumberFactory());converterRegistry.addConverter(new StringToBooleanConverter());converterRegistry.addConverter(Boolean.class, String.class, new ObjectToStringConverter());converterRegistry.addConverterFactory(new StringToEnumConverterFactory());converterRegistry.addConverter(new EnumToStringConverter((ConversionService) converterRegistry));converterRegistry.addConverterFactory(new IntegerToEnumConverterFactory());converterRegistry.addConverter(new EnumToIntegerConverter((ConversionService) converterRegistry));converterRegistry.addConverter(new StringToLocaleConverter());converterRegistry.addConverter(Locale.class, String.class, new ObjectToStringConverter());converterRegistry.addConverter(new StringToCharsetConverter());converterRegistry.addConverter(Charset.class, String.class, new ObjectToStringConverter());converterRegistry.addConverter(new StringToCurrencyConverter());converterRegistry.addConverter(Currency.class, String.class, new ObjectToStringConverter());converterRegistry.addConverter(new StringToPropertiesConverter());converterRegistry.addConverter(new PropertiesToStringConverter());converterRegistry.addConverter(new StringToUUIDConverter());converterRegistry.addConverter(UUID.class, String.class, new ObjectToStringConverter());}}

就是添加了一堆的默认转换器,到这基本上就能知道spring的转换机制了,以及如何实现自己的转换器

还有个小问题就是前面说了注册ConversionServiceFactoryBean的方法名一定要是 conversionService,Why?

请看如下代码,在实例化非懒加载单例Bean之前就会获取ConversionService设置到beanFactory,而这个名字就只能叫conversionService

org.springframework.context.support.AbstractApplicationContext#finishBeanFactoryInitialization

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {String CONVERSION_SERVICE_BEAN_NAME = "conversionService";if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {beanFactory.setConversionService(beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));}// 实例化非懒加载的单例BeanbeanFactory.preInstantiateSingletons();
}

ConversionService就介绍到这


欢迎关注,学习不迷路!

这篇关于18. Spring类型转换之ConversionService的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/398213

相关文章

JAVA中安装多个JDK的方法

《JAVA中安装多个JDK的方法》文章介绍了在Windows系统上安装多个JDK版本的方法,包括下载、安装路径修改、环境变量配置(JAVA_HOME和Path),并说明如何通过调整JAVA_HOME在... 首先去oracle官网下载好两个版本不同的jdk(需要登录Oracle账号,没有可以免费注册)下载完

Spring StateMachine实现状态机使用示例详解

《SpringStateMachine实现状态机使用示例详解》本文介绍SpringStateMachine实现状态机的步骤,包括依赖导入、枚举定义、状态转移规则配置、上下文管理及服务调用示例,重点解... 目录什么是状态机使用示例什么是状态机状态机是计算机科学中的​​核心建模工具​​,用于描述对象在其生命

Spring Boot 结合 WxJava 实现文章上传微信公众号草稿箱与群发

《SpringBoot结合WxJava实现文章上传微信公众号草稿箱与群发》本文将详细介绍如何使用SpringBoot框架结合WxJava开发工具包,实现文章上传到微信公众号草稿箱以及群发功能,... 目录一、项目环境准备1.1 开发环境1.2 微信公众号准备二、Spring Boot 项目搭建2.1 创建

Java中Integer128陷阱

《Java中Integer128陷阱》本文主要介绍了Java中Integer与int的区别及装箱拆箱机制,重点指出-128至127范围内的Integer值会复用缓存对象,导致==比较结果为true,下... 目录一、Integer和int的联系1.1 Integer和int的区别1.2 Integer和in

SpringSecurity整合redission序列化问题小结(最新整理)

《SpringSecurity整合redission序列化问题小结(最新整理)》文章详解SpringSecurity整合Redisson时的序列化问题,指出需排除官方Jackson依赖,通过自定义反序... 目录1. 前言2. Redission配置2.1 RedissonProperties2.2 Red

IntelliJ IDEA2025创建SpringBoot项目的实现步骤

《IntelliJIDEA2025创建SpringBoot项目的实现步骤》本文主要介绍了IntelliJIDEA2025创建SpringBoot项目的实现步骤,文中通过示例代码介绍的非常详细,对大家... 目录一、创建 Spring Boot 项目1. 新建项目2. 基础配置3. 选择依赖4. 生成项目5.

JSONArray在Java中的应用操作实例

《JSONArray在Java中的应用操作实例》JSONArray是org.json库用于处理JSON数组的类,可将Java对象(Map/List)转换为JSON格式,提供增删改查等操作,适用于前后端... 目录1. jsONArray定义与功能1.1 JSONArray概念阐释1.1.1 什么是JSONA

Java JDK1.8 安装和环境配置教程详解

《JavaJDK1.8安装和环境配置教程详解》文章简要介绍了JDK1.8的安装流程,包括官网下载对应系统版本、安装时选择非系统盘路径、配置JAVA_HOME、CLASSPATH和Path环境变量,... 目录1.下载JDK2.安装JDK3.配置环境变量4.检验JDK官网下载地址:Java Downloads

Spring boot整合dubbo+zookeeper的详细过程

《Springboot整合dubbo+zookeeper的详细过程》本文讲解SpringBoot整合Dubbo与Zookeeper实现API、Provider、Consumer模式,包含依赖配置、... 目录Spring boot整合dubbo+zookeeper1.创建父工程2.父工程引入依赖3.创建ap

SpringBoot结合Docker进行容器化处理指南

《SpringBoot结合Docker进行容器化处理指南》在当今快速发展的软件工程领域,SpringBoot和Docker已经成为现代Java开发者的必备工具,本文将深入讲解如何将一个SpringBo... 目录前言一、为什么选择 Spring Bootjavascript + docker1. 快速部署与