目前在开发的过程中遇到:通过spring在后台对前台form 传递过来的属性自动封装到对应的bean中,对其中的一些类进行了相应的学习,还是有些不是很清楚,将以下文章转载分享:
看spring源码的时间也有很长一段时间了,对其中bean的注入也有一定的了解。总想对这一段时间的学习经历做出总结,又不知道从何处开始。也看了从主要脉络开始写,本人也看了计文柯老师编写的《spring技术内幕》,觉得将的很生动,就是对于一个刚学习的人来说有点深奥。想从一些基础的东西开始慢慢的解释spring的bean内核,也给希望给那些和我一样想了解spring内核的人提供一些帮助。也希望各位老鸟看了之后提出宝贵的建议。
先从spring的bean的属性操作开始吧。
一 Bean的properties的操作特性
1 properties操作的整体的结构图
这是我整理出来的bean相关属性的操作接口图。从这个图中我们可以清晰的看出对于bean属性相关操作的功能。在最上面的PropertyAccessor接口提供了对于bean属性的取值,赋值等基本的操作,并且定义了属性常用的分割符“.”,“[”,“]”等。TypeConverter接口提供了在需要的情况下对一些类型的值,进行转换和封装。这些实际性的操作在我们给bean的赋值的时候都会用到。例如 在我们的引用中,我们有一个属性start是int类型的,在spring的配置文件中
给这个属性赋21的值。我们在这设置的是一个字符串类型的值,在bean的初始化的时候就需要同过实现convertIfNecessary的方法将字符型串类型转化成int类型。
PropertyEditorRegistry接口提供了一些对属性编辑器注册和查找的方法。而这些方法的具体实现是在PropertyEditorRegistrySupport类中实现的。ConfigurablePropertyAccessor接口只是继承了上面的的三个接口。方便在后面实现类去做实现的时候只用去实现这个统一接口。同时也增加了在对属性赋值的时候是否去提取他以前值的标志接口. BeanWrapper接口继承了ConfigurablePropertyAccessor接口,同时还添加了一些bean的类型,实例添加获取等操作,从而完成了一个bean对象的初步的服装。
下面对这些接口的实现类做主要的分析。
u PropertyEditorRegistrySupport
PropertyEditorRegistrySupport的类实现了各种类型的的属性的编译器.
这个类里面定义几种类型的类型编辑器的存储容器,是否启用一些通用属性的编辑器。
通过getDefaultEditor的方法来获取默认类型的属性的编辑器.在defaultEditors容器中存储的是属性的类型,各种类型的编辑器的。
通过doRegisterDefaultEditors来注册了64中默认类型的编辑器。这些编辑器都是我们在编码过程中常见的类型,例如cahr,Class,String,List等等。
private void doRegisterDefaultEditors() {
this.defaultEditors = new HashMap(64);
this.defaultEditors.put(Charset.class, new CharsetEditor());
this.defaultEditors.put(Class.class, new ClassEditor());
this.defaultEditors.put(Class[].class, new ClassArrayEditor());
this.defaultEditors.put(File.class, new FileEditor());
this.defaultEditors.put(InputStream.class, new InputStreamEditor());
this.defaultEditors.put(Locale.class, new LocaleEditor());
this.defaultEditors.put(Pattern.class, new PatternEditor());
this.defaultEditors.put(Properties.class, new PropertiesEditor());
this.defaultEditors.put(Resource[].class, new ResourceArrayPropertyEditor());
this.defaultEditors.put(URI.class, new URIEditor());
this.defaultEditors.put(URL.class, new URLEditor());
// Default instances of collection editors.
// Can be overridden by registering custom instances of those as custom editors.
this.defaultEditors.put(Collection.class, new CustomCollectionEditor(Collection.class));
this.defaultEditors.put(Set.class, new CustomCollectionEditor(Set.class));
this.defaultEditors.put(SortedSet.class, new CustomCollectionEditor(SortedSet.class));
this.defaultEditors.put(List.class, new CustomCollectionEditor(List.class));
this.defaultEditors.put(SortedMap.class, new CustomMapEditor(SortedMap.class));
// Default editors for primitive arrays.
this.defaultEditors.put(byte[].class, new ByteArrayPropertyEditor());
this.defaultEditors.put(char[].class, new CharArrayPropertyEditor());
// The JDK does not contain a default editor for char!
this.defaultEditors.put(char.class, new CharacterEditor(false));
this.defaultEditors.put(Character.class, new CharacterEditor(true));
// Spring's CustomBooleanEditor accepts more flag values than the JDK's default editor.
this.defaultEditors.put(boolean.class, new CustomBooleanEditor(false));
this.defaultEditors.put(Boolean.class, new CustomBooleanEditor(true));
// The JDK does not contain default editors for number wrapper types!
// Override JDK primitive number editors with our own CustomNumberEditor.
this.defaultEditors.put(byte.class, new CustomNumberEditor(Byte.class, false));
this.defaultEditors.put(Byte.class, new CustomNumberEditor(Byte.class, true));
this.defaultEditors.put(short.class, new CustomNumberEditor(Short.class, false));
this.defaultEditors.put(Short.class, new CustomNumberEditor(Short.class, true));
this.defaultEditors.put(int.class, new CustomNumberEditor(Integer.class, false));
this.defaultEditors.put(Integer.class, new CustomNumberEditor(Integer.class, true));
this.defaultEditors.put(long.class, new CustomNumberEditor(Long.class, false));
this.defaultEditors.put(Long.class, new CustomNumberEditor(Long.class, true));
this.defaultEditors.put(float.class, new CustomNumberEditor(Float.class, false));
this.defaultEditors.put(Float.class, new CustomNumberEditor(Float.class, true));
this.defaultEditors.put(double.class, new CustomNumberEditor(Double.class, false));
this.defaultEditors.put(Double.class, new CustomNumberEditor(Double.class, true));
this.defaultEditors.put(BigDecimal.class, new CustomNumberEditor(BigDecimal.class, true));
this.defaultEditors.put(BigInteger.class, new CustomNumberEditor(BigInteger.class, true));
// Only register config value editors if explicitly requested.
if (this.configValueEditorsActive) {
StringArrayPropertyEditor sae = new StringArrayPropertyEditor();
this.defaultEditors.put(String[].class, sae);
this.defaultEditors.put(short[].class, sae);
this.defaultEditors.put(int[].class, sae);
this.defaultEditors.put(long[].class, sae);
}
}
/**
* Copy the default editors registered in this instance to the given target registry.
* @param target the target registry to copy to
*/
protected void copyDefaultEditorsTo(PropertyEditorRegistrySupport target) {
target.defaultEditors = this.defaultEditors;
target.defaultEditorsActive = this.defaultEditorsActive;
target.configValueEditorsActive = this.configValueEditorsActive;
}
注册一个需要用到的属性类型编辑器
这个方法需要两个参数,属性的类型和能对这个类型做出处理的属性编辑器。他是通过
下面的方法的来实现主体注册的
注册共享的属性编辑器
通过属性的路径或者属性的类型来获取属性的编辑器
通过属性的类型来获取属性的编辑器。
u BeanWrapperImpl
BeanWrapperImpl类是对bean的封装类的BeanWrapper的实现,主要是设置bean的属性值,获取bean的类型的等操作。
下面是实例化的BeanWrapperImpl,注册默认的属性编辑器,调用的是从
PropertyEditorRegistrySupport中集成过来的。
获取到某个属性的PropertyDescriptor,
主要是通过调用getPropertyDescriptorInternal的方法来实现,这个方法是获取到当前对象的Class类的所有属性的PropertyDescriptor缓存容器,从容器中查找当前的名称的属性的PropertyDescriptor。
在上面的代码中当propertyName是普通属性的的名字(不包含.)返回的是当前对象this。
通过getPropertyType方法可以获取到指定属性名称的类型。
下面是获取到具体属性的值
我来具体的看下是怎么通过属性名称来获取拥有当前属性的实例对象.
先判断属性名称中有没有包含.当没有包含的时候直接返回当前对象,当包含.的时候实例化属性名称中包含的类.