Spring中类型转换服务ConversionService
以及 Converter
类型转换器
前面我也已经了解了整个spring启动的大致流程, 即
ClassPathXmlApplicationContext
的构造方法
执行过程中调用AbstractApplicationContext
类中的refresh()
方法。在
refresh()
方法中 调用了13个具体方法。其中有一个方法finishBeanFactoryInitialization(beanFactory)
是为剩余未实例化, 非懒加载的BeanDefinition
进行实例化。这这个方法执行的第一部分逻辑,就是我们今天要讨论的内容:
ConversionService
类型转换服务
0、概述
在spring的bean创建过程中,首先进行的是bean的实例化过程, 实例化过程中会遇到各种属性值的解析与类型转换, 这个过程就离不开Converter
去做相应的处理。 那么这些Converter
又是存在放在哪里, 并且什么时候加入到对应的集合中去的呢? 下面请看具体的源码分析
1、源码分析
1.1、ConversionService
接口的源码
/*
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.core.convert;
import org.springframework.lang.Nullable;
/**
* 类型转换服务
*
* A service interface for type conversion. This is the entry point into the convert system.
* Call {@link #convert(Object, Class)} to perform a thread-safe type conversion using this system.
*
*/
public interface ConversionService {
/**
* 判断能否进行类型转换
*/
boolean canConvert(@Nullable Class<?> sourceType, Class<?> targetType);
/**
* 判断是否可以进行类型转换
*/
boolean canConvert(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType);
/**
* 类型转换,获取合适的转换器进行类型的转换,默认是DefaultConversionService,也可以是自定义的
*/
@Nullable
<T> T convert(@Nullable Object source, Class<T> targetType);
@Nullable
Object convert(@Nullable Object source, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType);
}
1.2、实现类有哪些?
-
这里,比较核心且我们应该关心的一般有两个,这里主要提一下
DefaultConversionService
DefaultConversionService
ConfigurableConversionService
-
DefaultConversionService
中有几个方法需要我们关注一下
public static void addDefaultConverters(ConverterRegistry converterRegistry) {
addScalarConverters(converterRegistry);
addCollectionConverters(converterRegistry);
// 想 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));
}
2、Converter 分析与自定义
2.1、Converter 分类
从上图大致我们可以了解到, ConversionService
管理着一系列的 Converter
,进行类型转换服务, 具体的分类如下:
Converter
: 一般用于一对一的一个类型转换S类型 -> T类型
T convert(S source);
GenericConverter
: 一般用于将一种类型转换成多个目标类型的描述Object convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType);
ConverterFactory
: “范围”转换器的工厂,可以将对象从 S 转换为 R 的子类型<T extends R> Converter<S, T> getConverter(Class<T> targetType);
2.2、如何自定义Converter 并添加到spring 容器中进行使用
这里我们可以参考一下spring官方文档中的介绍
上面截图我们可以看出来, 可以通过xml方法想 spring 容器中注入我们自定义的 Converter
3.2、如何具体实现
3.2.1、先自定义一个Converter
import org.springframework.core.convert.converter.Converter;
public class StudentConverter implements Converter<String,Student> {
@Override
public Student convert(String source) {
System.out.println("-----");
Student s = new Student();
String[] splits = source.split("_");
s.setId(Integer.parseInt(splits[0]));
s.setName(splits[1]);
return s;
}
}
3.2.2、实现一个辅助类: 学生类
public class Student {
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
3.2.3、通过xml添加到容器中
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:msb="http://www.mashibing.com/schema/user"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.mashibing.com/schema/user http://www.mashibing.com/schema/user.xsd">
<bean id="studentConverter" class="com.qzk.selfConverter.StudentConverter"></bean>
<bean id ="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<ref bean="studentConverter"></ref>
</set>
</property>
</bean>
</beans>
3.2.4、 启动测试启动类
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @ClassName TestConverter
* @Description TODO
* @Author qzk
* @Date 2022/5/6 10:40 下午
* @Version 1.0
**/
public class TestConverter {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
StudentConverter bean = context.getBean(StudentConverter.class);
System.out.println(bean);
}
}
如上图,我们已经看到,在容器中已经有这个转换器了, 但是这边看, 还是不太清晰,我们来看下面这张图
注意:
-
这里此时有53个,是因为有部分是spring自带的类型转换服务, 我们自己定义的就只有一个。这个在上面
DefaultConversionService
中的addDefaultConverters
等方法中也可以看到, 有添加spring自带的类型转换服务的。 -
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { // Initialize conversion service for this context. // 为上下文初始化类型转换器 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)); } ..... ..... }
-
上面的代码中的这段, 只是在`beanFactory 中设置了这些类型转换服务, 还没有去具体使用。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· DeepSeek在M芯片Mac上本地化部署
2019-05-06 通过互斥锁实现模拟抢票数据安全问题
2019-05-06 进程中join方法的使用
2019-05-06 开启子进程的两种方法
2019-05-06 基于TCP协议的远程终端控制并发socketserver实现以及粘包问题处理
2019-05-06 基于TCP通过socketserver简单实现并发效果