Spring 属性注入(二)BeanWrapper 结构
Spring 属性注入(二)BeanWrapper 结构
Spring 系列目录(https://www.cnblogs.com/binarylei/p/10117436.html)
BeanWrapper 位于 org.springframework.beans 包中,默认实现为 BeanWrapperImpl,提供分析和处理标准 JavaBean 用于 get 和 set 属性,取得属性描述,查询属性的读/写能力。
beans 包还提供了一个 PropertyValues 用于保存多个属性值,默认的实现 MutablePropertyValues。另外还有两个有用的工具类,BeanUtils 和 PropertyAccessorUtils。
一、BeanWrapper 类图

PropertyEditorRegistryPropertyEditor 注册、查找。TypeConverter类型转换,其主要的工作由 TypeConverterDelegate 这个类完成的。PropertyAccessor属性读写。ConfigurablePropertyAccessor配置一些属性,如设置 ConversionService、是否暴露旧值、嵌套注入时属性为 null 是否自动创建。BeanWrapper对 bean 进行封装。AbstractNestablePropertyAccessor实现了对嵌套属性注入的处理,其它实现见名知义就不介绍了。
BeanWrapper 的层次结构还是比较清晰的,继承于 ConfigurablePropertyAccessor 和 PropertyAccessor 接口。
有一点不太明白,为什么 BeanWrapper 要继承于 PropertyEditorRegistry。从字面意义上来说,PropertyEditorRegistry 提供了 PropertyEditor,而 TypeConverter 进行类型转换,和 BeanWrapper 不是继承关系,使用组合感觉更好。
二、PropertyEditorRegistry
PropertyEditor 将 String 转换为其它类型,PropertyEditorRegistry 统一管理所有的 PropertyEditor 注册和查找。
public interface PropertyEditorRegistry {
// 1. 根据类型注册 PropertyEditor
void registerCustomEditor(Class<?> requiredType, PropertyEditor propertyEditor);
// 2. 根据类型(requiredType)和属性(propertyPath)注册 PropertyEditor
// 查找时优先根据 propertyPath 查找对应的 PropertyEditor,propertyPath 可以为嵌套属性
void registerCustomEditor(@Nullable Class<?> requiredType,
@Nullable String propertyPath, PropertyEditor propertyEditor);
// 3. 根据类型和属性查找 PropertyEditor
PropertyEditor findCustomEditor(@Nullable Class<?> requiredType, @Nullable String propertyPath);
}
PropertyEditorRegistry 的实现类 PropertyEditorRegistrySupport 分析见这两篇文章:
三、TypeConverter
TypeConverter 负责类型转换,其主要的工作由 TypeConverterDelegate 这个类完成的。
public interface TypeConverter {
// 1. value 转换成 requiredType
<T> T convertIfNecessary(Object value, Class<T> requiredType) throws TypeMismatchException;
// 2. methodParam 同下
<T> T convertIfNecessary(Object value, Class<T> requiredType,
MethodParameter methodParam) throws TypeMismatchException;
// 3. field 是 value 转换成 requiredType 后需要赋值的 field 字段
// 可以从该 field 字段拿到其泛型信息,从而进一步判断是否可以转换,毕竟 requiredType 只有 Class 信息
<T> T convertIfNecessary(Object value, Class<T> requiredType, Field field)
throws TypeMismatchException;
}
TypeConverter 的实现类 TypeConverterSupport 的所有功能,实际是都是委托给 TypeConverterDelegate 完成的。
四、PropertyAccessor
PropertyAccessor 提供了对 JavaBean 的基本操作。
public interface PropertyAccessor {
boolean isReadableProperty(String propertyName);
boolean isWritableProperty(String propertyName);
Class<?> getPropertyType(String propertyName) throws BeansException;
TypeDescriptor getPropertyTypeDescriptor(String propertyName) throws BeansException;
Object getPropertyValue(String propertyName) throws BeansException;
void setPropertyValue(String propertyName, @Nullable Object value) throws BeansException;
void setPropertyValue(PropertyValue pv) throws BeansException;
void setPropertyValues(Map<?, ?> map) throws BeansException;
void setPropertyValues(PropertyValues pvs) throws BeansException;
void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown)
throws BeansException;
void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown, boolean ignoreInvalid)
throws BeansException;
}
PropertyAccessor 的实现类是 AbstractPropertyAccessor,这个类中 setPropertyValue 进行了处理,最终都是调用 setPropertyValue(String propertyName, Object value) 完成属性注入。
四、ConfigurablePropertyAccessor
public interface ConfigurablePropertyAccessor extends
PropertyAccessor, PropertyEditorRegistry, TypeConverter {
void setConversionService(@Nullable ConversionService conversionService);
ConversionService getConversionService();
// PropertyEditor 使用时是否暴露修改前后值
void setExtractOldValueForEditor(boolean extractOldValueForEditor);
boolean isExtractOldValueForEditor();
// 嵌套注入时当属性为 null 时是否自动生成对象
void setAutoGrowNestedPaths(boolean autoGrowNestedPaths);
boolean isAutoGrowNestedPaths();
}
ConfigurablePropertyAccessor 的实现也类是 AbstractPropertyAccessor,这个类中默认 extractOldValueForEditor 和 autoGrowNestedPaths 都是 false,即不暴露旧值,也不支持嵌套注入时属性为 null 就自动创建对象。
五、BeanWrapper
public interface BeanWrapper extends ConfigurablePropertyAccessor {
// @since 4.1 设置集合或数组自动生成对象的最大嵌套深度
void setAutoGrowCollectionLimit(int autoGrowCollectionLimit);
int getAutoGrowCollectionLimit();
Object getWrappedInstance();
Class<?> getWrappedClass();
PropertyDescriptor[] getPropertyDescriptors();
PropertyDescriptor getPropertyDescriptor(String propertyName) throws InvalidPropertyException;
}
- Spring 属性注入(三)AbstractNestablePropertyAccessor
- BeanWrapperImpl 源码分析如下:
BeanWrapper 的实现类是 BeanWrapperImpl,主要完成了 JavaBean 的内省,包括 PropertyDescriptor 的获取,属性的赋值等。
(1) JavaBean 的内省
private CachedIntrospectionResults cachedIntrospectionResults;
// 获取
private CachedIntrospectionResults getCachedIntrospectionResults() {
if (this.cachedIntrospectionResults == null) {
this.cachedIntrospectionResults = CachedIntrospectionResults.forClass(getWrappedClass());
}
return this.cachedIntrospectionResults;
}
JavaBean 的内省都是由 CachedIntrospectionResults 完成,通过 cachedIntrospectionResults 就可以获取对应属性的 PropertyDescriptor。例如下面两个方法:
@Override
public PropertyDescriptor[] getPropertyDescriptors() {
return getCachedIntrospectionResults().getPropertyDescriptors();
}
@Override
public PropertyDescriptor getPropertyDescriptor(String propertyName) throws InvalidPropertyException {
BeanWrapperImpl nestedBw = (BeanWrapperImpl) getPropertyAccessorForPropertyPath(propertyName);
// 获取属性名称
String finalPath = getFinalPath(nestedBw, propertyName);
PropertyDescriptor pd = nestedBw.getCachedIntrospectionResults().getPropertyDescriptor(finalPath);
return pd;
}
(2) BeanPropertyHandler
@Override
protected BeanPropertyHandler getLocalPropertyHandler(String propertyName) {
PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(propertyName);
return (pd != null ? new BeanPropertyHandler(pd) : null);
}
BeanPropertyHandler 是 BeanWrapperImpl 的内部类,是对 PropertyDescriptor 的封装,完成对属性的各种操作,如赋值。
(3) convertForProperty
convertForProperty 在 AbstractAutowireCapableBeanFactory#applyPropertyValues 属性注入时使用
public Object convertForProperty(@Nullable Object value, String propertyName) throws TypeMismatchException {
CachedIntrospectionResults cachedIntrospectionResults = getCachedIntrospectionResults();
PropertyDescriptor pd = cachedIntrospectionResults.getPropertyDescriptor(propertyName);
if (pd == null) {
throw new InvalidPropertyException(getRootClass(), getNestedPath() + propertyName,
"No property '" + propertyName + "' found");
}
TypeDescriptor td = cachedIntrospectionResults.getTypeDescriptor(pd);
if (td == null) {
td = cachedIntrospectionResults.addTypeDescriptor(pd, new TypeDescriptor(property(pd)));
}
// 父类 AbstractNestablePropertyAccessor 进行类型转换
return convertForProperty(propertyName, null, value, td);
}
// Property 也是对 PropertyDescriptor 封装,在 Android 等环境中不存在 PropertyDescriptor 类
private Property property(PropertyDescriptor pd) {
GenericTypeAwarePropertyDescriptor gpd = (GenericTypeAwarePropertyDescriptor) pd;
return new Property(gpd.getBeanClass(), gpd.getReadMethod(), gpd.getWriteMethod(), gpd.getName());
}
每天用心记录一点点。内容也许不重要,但习惯很重要!
Spring 属性注入(二)BeanWrapper 结构的更多相关文章
- Spring 属性注入(一)JavaBean 内省机制在 BeanWrapper 中的应用
Spring 属性注入(一)JavaBean 内省机制在 BeanWrapper 中的应用 Spring 系列目录(https://www.cnblogs.com/binarylei/p/101174 ...
- Spring 属性注入(三)AbstractNestablePropertyAccessor
Spring 属性注入(三)AbstractNestablePropertyAccessor Spring 系列目录(https://www.cnblogs.com/binarylei/p/10117 ...
- Spring 属性注入(四)属性键值对 - PropertyValue
Spring 属性注入(四)属性键值对 - PropertyValue Spring 系列目录(https://www.cnblogs.com/binarylei/p/10117436.html) P ...
- spring 属性注入
Spring的核心技术室依赖注入,下面是依赖注入之属性注入的实现过程,牛刀小试,请看效果. 1.首先添加Spring.Web引用.本例中是使用分层思想来演示的,下面是项目的结构和UserModel类的 ...
- java spring属性注入
一.创建对象时候,向类里面属性设置值:一般有三个方式 1) .有参构造, 2). set**** 3).接口注入 二. 在spring框架里面,支持前面两种方式: 1).有参构造方法 用constr ...
- Spring属性注入、构造方法注入、工厂注入以及注入参数(转)
Spring 是一个开源框架. Spring 为简化企业级应用开发而生(对比EJB2.0来说). 使用 Spring 可以使简单的 JavaBean 实现以前只有 EJB 才能实现的功能.Spring ...
- 六 Spring属性注入的四种方式:set方法、构造方法、P名称空间、SPEL表达式
Spring的属性注入: 构造方法的属性注入 set方法的属性注入
- spring属性注入
1,set方法注入 (1)对于值类型的属性: 在对象中一定要有set方法 package com.songyan.demo1; import com.songyan.injection.Car; /* ...
- Spring 依赖注入(二、注入参数)
注入参数基本分7类: 1.基本类型值 2.注入bean 3.内部bean 4.注入null值 5.级联属性 6.List,Set,Map集合的注入 7.properties文件的注入(和集合注入基本是 ...
随机推荐
- opencv批量读取图片
#include<opencv2/opencv.hpp>using namespace cv;using namespace std;int main(){ int num=4;// ...
- jms版本
Java消息服务是一个在 Java标准化组织(JCP)内开发的标准(代号JSR 914). 2001年6月25日,Java消息服务发布JMS 1.0.2b,2002年3月18日Java消息服务发布 1 ...
- PropertyGrid控件动态生成属性及下拉菜单 (转)
http://blog.sina.com.cn/s/blog_6f14b7010101b91b.html https://msdn.microsoft.com/zh-cn/library/ms1718 ...
- 配置完php.ini中的扩展库后,重启apache出现错误1067
网上有很多解决办法,比如更改环境变量,重装apache等等,但没有一个是符合我的.最后发现只是犯了一个低级错误,因为是第一次配置php.ini中的扩展库,忘记配置扩展库的路径. 解决办法:需要先加上扩 ...
- 二进制中1的个数(python)
题目描述 输入一个整数,输出该数二进制表示中1的个数.其中负数用补码表示. # -*- coding:utf-8 -*- class Solution: def NumberOf1(self, n): ...
- cf-Global Round2-D. Frets On Fire(二分)
题目链接:http://codeforces.com/contest/1119/problem/D 题意:给n(<=1e5)个数s[i],i=1..n,(0<=s[i]<=1e18) ...
- 2019-3-10——生成对抗网络GAN---生成mnist手写数字图像
""" 生成对抗网络(GAN,Generative Adversarial Networks)的基本原理很简单: 假设有两个网络,生成网络G和判别网络D.生成网络G接受一 ...
- mac上为nodejs设置环境变量
Mac下面的环境变量设置和Linux差不多,一般为这几个文件(左边的先加载): /etc/profile /etc/paths ~/.bash_profile ~/.bash_login ~/.pro ...
- 六.Spring与RabbitMQ集成--HelloWorld
spring对RabbitMQ做了很好的集成,我们称之为spring AMQP,其官方文档写得十分详尽,文档地址:https://docs.spring.io/spring-amqp/referenc ...
- java正则表达式(regular)
哎呀妈呀,脑瓜疼----正则表达式 正则是用来处理复杂文本类型的 标准字符集合: \d --->代表0-9任意一个数字 \D ---->除了数字之外的任意字符 \w ----->字母 ...