Sping源码(九)—— Bean的初始化(非懒加载)— ConversionService

序言

经过前面一系列的加载、解析等准备工作,此刻refresh方法的执行已经来到了尾声,接下来我们用几篇文章着重的介绍一下Bean的初始化

代码

着重看refresh()主流程中的finishBeanFactoryInitialization()方法。
finishBeanFactoryInitialization
方法首先会判断beanFactory中是否包含ConversionService,并设置属性。

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {// Initialize conversion service for this context.// 如果包含ConversionService,则赋值给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));}//省略部分源码...}

扩展:ConversionService

我们经常会在页面进行各种各样的输入 abcd,1234等 这些输入是如何变换成指定的类型的呢?。
看看beanFacroty设置的ConversionService是什么?如果我们想要自定义ConversionService改如何实现?

ConversionService
Spring的提供的ConversionService接口,里面包含判断canConvert()方法判断是否可以进行类型转换,convert方法进行类型的转换。接口的实现类有很多,我们主要看DefaultConversionService即可。

/*** 类型转换服务*/
public interface ConversionService {/***  判断sourceType是否能转换成targetType*/boolean canConvert(@Nullable Class<?> sourceType, Class<?> targetType);boolean canConvert(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType);@Nullable<T> T convert(@Nullable Object source, Class<T> targetType);@NullableObject convert(@Nullable Object source, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType);
}

DefaultConversionService
DefaultConversionService下分别有addDefaultConvertersaddCollectionConvertersaddScalarConverters三个方法,会在DefaultConversionService初始化时添加各种类型的Converter,以便我们使用时直接拿。我们看一下源码:

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 StringToTimeZoneConverter());//添加各种Converter。。。。}public static void addCollectionConverters(ConverterRegistry converterRegistry) {ConversionService conversionService = (ConversionService) converterRegistry;converterRegistry.addConverter(new ArrayToCollectionConverter(conversionService));//添加各种Converter。。。。}private static void addScalarConverters(ConverterRegistry converterRegistry) {//省略部分源码converterRegistry.addConverterFactory(new StringToNumberConverterFactory());//添加各种ConverterFacroty。。。。}
}

Converter接口

addDefaultConverters方法。
StrinToimeZoneConverter
类继承了Converter,而Converter接口中的convert方法会将参数S 转换成 T类型

class StringToTimeZoneConverter implements Converter<String, TimeZone> {@Overridepublic TimeZone convert(String source) {return StringUtils.parseTimeZoneString(source);}
}@FunctionalInterface
public interface Converter<S, T> {/** S 转换成 T类型* Convert the source object of type {@code S} to target type {@code T}.* @param source the source object to convert, which must be an instance of {@code S} (never {@code null})* @return the converted object, which must be an instance of {@code T} (potentially {@code null})* @throws IllegalArgumentException if the source cannot be converted to the desired target type*/@NullableT convert(S source);
}

ConditionalGenericConverter

addCollectionConverters方法。
ArrayToCollectionConverter
类继承关系
ArrayToCollectionConverter -》ConditionalGenericConverter -》 GenericConverter(ConditionalConverter)

其中ConditionalConverter接口中的match方法可以理解成@Confitional注解,根据传入的 sourceType 和 targetType 来判断是否符合转换。

GenericConverter中的convert方法,会将 source 通过 sourceType的描述 转换成 targetType类型

final class ArrayToCollectionConverter implements ConditionalGenericConverter {@Overridepublic Set<ConvertiblePair> getConvertibleTypes() {return Collections.singleton(new ConvertiblePair(Object[].class, Collection.class));}@Overridepublic boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {return ConversionUtils.canConvertElements(sourceType.getElementTypeDescriptor(), targetType.getElementTypeDescriptor(), this.conversionService);}public Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {// 。。。。。。。省略}
}
public interface ConditionalGenericConverter extends GenericConverter, ConditionalConverter {}
public interface ConditionalConverter {boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType);
}
public interface GenericConverter {/*** Return the source and target types that this converter can convert between.* <p>Each entry is a convertible source-to-target type pair.* <p>For {@link ConditionalConverter conditional converters} this method may return* {@code null} to indicate all source-to-target pairs should be considered.*/@NullableSet<ConvertiblePair> getConvertibleTypes();/*** Convert the source object to the targetType described by the {@code TypeDescriptor}.* @param source the source object to convert (may be {@code null})* @param sourceType the type descriptor of the field we are converting from* @param targetType the type descriptor of the field we are converting to* @return the converted object*/@NullableObject convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType);/*** suorceType 和 targetType的键值对* Holder for a source-to-target class pair.*/final class ConvertiblePair {private final Class<?> sourceType;private final Class<?> targetType;public ConvertiblePair(Class<?> sourceType, Class<?> targetType) {this.sourceType = sourceType;this.targetType = targetType;}public Class<?> getSourceType() {return this.sourceType;}public Class<?> getTargetType() {return this.targetType;}}
}

TypeDescriptor
包含常见基础的类型类和包装类。

public class TypeDescriptor implements Serializable {private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0];private static final Map<Class<?>, TypeDescriptor> commonTypesCache = new HashMap<>(32);private static final Class<?>[] CACHED_COMMON_TYPES = {boolean.class, Boolean.class, byte.class, Byte.class, char.class, Character.class,double.class, Double.class, float.class, Float.class, int.class, Integer.class,long.class, Long.class, short.class, Short.class, String.class, Object.class};static {for (Class<?> preCachedClass : CACHED_COMMON_TYPES) {commonTypesCache.put(preCachedClass, valueOf(preCachedClass));}}
}

ConverterFactory

StringToNumberConverterFactory

final class StringToNumberConverterFactory implements ConverterFactory<String, Number> {@Overridepublic <T extends Number> Converter<String, T> getConverter(Class<T> targetType) {return new StringToNumber<>(targetType);}private static final class StringToNumber<T extends Number> implements Converter<String, T> {private final Class<T> targetType;public StringToNumber(Class<T> targetType) {this.targetType = targetType;}@Overridepublic T convert(String source) {if (source.isEmpty()) {return null;}return NumberUtils.parseNumber(source, this.targetType);}}
}

ConverterFactory
ConverterFactory转换会支持将 S 转换成 T 类型 (T instance of R)。

public interface ConverterFactory<S, R> {/*** 获取转换器** Get the converter to convert from S to target type T, where T is also an instance of R.* @param <T> the target type* @param targetType the target type to convert to* @return a converter from S to T*/<T extends R> Converter<S, T> getConverter(Class<T> targetType);
}

图解

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/16920.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JAVA开发 利用代码生成奖状

通过java实现用模板生成奖状 1、图片模板2、实现代码3、生成模板 1、图片模板 2、实现代码 import javax.imageio.ImageIO; import java.awt.*; import java.awt.font.TextAttribute; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException;…

三坐标测量机在汽车零部件质量控制中的应用

高质量的零部件能够确保汽车的性能达到设计标准&#xff0c;包括动力性能、燃油效率、操控稳定性等&#xff0c;从而提供更好的驾驶体验&#xff0c;建立消费者对汽车品牌的信任&#xff1b;也推动了汽车行业的技术创新&#xff0c;制造商不断研发新材料、新工艺&#xff0c;以…

Java 登录错误次数限制,用户禁登1小时

手机号验证码登录&#xff0c;验证码输入错误次数超5次封禁 Overridepublic boolean checkCaptcha(String phoneNum, String captcha) {String codeNum (String) redisTemplate.opsForValue().get(UserCacheNames.USER_CAPTCHA phoneNum);if (codeNum null) {throw new Wan…

怎么图片转excel表格免费?介绍三个方法

怎么图片转excel表格免费&#xff1f;在日常工作中&#xff0c;我们经常需要将图片中的表格数据转化为可编辑的Excel格式。幸运的是&#xff0c;市面上有多款软件支持这一功能&#xff0c;并且部分软件还提供免费使用的选项。本文将为您详细介绍几款可以免费将图片转换为Excel表…

Java 异步编程——Java内置线程调度器(Executor 框架)

文章目录 Java多线程的两级调度模型Executor 框架Executor 框架的组成概念Executor 框架中任务执行的两个阶段&#xff1a;任务提交和任务执行 在 Java1.5 以前&#xff0c;开发者必须手动实现自己的线程池&#xff1b;从 Java1.5 开始&#xff0c;Java 内部提供了线程池。 在J…

Python代码:十九、列表的长度

1、题目 描述&#xff1a; 牛牛学会了使用list函数与split函数将输入的连续字符串封装成列表&#xff0c;你能够帮他使用len函数统计一些公输入了多少字符串&#xff0c;列表中有多少元素吗&#xff1f; 输入描述&#xff1a; 输入一行多个字符串&#xff0c;字符串之间通过…

基于Java+SpringBoot+Mybaties-plus+Vue+elememt + uniapp 驾校预约平台 的设计与实现

一.项目介绍 系统角色&#xff1a;管理员、教练、学员 小程序(仅限于学员注册、登录)&#xff1a; 查看管理员发布的公告信息 查看管理员发布的驾校信息 查看所有教练信息、预约(需教练审核)、评论、收藏喜欢的教练 查看管理员发布的考试信息、预约考试(需管理…

流媒体内网穿透/组网/视频协议转换EasyNTS上云网关如何更改密码?

EasyNTS上云网关的主要作用是解决异地视频共享/组网/上云的需求&#xff0c;网页对域名进行添加映射时&#xff0c;添加成功后会生成一个外网访问地址&#xff0c;在浏览器中输入外网访问地址&#xff0c;即可查看内网应用。无需开放端口&#xff0c;EasyNTS上云网关平台会向Ea…

【linux】深入了解线程池:基本概念与代码实例(C++)

文章目录 1. 前言1.1 概念1.2 应用场景1.3 线程池的种类1.4 线程池的通常组成 2. 代码示例2.1 log.hpp2.2 lockGuard.hpp① pthread_mutex_t 2.3 Task.hpp2.4 thread.hpp2.5 threadPool.hpp① 基本框架② 成员变量③ 构造函数④ 其余功能函数&#xff1a; main.cc结果演示 完整…

动态规划-似包非包问题

组合总和 Ⅳ&#xff08;377&#xff09; 题目描述&#xff1a; 状态表示&#xff1a; 我们看到这题发现有一个限制条件就是目标整数target并且此时数组中的数字是可以重复选择的&#xff0c;这时候不难联想到前面学习的完全背包问题&#xff0c;这题好像符合完全背包问题的…

关于linux磁盘告警问题

案例&#xff1a;我们在执行df命令时&#xff0c;查看到磁盘利用率很高&#xff0c;但是到相对应的目录执行du -sh *来找大文件时进行删除时&#xff0c;发现各个目录相加并不大&#xff0c;如下图&#xff1a; 使用df命令查看到根(/)目录使用到33G&#xff0c;而du命令显示只使…

FuTalk设计周刊-Vol.050

#AI漫谈 热点捕手 1.Canva 宣布收购 Affinity 创意套件 平面设计平台 Canva 于 3 月 26 日宣布收购知名设计软件 Affinity 以“迎战”Adobe&#xff0c;不过此后许多设计师开始担心原本采用“永久授权”付费方案的 Affinity 系列软件是否会转为订阅制&#xff0c;而目前 Canv…

Android Studio开发之路(十四)自定义Titlebar以及设置顶部状态栏颜色

一、描述 项目需求&#xff0c;我要做一个下图这样的titlebar,包括一个返回按钮&#xff0c;一个关闭按钮&#xff0c;一个文本框。默认的titlebar按钮设计不太满足我的需求&#xff0c;于是我打算自定义一个titlebar组件&#xff0c;应用到我的每一个页面 二、titlebar组件设…

【NumPy】关于numpy.searchsorted()函数,看这一篇文章就够了

&#x1f9d1; 博主简介&#xff1a;阿里巴巴嵌入式技术专家&#xff0c;深耕嵌入式人工智能领域&#xff0c;具备多年的嵌入式硬件产品研发管理经验。 &#x1f4d2; 博客介绍&#xff1a;分享嵌入式开发领域的相关知识、经验、思考和感悟&#xff0c;欢迎关注。提供嵌入式方向…

【Qt】数据库(一)SQLITE创建、增删查改

填坑1&#xff1a;如何连续插入 汇总SQlite语句 创建表格&#xff1a;create table <table_name> (f1 type1, f2 type2,…); 增&#xff1a;insert into <table_name> values (value1, value2,…); 改&#xff1a;update <table_name> set <f1value1>,…

数据结构第二篇【关于java线性表(顺序表)的基本操作】

【关于java线性表&#xff08;顺序表&#xff09;的基本操作】 线性表是什么&#xff1f;&#x1f435;&#x1f412;&#x1f98d;顺序表的定义&#x1f9a7;&#x1f436;&#x1f435;创建顺序表新增元素,默认在数组最后新增在 pos 位置新增元素判定是否包含某个元素查找某个…

使用高性能NIO框架netty实现IM集群对聊方案

文章目录 前言技术积累什么是nettynetty如何实现IM如何实现IM集群 实战演示基础配置netty搭建IM集群redis发布订阅 实战测试 前言 在前面的博文中我们分享了原生websoket集群搭建&#xff0c;也用redis 发布订阅实现了集群消息正常有序分发。但是有不少同学希望风向一期netty实…

Json差异比较

json差异比较 如何比较两个json的差异 代码实现 导入依赖 <dependency><groupId>cn.xiaoandcai</groupId><artifactId>json-diff</artifactId><!-- 旧版本可能存在某些缺陷。版本请以maven仓库最版为准。 --><version>4.1.3-RC1-R…

问题记录_stm32“No target connected“

问题描述&#xff1a; 基于HAL库和stm32cubeMX生成的代码&#xff0c;烧录时出现如下报错窗口&#xff1a; 问题原因&#xff1a; stm32cubeMX生成代码时关闭了SWJ调试功能 解决方法&#xff1a; 在项目中找到__HAL_AFIO_REMAP_SWJ_DISABLE();并注释掉 然后短按复位键的…

AI大模型是如何测试效果的?

AI大模型的测试和评估是一个复杂的过程&#xff0c;通常包括多个方面的考量&#xff0c;因此对大模型的测试也称为多度测试。 可以简单概括为以下几个方面&#xff1a; 基准测试&#xff08;Benchmarking&#xff09;&#xff1a;使用标准数据集和任务评估模型性能&#xff0c…