(spring-第11回【IoC基础篇】)BeanWrapper--实例化Bean的第四大利器

12/12/2015来源:Java教程人气:964

重复是理解和记忆的最好方法。在讲实例化Bean的每个步骤之前,我都会先复习一下Bean实例化的整个过程:

 

结合图片我们回顾一下具体的过程:

  1. ResourceLoader加载配置信息,
  2. 由BeanDefinitionReader读取并解析<bean>标签,并将<bean>标签的属性都转换为BeanDefinition对应的属性,并注册到BeanDefinitionRegistry注册表中。
  3. 容器扫描注册表,通过反射机制获取BeanFactoryPostPRocessor类型的工厂后处理器,并用这个工厂后处理器对BeanDefinition进行加工。
  4. 取出加工过的BeanDefinition,使用InstantiationStrategy实例化Bean。
  5. BeanWrapper结合BeanDefinitionRegistry和PropertyEditorRegistry对Bean的属性赋值。

今天我们将介绍的就是第五步。开门见山,BeanWrapper的功能:

spring通过BeanWrapper完成属性的配置工作。具体表现为:

  1. 从BeanDefinitionRegistry注册表中取出尚未进行属性配置的BeanDefinition,获取Bean属性的配置信息,
  2. 使用属性编辑器对这些配置信息进行转换得到Bean属性的值,
  3. 最后对Bean通过反射机制设置属性值。

下面是BeanWrapper的继承结构:

 

从上面的结构可以看出,BeanWrapperImpl(BeanWrapper的实现类)有两个顶级接口,分别是:PropertyEditorRegistry和Propertyaccessor,前者是属性编辑器,负责将配置文件中bean属性的字面值转换为bean具体的属性值。后者定义了各种访问bean属性的方法。所以BeanWrapperImpl具有三重身份:

  1.  Bean包裹器:(顾名思义)

        下面代码是BeanWrapperImpl初始化时要执行的方法,而参数中的object就是包裹的bean对象。

        其中第8行就是把object.getClass()保存在cachedIntrospectionResults 属性中,该属性是CachedIntrospectionResults类的实例,

        CachedIntrospectionResults是负责缓存属性描述器(PropertyDescriptor)信息的。  

        object是对象的实例,而object.getClass()则获取的是实例对应的类的描述信息,那么cachedIntrospectionResults 拿到这个实例类的描述信息class,就可以通过反射机制来访问该class里面的所有属性了,最后封装成PropertyDescriptor。

        属性描述器(PropertyDescriptor)是java.beans.PropertyDescriptor包里的类,用来描述java bean的属性(一个描述器描述一个属性),这个属性是JavaBean通过一对入口方法导出的。

        BeanWrapperImpl利用属性描述器信息结合属性编辑器来设置属性。

1 public void setWrappedInstance(Object object, String nestedPath, Object rootObject) {
2         Assert.notNull(object, "Bean object must not be null");
3         this.object = object;
4         this.nestedPath = (nestedPath != null ? nestedPath : "");
5         this.rootObject = (!"".equals(this.nestedPath) ? rootObject : object);
6         this.nestedBeanWrappers = null;
7         this.typeConverterDelegate = new TypeConverterDelegate(this, object);
8         setIntrospectionClass(object.getClass());
9     }
1 protected void setIntrospectionClass(Class clazz) {
2         if (this.cachedIntrospectionResults != null &&
3                 !clazz.equals(this.cachedIntrospectionResults.getBeanClass())) {
4             this.cachedIntrospectionResults = null;
5         }
6     }

 

  

   2.  属性访问器:即PropertyAccessor,这个接口有很多方法,诸如:setPropertyValue、setPropertyValues等,BeanWrapperImpl通过这些方法来设置bean属性的值。

 

3.  属性编辑器注册表:(负责取出属性编辑器,BeanWrapperImpl结合属性编辑器来设置属性)。

 

下面是BeanWrapperImpl的某个构造函数,一开始就调用了从属性编辑器那里继承过来的registerDefaultEditors方法,该方法自动注册加载spring默认的属性编辑器们。

 

1 public BeanWrapperImpl(Object object) {
2         registerDefaultEditors();
3         setWrappedInstance(object);
4     }

 

BeanWrapperImpl完成Bean属性的配置工作之后,接下来还需要Bean后处理器(实现了BeanPostProcessor接口的Bean)继续对Bean实例进行加工,直到装配出一个准备就绪的Bean,把肉放到碗里等萌宝来吃。

由于本文未对代码进行详细解读,所以其中会有没有讲到的地方,比如,属性编辑器具体是怎样的?如何对bean的属性进行编辑?下一篇博文将会详细介绍。