Spring 学习 (二)__BeanWrapper及其实现

来源:互联网 发布:软件开发合作协议 编辑:程序博客网 时间:2024/05/22 04:56

[置顶] Spring 学习 (二)__BeanWrapper及其实现

标签: springbeanobjectstringclassioc
 14840人阅读 评论(3) 收藏 举报
 分类:

目录(?)[+]

一、 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 plain copy
 print?
  1. public BeanWrapperImpl(Object object) {  
  2.        registerDefaultEditors();  
  3.        setWrappedInstance(object);  
  4.     }  

构造方法的实现很简单,第一步在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 plain copy
 print?
  1. public void setPropertyValue(PropertyValue pv) throws BeansException {  
  2.        PropertyTokenHolder tokens = (PropertyTokenHolder) pv.resolvedTokens;  
  3.        if (tokens == null) {  
  4.            ……………..  
  5.             BeanWrapperImpl nestedBw = null;  
  6.            try {  
  7.               //根据属性名获取BeanWrapImpl对象,支持多重属性的递归分析处理  
  8.               nestedBw = getBeanWrapperForPropertyPath(propertyName);  
  9.            }  
  10.            catch ………..  
  11.            tokens = getPropertyNameTokens(getFinalPath(nestedBw, propertyName));  
  12.            //如果nestedBw等于this,则设置resolvedTokens属性值为tokens  
  13.            if (nestedBw == this) {  
  14.               pv.getOriginalPropertyValue().resolvedTokens = tokens;  
  15.            }  
  16.            nestedBw.setPropertyValue(tokens, pv);  
  17.        }  
  18.        else {  
  19.            setPropertyValue(tokens, pv);  
  20.        }  
  21.     }  

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

6.2                   getBeanWrapperForPropertyPath方法

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

[java] view plain copy
 print?
  1. protected BeanWrapperImpl getBeanWrapperForPropertyPath(String propertyPath) {  
  2.        //根据属性路径获取其第一个属性分隔符.的下标  
  3.        int pos = PropertyAccessorUtils.getFirstNestedPropertySeparatorIndex(propertyPath);  
  4.        //如果找到,则表示是有多重属性递归处理  
  5.        // Handle nested properties recursively.  
  6.        if (pos > -1) {  
  7.            //获取第一个属性分隔符前面的属性名称  
  8.            String nestedProperty = propertyPath.substring(0, pos);  
  9.            //获取第一个属性分隔符后面的字符串  
  10.            String nestedPath = propertyPath.substring(pos + 1);  
  11.            //获取第一个属性片断的BeanWrapperImpl对象nestedBw  
  12.            BeanWrapperImpl nestedBw = getNestedBeanWrapper(nestedProperty);  
  13.            //调用nestedBw的getBeanWrapperForPropertyPath方法,对第一个属性分隔符后面的属性字符串进行处理  
  14.            return nestedBw.getBeanWrapperForPropertyPath(nestedPath);  
  15.        }  
  16.        //否则,返回this对象本身  
  17.        else {  
  18.            return this;  
  19.        }  
  20.     }  

在此方法中对嵌套类型的属性进行了分析,首先将处理第一个.前的属性,获取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”]

最顶层的BeanWrapperemployeeBeanWrapper,其包装的对象是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类代表attrskeylocation的属性,则其canonicalNameattrs[“location”]

 

String actualName

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

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

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

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

 

String[] keys

代表当前级别属性中所有位于[与]间的key或索引所组成的数组

注:“当前级别属性”表示所要访问在属性在属性全路径中位于..之间的值

九、 所使用到的工具类

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

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



1
0
 
 

我的同类文章

  • JAVA学习(八)__Spring2.5+JUnit4单元测试2013-03-11
  • 关于Spring中dataSource的配置2012-11-06
  • JAVA学习(七)__Spring的@Autowired注入规则2013-03-11
  • Spring 学习(一)2012-08-24

参考知识库

img

Java SE知识库

img

Java EE知识库

img

Java 知识库

img

算法与数据结构知识库

猜你在找
spring3.2入门到大神(备java基础、jsp、servlet,javaee精髓)
深入浅出Spring Data JPA
深入浅出Spring
基于Maven+Springmvc+Spring+Mybatis+jQueryMobile驴友社区
万众期待全网首发—SpringData
JavaScript学习笔记-- undefined and null 数据类型分析
使用express-session和connect-mongo实现session管理导致request中session为undefined的问题
undefined reference to C代码中实现Surface显示
NDK编译时报错error undefined reference to rand是不是安卓库函数里面没有这个函数的实现呢
关于arm-linux-gcc交叉编译工具链实现自己的crt0或者编译UBOOT出现undefined reference to __aeabi_unwind_cpp_pr0的解决方法
查看评论
2楼 ruiting 2014-12-14 12:03发表 [回复]
我刚刚看了一下beanwrapper,用myeclipse跑一把,但是总是报错,能否帮忙看看?
BeanWrapperImpl company1 =new BeanWrapperImpl(new Company());
// setting the company name..
//company.setPropertyValue("name", "Some Company Inc.");
// ... can also be done like this:
PropertyValue value = new PropertyValue("name", "Some Company Inc.");

company1.setPropertyValue(value);

这里的company1.总是报错:Syntax error on token(s), misplaced construct(s)
是什么原因呢? 这种用法不对,还是语法哪儿不对呢? 我看了里面源码,有setPropertyValue函数啊
Re: hz531924627 2016-12-28 18:09发表 [回复]
回复ruiting:需要两个参数
company.setPropertyValue("name","value");
1楼 zxy861114 2014-08-19 14:47发表 [回复]
头像很销魂,文章很丰满~
我是从AbstractAutowireCapableBeanFactory.doCreateBean->populateBean->applyPropertyValues->AbstractPropertyAccessor.setPropertyValues->BeanWrapperImpl.setPropertyValue一路追过来的。谢谢你的文章~
0 0
原创粉丝点击