Spring IOC BeanWrapper
2016-11-26 00:59
253 查看
了解Spring依赖注入(也就是IOC或者DI)过程的朋友都应该知道。在Spring依赖注入中有两个非常关键的接口,那就是BeanDefinition和BeanWrapper。BeanDefinition是定义在Spring配置文件中元素解析后的对象。而今天我们就来分析一下BeanWrapper。如果大家不知道Spring IOC的话,先来给大家讲一讲Spring IOC的主要过程。Spring依赖注入是以BeanFactory接口中的getBean()方法触发的。下面简单画一下依赖注入的时序图:
其实Spring IOC的整个过程都包括在AbstractAutowireCapableBeanFactory#doCreateBean方法中,而这个方法包括3个小方法。
createBeanInstance():创建这个对象的空实例,相当于new Object(),然后放入BeanWrapper对象中
populateBean():依赖注入的主要过程。相当于调用setter方法。
initializeBean():调用init方法,Spring中的init-method。
上面这三个方法中BeanWrapper和BeanDefinition始终贯彻依赖注入的整个过程。由BeanDefinition提供数据,然后BeanWrapper负责依赖注入。具体是由BeanWrapper的实现类BeanWrapperImpl来完成的。下面我们看一下BeanWrapperImpl的类结构图。
下面我们来分析一下图中几个接口干的事:
这个接口就三个方法,根据方法我们可以知道。这个是对自定义PropertyEditor的注册与发现。而PropertyEditor是Java内省里面的接口,用于改变指定property属性的类型。可以结合下面的TypeConverter接口一起思考。
这三个方法上面都有共同的注释:
它的意思是转换定义在xml中的值为指定类型,使用PropertyEditor类中的setAsText()方法转换String类型到任何类型。
典型的应用:
我们如果目标对象是Resource可以直接在xml定义这个Resource为String类型。因为Spring有相应的PropertyEditor实现类ResourceEditor。
例如我们定义Mybatis的配置文件:
但是我们可以看看SqlSessionFactoryBean:
我们可以看到在SqlSessionFactoryBean中mapperLocations的属性是Resource.但是我们在配置文件中并没有指定它的类型。这个活就是TypeConverter干的。
由上面我们可以浓缩为4个方法:
1. isReadableProperty().判断指定property是否可读,是否包含getter方法。
2. isWritableProperty().判断指定property是否可写,是否包含setter方法。
3. getPropertyType().获取指定propertyName的类型。
4. setPropertyValue().设置指定propertyValue.
这4个方法是依赖注入的核心方法。
其中主要的是以下2个方法:
1. void setConversionService(ConversionService conversionService);
2. ConversionService getConversionService();
用于集成Spring中的ConversionService.
这个对象有4个方法比较重要:
1. getWrappedInstance().获取包装对象的实例。
2. getWrappedClass().获取包装对象的类型。
3. getPropertyDescriptors().获取包装对象所有属性的PropertyDescriptor.就是这个属性的上下文。
4. getPropertyDescriptor().获取包装对象指定属性的上下文。
注意:默认情况下它会自动注册org.springframework.beans.propertyeditors包下面的property editors.是JDK标准的PropertyEditors的扩展。我们也可以调用registerCustomEditor()方法来给特别的实例注册一个编辑器。(i.e. they are not shared across the application)。可以查看PropertyEditorRegistrySupport了解更多详情。
其实Spring IOC的整个过程都包括在AbstractAutowireCapableBeanFactory#doCreateBean方法中,而这个方法包括3个小方法。
createBeanInstance():创建这个对象的空实例,相当于new Object(),然后放入BeanWrapper对象中
populateBean():依赖注入的主要过程。相当于调用setter方法。
initializeBean():调用init方法,Spring中的init-method。
上面这三个方法中BeanWrapper和BeanDefinition始终贯彻依赖注入的整个过程。由BeanDefinition提供数据,然后BeanWrapper负责依赖注入。具体是由BeanWrapper的实现类BeanWrapperImpl来完成的。下面我们看一下BeanWrapperImpl的类结构图。
下面我们来分析一下图中几个接口干的事:
1、PropertyEditorRegistry – 自定义编辑器
注册JavaBean的PropertyEditor的概括方法,对PropertyEditorRegistrar起作用的中心接口。public interface PropertyEditorRegistry { void registerCustomEditor(Class<?> requiredType, PropertyEditor propertyEditor); void registerCustomEditor(Class<?> requiredType, String propertyPath, PropertyEditor propertyEditor); PropertyEditor findCustomEditor(Class<?> requiredType, String propertyPath); }
这个接口就三个方法,根据方法我们可以知道。这个是对自定义PropertyEditor的注册与发现。而PropertyEditor是Java内省里面的接口,用于改变指定property属性的类型。可以结合下面的TypeConverter接口一起思考。
2、TypeConverter – 依赖注入类型转换
定义类型转换方法的接口,典型的(但是不是必须的)是和PropertyEditorRegistry接口一起实现。public interface TypeConverter { <T> T convertIfNecessary(Object value, Class<T> requiredType) throws TypeMismatchException; <T> T convertIfNecessary(Object value, Class<T> requiredType, MethodParameter methodParam) throws TypeMismatchException; <T> T convertIfNecessary(Object value, Class<T> requiredType, Field field) throws TypeMismatchException; }
这三个方法上面都有共同的注释:
/** * Convert the value to the required type (if necessary from a String). * <p>Conversions from String to any type will typically use the {@code setAsText} * method of the PropertyEditor class, or a Spring Converter in a ConversionService. /
它的意思是转换定义在xml中的值为指定类型,使用PropertyEditor类中的setAsText()方法转换String类型到任何类型。
典型的应用:
我们如果目标对象是Resource可以直接在xml定义这个Resource为String类型。因为Spring有相应的PropertyEditor实现类ResourceEditor。
例如我们定义Mybatis的配置文件:
<bean id="userSqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="mapperLocations"> <list> <value>classpath:com.spring.framework.carl.user.mapper/*.xml</value> </list> </property> </bean>
但是我们可以看看SqlSessionFactoryBean:
我们可以看到在SqlSessionFactoryBean中mapperLocations的属性是Resource.但是我们在配置文件中并没有指定它的类型。这个活就是TypeConverter干的。
3、PropertyAccessor – Property操作
类可以访问指定properties的通用接口(例如:一个对象里面的bean properties或者一个对象的fields).做为BeanWrapper的基础接口。public interface PropertyAccessor { /** * Path separator for nested properties. * Follows normal Java conventions: getFoo().getBar() would be "foo.bar". */ String NESTED_PROPERTY_SEPARATOR = "."; char NESTED_PROPERTY_SEPARATOR_CHAR = '.'; /** * Marker that indicates the start of a property key for an * indexed or mapped property like "person.addresses[0]". */ String PROPERTY_KEY_PREFIX = "["; char PROPERTY_KEY_PREFIX_CHAR = '['; /** * Marker that indicates the end of a property key for an * indexed or mapped property like "person.addresses[0]". */ String PROPERTY_KEY_SUFFIX = "]"; char PROPERTY_KEY_SUFFIX_CHAR = ']'; 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, 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; }
由上面我们可以浓缩为4个方法:
1. isReadableProperty().判断指定property是否可读,是否包含getter方法。
2. isWritableProperty().判断指定property是否可写,是否包含setter方法。
3. getPropertyType().获取指定propertyName的类型。
4. setPropertyValue().设置指定propertyValue.
这4个方法是依赖注入的核心方法。
4、ConfigurablePropertyAccessor – 结合Spring中ConversionService
将PropertyAccessor的配置方法封进内部的接口.并且继承了PropertyEditorRegistry接口,定义了PropertyEditor的管理方法,主要是为BeanWrapper服务。public interface ConfigurablePropertyAccessor extends PropertyAccessor, PropertyEditorRegistry, TypeConverter { void setConversionService(ConversionService conversionService); ConversionService getConversionService(); void setExtractOldValueForEditor(boolean extractOldValueForEditor); boolean isExtractOldValueForEditor(); void setAutoGrowNestedPaths(boolean autoGrowNestedPaths); boolean isAutoGrowNestedPaths(); }
其中主要的是以下2个方法:
1. void setConversionService(ConversionService conversionService);
2. ConversionService getConversionService();
用于集成Spring中的ConversionService.
5、BeanWrapper – 操作Bean实例
public interface BeanWrapper extends ConfigurablePropertyAccessor { void setAutoGrowCollectionLimit(int autoGrowCollectionLimit); int getAutoGrowCollectionLimit(); Object getWrappedInstance(); Class<?> getWrappedClass(); PropertyDescriptor[] getPropertyDescriptors(); PropertyDescriptor getPropertyDescriptor(String propertyName) throws InvalidPropertyException; }
这个对象有4个方法比较重要:
1. getWrappedInstance().获取包装对象的实例。
2. getWrappedClass().获取包装对象的类型。
3. getPropertyDescriptors().获取包装对象所有属性的PropertyDescriptor.就是这个属性的上下文。
4. getPropertyDescriptor().获取包装对象指定属性的上下文。
6、BeanWrapperImpl – 依赖注入实现类
BeanWrapper接口的默认实现类。用于对Bean的包装,实现上面接口所定义的功能很简单包括设置获取被包装的对象,获取被包装bean的属性描述器。注意:默认情况下它会自动注册org.springframework.beans.propertyeditors包下面的property editors.是JDK标准的PropertyEditors的扩展。我们也可以调用registerCustomEditor()方法来给特别的实例注册一个编辑器。(i.e. they are not shared across the application)。可以查看PropertyEditorRegistrySupport了解更多详情。
相关文章推荐
- (spring-第11回【IoC基础篇】)BeanWrapper--实例化Bean的第四大利器
- Mike 企业级框架专题 Spring Ioc容器装配Bean
- Spring学习笔记(二) IoC容器与Bean
- 《Spring 3.x 企业应用开发实战》学习笔记 第三章 IoC容器概述 3.5 Bean的生命周期
- Spring学习08--IoC容器的高级特性(lazy-init、FactoryBean、BeanPostProcessor、autowiring)
- 严重: StandardWrapper.Throwable org.springframework.beans.factory.BeanCreationException
- Spring--IoC--Bean的装配--动态工厂Bean
- Spring--IoC--Bean的装配--静态工厂Bean
- Spring动态管理IoC容器中的Bean
- 做一个合格的程序猿之浅析Spring IoC源码(二)BeanFactory初始化
- 【SSH进阶之路】Spring的IOC逐层深入——源码解析之IoC的根本BeanFactory(五)
- 学习《spring 3.x企业应用开发实战》之在IoC容器中装配Bean
- spring入门 IOC及Bean容器
- Spring IOC之bean的scope属性值:prototype与singleton
- Spring IOC 之Bean的作用域
- 01 走进Spring,Context、Bean和IoC
- 【死磕 Spring】----- IOC 之解析 bean 标签:开启解析进程
- Spring2.5 IoC之bean的四种注入方式(理论篇)
- Spring再回头(一)------IOC(主要是对bean的配置)
- Spring中的IOC(二):容器对bean属性的装配