交流
商城
MCN
登入
注册
首页
提问
分享
讨论
建议
公告
动态
发表新帖
发表新帖
spring核心第7-1 章:ConversionService
分享
未结
0
919
李延
LV6
2021-05-13
悬赏:20积分
# 作用 提供类型转换服务,可以将A类型数据转换为B类型数据。 # 主要实现与调用 主要实现为ApplicationConversionService 在启动springboot项目时。通过ApplicationConversionService.getSharedInstance()。向BeanFactory与Environment中设置相关对象,提供类型转换服务。 我们具体可以在TypeConverter中看到具体调用过程。 # 继承关系  ## ConversionService 类型转换服务接口。定义一下方法: - canConvert 判断两个类型间是否可以转换 - convert 类型类型 ## ConverterRegistry 转换器注册接口。定义了转换器的添加删除和查询功能。 **下面的类都是基于上面两个类的子类。** ## FormatterRegistry 添加对Formatter的注册,Formatter为格式化转换器。比如子类:YearFormatter,可以将字符串类型转换为Year类型。 //TODO 如果有必要在详细研究。 ## GenericConversionService 通用的转换服务 在说明这个类的方法前我们需要先说明和它相关的几个类的作用。这样我们才方便继续理解当前代码: Converter<?,?> GenericConverter ConvertiblePair Converters ### Converter 转换类。这个类有两个范型,代表着将数据从A类类型转换为B类型。这个接口只支持一组类型的转换。 ### GenericConverter 通用的转换类。这个类没有范型。支持多组类型的转换。 ### ConvertiblePair GenericConverter的子类。分装了转换时 原类型与目标类型。 ### Converters 保存多个GenericConverter。并通过转换类型查找适合当前转换的GenericConverter。 ** 下面我们继续说明GenericConversionService** ### addConverter ```java @Override public void addConverter(GenericConverter converter) { this.converters.add(converter); invalidateCache(); } ``` 我们可以看到其实就是将converter添加到conveters内 ### canConvert ```java @Override public boolean canConvert(@Nullable Class<?> sourceType, Class<?> targetType) { Assert.notNull(targetType, "Target type to convert to cannot be null"); return canConvert((sourceType != null ? TypeDescriptor.valueOf(sourceType) : null), TypeDescriptor.valueOf(targetType)); } @Override public boolean canConvert(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType) { Assert.notNull(targetType, "Target type to convert to cannot be null"); if (sourceType == null) { return true; } GenericConverter converter = getConverter(sourceType, targetType); return (converter != null); } @Nullable protected GenericConverter getConverter(TypeDescriptor sourceType, TypeDescriptor targetType) { ConverterCacheKey key = new ConverterCacheKey(sourceType, targetType); GenericConverter converter = this.converterCache.get(key); if (converter != null) { return (converter != NO_MATCH ? converter : null); } converter = this.converters.find(sourceType, targetType); if (converter == null) { converter = getDefaultConverter(sourceType, targetType); } if (converter != null) { this.converterCache.put(key, converter); return converter; } this.converterCache.put(key, NO_MATCH); return null; } ``` canConvert 也就时判断conveters内是否有符合当前类型的conveter ### convert ```java @Override @Nullable public Object convert(@Nullable Object source, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType) { Assert.notNull(targetType, "Target type to convert to cannot be null"); if (sourceType == null) { Assert.isTrue(source == null, "Source must be [null] if source type == [null]"); return handleResult(null, targetType, convertNullSource(null, targetType)); } if (source != null && !sourceType.getObjectType().isInstance(source)) { throw new IllegalArgumentException("Source to convert from must be an instance of [" + sourceType + "]; instead it was a [" + source.getClass().getName() + "]"); } GenericConverter converter = getConverter(sourceType, targetType); if (converter != null) { Object result = ConversionUtils.invokeConverter(converter, source, sourceType, targetType); return handleResult(sourceType, targetType, result); } return convert(source, sourceType, targetType); } ``` 我们看到类型转换就是获取到合适的转换器,并进行执行,同时handleResult 进行类型判断。 ## ApplicationConversionService 这个类是在父类基础上添加了一些默认的转换器,具体如下: ```java public static void addApplicationConverters(ConverterRegistry registry) { addDelimitedStringConverters(registry); registry.addConverter(new StringToDurationConverter()); registry.addConverter(new DurationToStringConverter()); registry.addConverter(new NumberToDurationConverter()); registry.addConverter(new DurationToNumberConverter()); registry.addConverter(new StringToPeriodConverter()); registry.addConverter(new PeriodToStringConverter()); registry.addConverter(new NumberToPeriodConverter()); registry.addConverter(new StringToDataSizeConverter()); registry.addConverter(new NumberToDataSizeConverter()); registry.addConverter(new StringToFileConverter()); registry.addConverter(new InputStreamSourceToByteArrayConverter()); registry.addConverterFactory(new LenientStringToEnumConverterFactory()); registry.addConverterFactory(new LenientBooleanToEnumConverterFactory()); } ``` 在mvc项目中,会加载 beanFactory的转换器。具体在mvc中说明 ```java public static void addBeans(FormatterRegistry registry, ListableBeanFactory beanFactory) { Set<Object> beans = new LinkedHashSet<>(); beans.addAll(beanFactory.getBeansOfType(GenericConverter.class).values()); beans.addAll(beanFactory.getBeansOfType(Converter.class).values()); beans.addAll(beanFactory.getBeansOfType(Printer.class).values()); beans.addAll(beanFactory.getBeansOfType(Parser.class).values()); for (Object bean : beans) { if (bean instanceof GenericConverter) { registry.addConverter((GenericConverter) bean); } else if (bean instanceof Converter) { registry.addConverter((Converter<?, ?>) bean); } else if (bean instanceof Formatter) { registry.addFormatter((Formatter<?>) bean); } else if (bean instanceof Printer) { registry.addPrinter((Printer<?>) bean); } else if (bean instanceof Parser) { registry.addParser((Parser<?>) bean); } } } ```
回帖
消灭零回复
提交回复
热议榜
java 相关知识分享
8
好的程序员与不好的程序员
6
写给工程师的十条精进原则
5
spring boot以jar包运行配置的logback日志文件没生成
5
一步一步分析SpringBoot启动源码(一)
5
MockMvc测试
5
【吐槽向】是不是有个吐槽的板块比较好玩
4
logstash jdbc同步mysql多表数据到elasticsearch
3
IntelliJ IDEA 优质License Server
3
.gitignore忽略规则
3
SpringBoot启动源码分析
3
一步一步分析SpringBoot启动源码(三)
3
2
一步一步分析SpringBoot启动源码(二)
2
积分不够将无法发表新帖
2
官方产品
Meta-Boot - 基于MCN
MCN - 快速构建SpringBoot应用
微信扫码关注公众号