概述
参考文章:
http://www.iocoder.cn/
在 Spring 容器加载阶段,容器将 xml 文件中定义的
<bean>
解析为 BeanDefinition,BeanDefinition 中存储着我们定义一个 bean 需要的所有信息,包括属性,这些属性是以 String 类型的存储的。当用户触发 Bean 实例化阶段时,Spring 容器会将这些属性转换为这些属性真正对应的类型。
执行类型转换的主要方法在AbstractAutowireCapableBeanFactory 的populateBean -> applyPropertyValues;
@Override
public void autowireBean(Object existingBean) {
// Use non-singleton bean definition, to avoid registering bean as dependent bean.
………………
// 进行属性转换
populateBean(bd.getBeanClass().getName(), bd, bw);
}
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
………………
if (pvs != null) {
// 申请参数 pvs PropertyValues
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
在applyPropertyValues中通过convertForProperty进行类型转换
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
………………
// 获得用户自定义的类型转换器
TypeConverter converter = getCustomTypeConverter();
if (converter == null) {
converter = bw;
}
………………
// Create a deep copy, resolving any references for values.
// 做一次深拷贝
List<PropertyValue> deepCopy = new ArrayList<>(original.size());
boolean resolveNecessary = false;
for (PropertyValue pv : original) {
if (pv.isConverted()) {
// 深拷贝
deepCopy.add(pv);
}
else {
………………
if (convertible) {
// 转换属性
convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
}
// Possibly store converted value in merged bean definition,
// in order to avoid re-conversion for every created bean instance.
if (resolvedValue == originalValue) {
if (convertible) {
pv.setConvertedValue(convertedValue);
}
deepCopy.add(pv);
}
else if (convertible && originalValue instanceof TypedStringValue &&
!((TypedStringValue) originalValue).isDynamic() &&
!(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
pv.setConvertedValue(convertedValue);
deepCopy.add(pv);
}
else {
resolveNecessary = true;
deepCopy.add(new PropertyValue(pv, convertedValue));
}
}
}
…………
// Set our (possibly massaged) deep copy.
try {
// 将 值转换为PropertyValue然后放入bean的包装类中
bw.setPropertyValues(new MutablePropertyValues(deepCopy));
}
catch (BeansException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}
convertForProperty
private Object convertForProperty(
@Nullable Object value, String propertyName, BeanWrapper bw, TypeConverter converter) {
// 若 TypeConverter 为 BeanWrapperImpl 类型,则使用 BeanWrapperImpl 来进行类型转换
// 这里主要是因为 BeanWrapperImpl 实现了 PropertyEditorRegistry 接口
if (converter instanceof BeanWrapperImpl) {
return ((BeanWrapperImpl) converter).convertForProperty(value, propertyName);
}
else {
// 获得属性对应的 PropertyDescriptor 对象
PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
// 获得属性对应的 setting MethodParameter 对象
MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
// 进行转换
return converter.convertIfNecessary(value, pd.getPropertyType(), methodParam);
}
}
convertForProperty的主要内容是优先获得属性的描述对象,然后获得方法的描述对象,使用转换器,进行数据转换。
converter.convertIfNecessary主要有两个实现方法DataBinder 和 TypeConverterSupport
convertIfNecessary
public <T> T convertIfNecessary(@Nullable Object value, @Nullable Class<T> requiredType, @Nullable MethodParameter methodParam)
throws TypeMismatchException {
// 主要的执行转换的方法
return doConvert(value, requiredType, methodParam, null);
}
private <T> T doConvert(@Nullable Object value,@Nullable Class<T> requiredType,
@Nullable MethodParameter methodParam, @Nullable Field field) throws TypeMismatchException {
Assert.state(this.typeConverterDelegate != null, "No TypeConverterDelegate");
try {
// 使用字段转换
if (field != null) {
return this.typeConverterDelegate.convertIfNecessary(value, requiredType, field);
}
else {
// 使用方法参数集合进行转换
return this.typeConverterDelegate.convertIfNecessary(value, requiredType, methodParam);
}
}
catch (ConverterNotFoundException | IllegalStateException ex) {
throw new ConversionNotSupportedException(value, requiredType, ex);
}
catch (ConversionException | IllegalArgumentException ex) {
throw new TypeMismatchException(value, requiredType, ex);
}
}
最终追踪下我们发现真正进行类型转换使用的是TypeConverterDelegate的convertIfNecessary
public <T> T convertIfNecessary(@Nullable String propertyName, @Nullable Object oldValue, @Nullable Object newValue,
@Nullable Class<T> requiredType, @Nullable TypeDescriptor typeDescriptor) throws IllegalArgumentException {
// Custom editor for this type?
// 根据参数名称和类型获得此参数的自定义类型描述器
PropertyEditor editor = this.propertyEditorRegistry.findCustomEditor(requiredType, propertyName);
ConversionFailedException conversionAttemptEx = null;
// No custom editor but custom ConversionService specified?
// 未指定自定义编辑器,但指定了自定义ConversionService
ConversionService conversionService = this.propertyEditorRegistry.getConversionService();
if (editor == null && conversionService != null && newValue != null && typeDescriptor != null) {
// 获得newValue的类型描述符
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 below
conversionAttemptEx = ex;
}
}
}
……………………
return (T) convertedValue;
}
ConversionService
目前转换器的主要处理逻辑在此接口下,此接口的关系图
其接口的代码逻辑为
public interface ConversionService {
/**
* 是否可以以进行转换
* Return {@code true} if objects of {@code sourceType} can be converted to the {@code 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);
@Nullable
Object convert(@Nullable Object source, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType);
}
其进行数据转换的主要代码逻辑为
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 handleConverterNotFound(source, sourceType, targetType);
}
进行转换主要三个方法,我们先分析这三个方法
- getConverter
- handleResult
- handleConverterNotFound
getConverter 获得转换器
protected GenericConverter getConverter(TypeDescriptor sourceType, TypeDescriptor targetType) {
// 创建 ConverterCacheKey 对象
ConverterCacheKey key = new ConverterCacheKey(sourceType, targetType);
// 从 converterCache 缓存中,获得 GenericConverter 对象 converter
GenericConverter converter = this.converterCache.get(key);
// 如果获得到,则返回 converter
if (converter != null) {
return (converter != NO_MATCH ? converter : null);
}
// 如果获取不到,则从 converters 中查找
converter = this.converters.find(sourceType, targetType);
// 如果查找不到,则获得默认的 Converter 对象
if (converter == null) {
converter = getDefaultConverter(sourceType, targetType);
}
// 如果找到 converter ,则添加 converter 到 converterCache 中,并返回 converter
if (converter != null) {
this.converterCache.put(key, converter);
return converter;
}
// 如果找不到 converter ,则添加 NO_MATCH 占位符到 converterCache 中,并返回 null
this.converterCache.put(key, NO_MATCH);
return null;
}
ConverterCacheKey key = new ConverterCacheKey(sourceType, targetType);
spring底层重写了ConverterCacheKey的equals方法,这样使得,相同参数的的转换器key是一致的。
底层其实是spring从缓存中获得转换器,如果没有获取就去创建一个符合要求的转换器。而从其实现类可以发现,spring已经实现了相当多的类型转换。
handleResult
private Object handleResult(@Nullable TypeDescriptor sourceType, TypeDescriptor targetType, @Nullable Object result) {
if (result == null) {
assertNotPrimitiveTargetType(sourceType, targetType);
}
return result;
}
做了一个简单的验证,验证值是否符合预期
handleConverterNotFound
private Object handleConverterNotFound(
@Nullable Object source, @Nullable TypeDescriptor sourceType, TypeDescriptor targetType) {
// 情况一,如果 source 为空,则返回空
if (source == null) {
assertNotPrimitiveTargetType(sourceType, targetType);
return null;
}
// 情况二,如果 sourceType 为空,或者 targetType 是 sourceType 的子类,则返回 source
if ((sourceType == null || sourceType.isAssignableTo(targetType)) &&
targetType.getObjectType().isInstance(source)) {
return source;
}
// 抛出 ConverterNotFoundException 异常
throw new ConverterNotFoundException(sourceType, targetType);
}
判断返回null或者异常
实际上,大体的调用流是如下:TypeConverterSupport => ConversionService => Converter,具体想看spring
类型转换的具体实现以及缓存方式可以查看Converter的接口以及getConverter的方法。
最后
以上就是清秀水池为你收集整理的spring学习(六)——4 Spring的 类型转换的全部内容,希望文章能够帮你解决spring学习(六)——4 Spring的 类型转换所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复