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

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的类结构图。



下面我们来分析一下图中几个接口干的事:

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了解更多详情。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: