您的位置:首页 > 移动开发

SpringMVC 源代码深度解析BeanWrapper及其实现

2014-10-30 20:28 344 查看


一、 BeanWrapper

BeanWrapper是对Bean的包装,其接口中所定义的功能很简单包括设置获取被包装的对象,获取被包装bean的属性描述器,由于BeanWrapper接口是PropertyAccessor的子接口,因此其也可以设置以及访问被包装对象的属性值。BeanWrapper大部分情况下是在spring ioc内部进行使用,通过BeanWrapper,spring ioc容器可以用统一的方式来访问bean的属性。用户很少需要直接使用BeanWrapper进行编程。


二、 BeanWrapperImpl

BeanWrapperImpl类是对BeanWrapper接口的默认实现,它包装了一个bean对象,缓存了bean的内省结果,并可以访问bean的属性、设置bean的属性值。BeanWrapperImpl类提供了许多默认属性编辑器,支持多种不同类型的类型转换,可以将数组、集合类型的属性转换成指定特殊类型的数组或集合。用户也可以注册自定义的属性编辑器在BeanWrapperImpl中。

三、 BeanWrapper类图








四、 BeanWrapperImpl设置所包装的bean属性值序列图








五、 BeanWrapperImpl构造方法源码分析


5.1 BeanWrapperImpl构造方法

BeanWrapperImpl类有多个重载方法,下面的构造方法传入一个Object对象,此对象就是被BeanWrapperImpl类所包装的bean

[java] view
plaincopyprint?

public BeanWrapperImpl(Object object) {

registerDefaultEditors();

setWrappedInstance(object);

}

构造方法的实现很简单,第一步在registerDefaultEditors()方法内部设置属性defaultEditorsActive值为true

第二步则调用setWrappedInstance(object)方法,进行初始化以及设置被包装的对象


5.2 setWrappedInstance(object)方法

此方法内部对BeanWrapperImpl类的一些重要属性进行了初始化,并创建了TypeConverterDelegate类的实例作为类型转换处理对象。在此之后,将对被包装bean进行内省分析,内省分析结果保存在cachedIntrospectionResults属性中,此属性是CachedIntrospectionResults类的实例.


5.3 CachedIntrospectionResults类

CachedIntrospectionResults类用于对对象的Class进行内省分析,保存对象的PropertyDescriptor信息,其静态方法

static CachedIntrospectionResults forClass(Class beanClass)

throws BeansException

在BeanWrapperImpl类中被调用,用于对BeanWrapperImpl类所包装的bean进行内省分析,并返回内省分析结果给BeanWrapperImpl


六、 BeanWrapperImpl设置属性值源码分析


6.1 setPropertyValue(PropertyValue pv)方法

BeanWrapperImpl类有多个设置bean属性值的重载方法,此处以

public void setPropertyValue(PropertyValue pv)

throws BeansException

方法作为说明。

[java] view
plaincopyprint?

public void setPropertyValue(PropertyValue pv) throws BeansException {

PropertyTokenHolder tokens = (PropertyTokenHolder) pv.resolvedTokens;

if (tokens == null) {

……………..

BeanWrapperImpl nestedBw = null;

try {

//根据属性名获取BeanWrapImpl对象,支持多重属性的递归分析处理

nestedBw = getBeanWrapperForPropertyPath(propertyName);

}

catch ………..

tokens = getPropertyNameTokens(getFinalPath(nestedBw, propertyName));

//如果nestedBw等于this,则设置resolvedTokens属性值为tokens

if (nestedBw == this) {

pv.getOriginalPropertyValue().resolvedTokens = tokens;

}

nestedBw.setPropertyValue(tokens, pv);

}

else {

setPropertyValue(tokens, pv);

}

}

上述方法根据tokens变量是否为null,有两个不同的分支。其中当tokens为null时,则会对属性名进行递归调用分析处理,返回分析处理后的BeanWrapImpl对象nestedBw。如果nestedBw==this,则会设置pv的resolvedTokens属性值,最后将调用nestedBw对象的设置属性值方法设置属性


6.2 getBeanWrapperForPropertyPath方法

getBeanWrapperForPropertyPath方法用于对属性名称(包括多重属性)进行处理,并返回BeanWrapperImpl对象。所支持的属性名称包括:多重属性(以.分隔)、数组集合map
key属性(以[]方式)。

[java] view
plaincopyprint?

protected BeanWrapperImpl getBeanWrapperForPropertyPath(String propertyPath) {

//根据属性路径获取其第一个属性分隔符.的下标

int pos = PropertyAccessorUtils.getFirstNestedPropertySeparatorIndex(propertyPath);

//如果找到,则表示是有多重属性递归处理

// Handle nested properties recursively.

if (pos > -1) {

//获取第一个属性分隔符前面的属性名称

String nestedProperty = propertyPath.substring(0, pos);

//获取第一个属性分隔符后面的字符串

String nestedPath = propertyPath.substring(pos + 1);

//获取第一个属性片断的BeanWrapperImpl对象nestedBw

BeanWrapperImpl nestedBw = getNestedBeanWrapper(nestedProperty);

//调用nestedBw的getBeanWrapperForPropertyPath方法,对第一个属性分隔符后面的属性字符串进行处理

return nestedBw.getBeanWrapperForPropertyPath(nestedPath);

}

//否则,返回this对象本身

else {

return this;

}

}

在此方法中对嵌套类型的属性进行了分析,首先将处理第一个.前的属性,获取nestedBw对象。然后再调用nestedBw对象的此方法递归处理第一个.后的其它属性,并返回处理结果。

getNestedBeanWrapper(nestedProperty)方法则根据nestedProperty获取嵌套的BeanWrapperImpl对象。


6.3 getPropertyNameTokens方法

getPropertyNameTokens方法内部用于对属性名全路径中最后一个.后的属性名称分析,返回PropertyTokenHolder对象。


6.4 setPropertyValue(tokens, pv)方法

最终的设置属性的操作在此方法内部进行实现,此方法将最原始的属性值经过数组、集合类型属性的处理和类型转换后得到转换后值convertedValue,并从内省信息中获取操作此属性的方法writeMethod,用反射调用writeMethod将参数值convertedValue写入至被包装对象的目标属性中。至此BeanWrapperImpl的对象设值操作处理完成。


七、 BeanWrapperImpl对嵌套属性的支持

BeanWrapperImpl类通过其成员属性提供了一种支持嵌套属性的数据结构,下面是BeanWrapperImpl类的成员:
属性类型及名称
说明
Object object
被BeanWrapper包装的对象
String nestedPath
当前BeanWrapper对象所属嵌套层次的属性名,最顶层的BeanWrapper此属性的值为空
Object rootObject
最顶层BeanWrapper所包装的对象
Map nestedBeanWrappers
缓存当前BeanWrapper的下一层属性的nestedPath和对应的BeanWrapperImpl对象,此BeanWrapperImpl所包装的对应是属性nestedPath的值
例如有类:

Class Employee

{

Company company;

Card card;

String name;

String id;

get/set方法

}

Class Company

{

String companyName;

Map<String,String> attrs;

get/set方法

}

Class Card

{

………….

}

嵌套属性:employee.company.attrs[“location”]

最顶层的BeanWrapper是employeeBeanWrapper,其包装的对象是employeeObj,nestedPath为空,rootObject也是employObj,
employeeBeanWrapper里的nestedBeanWrappers则将包含以下的键值对:

“company”---àcompanyBeanWrapper

“card” ---àcardBeanWrapper

对于对象companyBeanWrapper,则其包装的对象则是companyObj,其nestedPath的值为company,rootObject为employeeObj, nestedBeanWrappers里面的值为空。

BeanWrapperImpl在调用方法

protected BeanWrapperImpl getBeanWrapperForPropertyPath(String propertyPath)

分析employee.company.attrs[“location”]属性值时,将先处理第一个点之前的属性employee得到顶层的BeanWrapper
nestedBw,再调用nestedBw. getBeanWrapperForPropertyPath()方法递归处理第一个点后的其它属性,并最终返回所有属性段都分析后所产生的BeanWrapperImpl对象。
属性类型及名称
说明
String canonicalName
canonicalName为actualName再加上[key1][key2][key3]..这种形式

保存当前级别属性的实际名称,为[前的字符串

如属性employee.company.attrs[“location”]

在EmployeeBeanWrapperImpl类代表company属性,则canonicalName值为”company”

如在CompanyBeanWrapperImpl类代表attrs中key为location的属性,则其canonicalName为attrs[“location”]

String actualName
保存当前级别属性的实际名称,为[前的字符串

如属性employee.company.attrs[“location”]

在EmployeeBeanWrapperImpl类代表company属性,则actualName值为”company”

如在CompanyBeanWrapperImpl类代表attrs中key为location的属性,则其actualName为”attrs”,取当前属性级别中”[“前面的字符串

String[] keys
代表当前级别属性中所有位于[与]间的key或索引所组成的数组
注:“当前级别属性”表示所要访问在属性在属性全路径中位于..之间的值


九、 所使用到的工具类

在此过程中所使用到的一些工具类和主要方法如下:

org.springframework.beans.PropertyAccessorUtils 用于分析属性名称的工具类,提供分析嵌套属性、集合属性(包括.[]等)的一些工具方法。

出自于http://blog.csdn.net/zhiweianran/article/details/7919129
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐