本文主要是介绍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的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!