3.3. Bean 操作和BeanWrapper
最后更新于
最后更新于
org.springframework.beans
包遵循 JavaBeans 标准。JavaBean 是具有默认无参数构造函数的类,并且遵循命名约定,其中(例如)命名bingoMadness
的属性将具有setBingoMadness(..)
setter 方法和getBingoMadness()
getter 方法。有关 JavaBeans 和规范的更多信息,请参阅 javabeans。
bean 包中一个非常重要的类是BeanWrapper
接口及其对应的实现(BeanWrapperImpl
)。正如从 javadoc 中引用的那样, BeanWrapper
提供了设置和获取属性值(单独或批量)、获取属性描述符和查询属性以确定它们是可读还是可写的功能。此外,BeanWrapper
还提供对嵌套属性的支持,使子属性上的属性设置可以无限深。BeanWrapper
还支持添加标准 JavaBeans 的能力, PropertyChangeListeners
和VetoableChangeListeners
无需在目标类中支持代码。最后但并非最不重要的一点是,BeanWrapper
提供了对设置索引属性的支持。通常不由应用程序代码直接使用BeanWrapper
,而是由 DataBinder
和BeanFactory
.
BeanWrapper
工作方式部分由其名称表示:它包装一个 bean 以对该 bean 执行操作,例如设置和检索属性。
3.3.1. 设置和获取基本和嵌套属性
设置和获取属性是通过 BeanWrapper
的 setPropertyValue
和 getPropertyValue
重载方法变体完成的. 有关详细信息,请参阅他们的 Javadoc。下表显示了这些约定的一些示例:
表达式 | 备注 |
---|---|
(如果您不打算直接使用 BeanWrapper
,那么下一部分对您来说并不重要。如果您只使用DataBinder
和 BeanFactory
以及它们的默认实现,您应该跳到关于 的PropertyEditors
部分。)
以下两个示例类使用BeanWrapper
来获取和设置属性:
以下代码片段显示了一些示例,说明如何检索和操作实例化的Company
s 和Employee
s 的某些属性:
3.3.2. 内置PropertyEditor
实现
Spring 使用PropertyEditor
的概念来实现 Object
和String
之间的转换。以与对象本身不同的方式表示属性可能很方便。例如,Date
可以以人类可读的方式表示(如String
: '2007-14-09'
),而我们仍然可以将人类可读的形式转换回原始日期(或者,更好的是,将以人类可读的形式输入的任何日期转换回Date
对象)。这种行为可以通过注册自定义类型的编辑器java.beans.PropertyEditor
来实现 。在一个特定的 IoC 容器中注册自定义编辑器BeanWrapper
(如前一章所述),使其了解如何将属性转换为所需的类型。有关PropertyEditor
更多信息 ,请参阅java.beans
来自 Oracle 的软件包。
在 Spring 中使用属性编辑的几个示例:
在 bean 上设置属性是通过使用PropertyEditor
实现来完成的。当您使用String
在 XML 文件中声明的某个 bean 的属性值时,Spring(如果相应属性的设置器有Class
参数)ClassEditor
会尝试将参数解析为Class
对象。
在 Spring 的 MVC 框架中解析 HTTP 请求参数是通过使用各种PropertyEditor
实现来完成的,您可以在 CommandController
.
Spring 有许多内置的PropertyEditor
实现来简化生命周期。它们都位于org.springframework.beans.propertyeditors
包中。大多数(但不是全部,如下表所示)默认情况下由 BeanWrapperImpl
注册. 如果可以以某种方式配置属性编辑器,您仍然可以注册自己的变体来覆盖默认变体。下表描述了Spring PropertyEditor
提供的各种实现:
Spring 使用java.beans.PropertyEditorManager
为可能需要的属性编辑器设置搜索路径。搜索路径还包括sun.bean.editors
,其中包括诸如Font
、Color
和大多数基本类型的PropertyEditor
实现。另请注意,标准 JavaBeans 基础结构会自动发现PropertyEditor
类(无需显式注册它们),前提是它们与它们处理的类在同一个包中并且与该类具有相同的名称,并带有Editor
后缀。例如,可以具有以下类和包结构,这足以使SomethingEditor
该类被识别并用作Something
类型的属性的PropertyEditor
。
请注意,您也可以在此处使用标准BeanInfo
JavaBeans 机制(在此处进行了一定程度的描述 )。以下示例使用BeanInfo
机制显式注册一个或多个 具有关联类属性的PropertyEditor
实例:
被SomethingBeanInfo
引用类的以下 Java 源代码将CustomNumberEditor
与Something
类的age
属性相关联:
注册其他自定义PropertyEditor
实现
当将 bean 属性设置为字符串值时,Spring IoC 容器最终使用标准 JavaBeansPropertyEditor
实现将这些字符串转换为属性的复杂类型。Spring 预先注册了许多自定义PropertyEditor
实现(例如,将表示为字符串的类名转换为Class
对象)。此外,Java 的标准 JavaBeansPropertyEditor
查找机制允许PropertyEditor
对类进行适当命名,并将其放置在与其提供支持的类相同的包中,以便可以自动找到它。
如果需要注册其他自定义PropertyEditors
,可以使用多种机制。最手动的方法,通常不方便或不推荐,是使用 ConfigurableBeanFactory
接口的registerCustomEditor()
方法,假设您有参考BeanFactory
。另一种(稍微方便一点)机制是使用一个特殊的 bean factory 后处理器,称为CustomEditorConfigurer
. 尽管您可以将 bean factory 后处理器与BeanFactory
实现一起使用,但CustomEditorConfigurer
具有嵌套属性设置,因此我们强烈建议您将其与 ApplicationContext
应用。
请注意,所有 bean 工厂和应用程序上下文都会自动使用许多内置属性编辑器,通过它们使用 BeanWrapper
来处理属性转换。上一节列出了BeanWrapper
寄存器的标准属性编辑器。此外,ApplicationContext
还覆盖或添加额外的编辑器,以便以适合特定应用程序上下文类型的方式处理资源查找。
标准 JavaBeansPropertyEditor
实例用于将表示为字符串的属性值转换为属性的实际复杂类型。您可以使用 bean 工厂后处理器CustomEditorConfigurer
,方便地将对其他PropertyEditor
实例的支持添加到ApplicationContext
.
考虑以下示例,它定义了一个名为ExoticType
的用户类和另一个名为DependsOnExoticType
的类,需要将其ExoticType
设置为属性:
正确设置后,我们希望能够将 type 属性分配为字符串,然后将其PropertyEditor
转换为实际 ExoticType
实例。以下 bean 定义显示了如何设置这种关系:
PropertyEditor
实现可能类似于以下内容:
最后,以下示例显示了如何使用CustomEditorConfigurer
向 ApplicationContext
注册新的 PropertyEditor
,然后可以根据需要使用它:
使用PropertyEditorRegistrar
向 Spring 容器注册属性编辑器的另一种机制是创建和使用PropertyEditorRegistrar
. 当您需要在几种不同的情况下使用同一组属性编辑器时,此接口特别有用。您可以编写相应的注册器并在每种情况下重复使用它。 PropertyEditorRegistrar
实例与名为 PropertyEditorRegistry
的接口一起工作,该接口由 Spring BeanWrapper
(and DataBinder
) 实现。PropertyEditorRegistrar
实例与CustomEditorConfigurer
( 在此处描述)结合使用时特别方便,它公开了一个名为setPropertyEditorRegistrars(..)
的方法. 以这种方式添加到PropertyEditorRegistrar
的CustomEditorConfigurer
实例可以很容易地与DataBinder
和 Spring MVC 控制器共享。此外,它避免了在自定义编辑器上进行同步的需要:PropertyEditorRegistrar
预计会 为每个 bean 创建尝试创建新PropertyEditor
实例。
以下示例显示了如何创建自己的PropertyEditorRegistrar
实现:
另请参阅org.springframework.beans.support.ResourceEditorRegistrar
示例 PropertyEditorRegistrar
实现。请注意在 registerCustomEditors(..)
方法的实现中,它如何创建每个属性编辑器的新实例。
下一个示例展示了如何配置CustomEditorConfigurer
并将我们的实例CustomPropertyEditorRegistrar
注入其中:
最后(有点偏离本章的重点)对于那些使用Spring 的 MVC Web 框架的人来说,将 PropertyEditorRegistrar
与数据绑定 Web 控制器结合使用会非常方便。以下示例在@InitBinder
方法的实现中使用 PropertyEditorRegistrar
:
这种注册PropertyEditor
风格可以带来简洁的代码(@InitBinder
方法的实现只有一行长),并且可以将通用的PropertyEditor
注册代码封装在一个类中,然后根据需要在尽可能多的控制器之间共享。
类 | 备注 |
---|---|
name
指示与 getName()
或 isName()
和setName(..)
方法对应的属性名称。
account.name
指示对应于(例如) getAccount().setName()
或getAccount().getName()
方法的属性帐户的嵌套属性名称。
account[2]
指示索引属性account
的第三个元素。索引属性可以是array
、list
或其他自然排序的集合。
account[COMPANYNAME]
指示由 account
Map
属性的 COMPANYNAME 键索引的映射条目的值。
ByteArrayPropertyEditor
字节数组的编辑器。将字符串转换为其对应的字节表示。默认注册为BeanWrapperImpl
。
ClassEditor
将表示类的字符串解析为实际类,反之亦然。当找不到类时,抛出一个IllegalArgumentException
。默认情况下,由 BeanWrapperImpl
注册 。
CustomBooleanEditor
可自定义的Boolean
属性编辑器。默认情况下,注册者为BeanWrapperImpl
, 但可以通过将其自定义实例注册为自定义编辑器来覆盖。
CustomCollectionEditor
集合的属性编辑器,将任何Collection
源转换为给定的目标 Collection
类型。
CustomDateEditor
可定制的java.util.Date
属性编辑器,支持自定义DateFormat
。默认未注册。必须根据需要使用适当的格式进行用户注册。
CustomNumberEditor
任何子类的可定制Number
属性编辑器,例如Integer
、Long
、Float
或 Double
. 默认情况下,注册者为BeanWrapperImpl
,但可以通过将其自定义实例注册为自定义编辑器来覆盖。
FileEditor
将字符串解析为java.io.File
对象。默认情况下,由BeanWrapperImpl
注册 。
InputStreamEditor
单向属性编辑器,可以接受一个字符串并产生(通过一个中间ResourceEditor
和Resource
)InputStream
,以便InputStream
可以将属性直接设置为字符串。请注意,默认用法不会为您关闭InputStream
。默认情况下,由 BeanWrapperImpl
注册。
LocaleEditor
可以将字符串解析为Locale
对象,反之亦然(字符串格式为 [language]_[country]_[variant]
,与Locale
的方法toString()
相同)。也接受空格作为分隔符,作为下划线的替代。默认情况下,由 BeanWrapperImpl
注册。
PatternEditor
可以将字符串解析为java.util.regex.Pattern
对象,反之亦然。
PropertiesEditor
可以将java.util.Properties
字符串(使用类的 javadoc 中定义的格式格式化 )转换为Properties
对象。默认情况下,由BeanWrapperImpl
注册。
StringTrimmerEditor
修剪字符串的属性编辑器。可选地允许将空字符串转换为null
值。默认情况下未注册 - 必须是用户注册的。
URLEditor
可以将 URL 的字符串表示解析为实际URL
对象。默认情况下,由BeanWrapperImpl
注册。