(spring-第11回【IoC基础篇】)BeanWrapper--实例化Bean的第四大利器
重复是理解和记忆的最好方法。在讲实例化Bean的每个步骤之前,我都会先复习一下Bean实例化的整个过程:
结合图片我们回顾一下具体的过程:
- ResourceLoader加载配置信息,
- 由BeanDefinitionReader读取并解析<bean>标签,并将<bean>标签的属性都转换为BeanDefinition对应的属性,并注册到BeanDefinitionRegistry注册表中。
- 容器扫描注册表,通过反射机制获取BeanFactoryPostProcessor类型的工厂后处理器,并用这个工厂后处理器对BeanDefinition进行加工。
- 取出加工过的BeanDefinition,使用InstantiationStrategy实例化Bean。
- BeanWrapper结合BeanDefinitionRegistry和PropertyEditorRegistry对Bean的属性赋值。
今天我们将介绍的就是第五步。开门见山,BeanWrapper的功能:
spring通过BeanWrapper完成属性的配置工作。具体表现为:
- 从BeanDefinitionRegistry注册表中取出尚未进行属性配置的BeanDefinition,获取Bean属性的配置信息,
- 使用属性编辑器对这些配置信息进行转换得到Bean属性的值,
- 最后对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的属性进行编辑?下一篇博文将会详细介绍。