对于最新的稳定版本,请使用 Spring Framework 6.2.0! |
Bean 操作和BeanWrapper
该软件包遵循 JavaBeans 标准。
JavaBean 是一个具有默认无参数构造函数的类,它遵循
命名约定,其中(例如)名为 would 的属性
具有 setter 方法和 getter 方法。为
有关 JavaBeans 和规范的更多信息,请参阅 JavaBeans。org.springframework.beans
bingoMadness
setBingoMadness(..)
getBingoMadness()
bean 包中一个非常重要的类是接口及其
相应的实现 ()。正如 javadoc 中引用的那样,提供了设置和获取属性值(单独或在
bulk)、获取属性描述符和查询属性以确定它们是否为
readable 或 writable。此外,它还提供对嵌套属性
将 子属性 的 属性设置为 无限深度 。还支持添加标准 JavaBeans 和 的功能,而无需在目标类中支持代码。
最后但并非最不重要的一点是,它支持设置索引属性。
通常不由应用程序代码直接使用,但由 和 使用 。BeanWrapper
BeanWrapperImpl
BeanWrapper
BeanWrapper
BeanWrapper
PropertyChangeListeners
VetoableChangeListeners
BeanWrapper
BeanWrapper
DataBinder
BeanFactory
它的工作方式部分由它的名称表示:它将一个 bean 包装到
对该 Bean 执行操作,例如设置和检索属性。BeanWrapper
设置和获取基本属性和嵌套属性
设置和获取属性是通过 的 和 重载方法变体完成的。请参阅他们的 Javadoc 以获取
详。下表显示了这些约定的一些示例:setPropertyValue
getPropertyValue
BeanWrapper
表达 | 解释 |
---|---|
|
指示与 or 和 方法对应的属性。 |
|
指示对应于
(例如)OR 方法。 |
|
指示 indexed property 的第三个元素 。索引属性
可以是 , , 或其他自然有序的集合。 |
|
指示由属性的键编制索引的映射条目的值。 |
(如果您不打算使用
的 直接 。如果您只使用 和 以及它们的默认实现,您应该跳到 PropertyEditor
部分。BeanWrapper
DataBinder
BeanFactory
以下两个示例类使用 to get 和 set
性能:BeanWrapper
-
Java
-
Kotlin
public class Company {
private String name;
private Employee managingDirector;
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public Employee getManagingDirector() {
return this.managingDirector;
}
public void setManagingDirector(Employee managingDirector) {
this.managingDirector = managingDirector;
}
}
class Company {
var name: String? = null
var managingDirector: Employee? = null
}
-
Java
-
Kotlin
public class Employee {
private String name;
private float salary;
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public float getSalary() {
return salary;
}
public void setSalary(float salary) {
this.salary = salary;
}
}
class Employee {
var name: String? = null
var salary: Float? = null
}
以下代码片段显示了如何检索和操作某些
实例化的 S 和 S 的特性:Company
Employee
-
Java
-
Kotlin
BeanWrapper company = new BeanWrapperImpl(new Company());
// setting the company name..
company.setPropertyValue("name", "Some Company Inc.");
// ... can also be done like this:
PropertyValue value = new PropertyValue("name", "Some Company Inc.");
company.setPropertyValue(value);
// ok, let's create the director and tie it to the company:
BeanWrapper jim = new BeanWrapperImpl(new Employee());
jim.setPropertyValue("name", "Jim Stravinsky");
company.setPropertyValue("managingDirector", jim.getWrappedInstance());
// retrieving the salary of the managingDirector through the company
Float salary = (Float) company.getPropertyValue("managingDirector.salary");
val company = BeanWrapperImpl(Company())
// setting the company name..
company.setPropertyValue("name", "Some Company Inc.")
// ... can also be done like this:
val value = PropertyValue("name", "Some Company Inc.")
company.setPropertyValue(value)
// ok, let's create the director and tie it to the company:
val jim = BeanWrapperImpl(Employee())
jim.setPropertyValue("name", "Jim Stravinsky")
company.setPropertyValue("managingDirector", jim.wrappedInstance)
// retrieving the salary of the managingDirector through the company
val salary = company.getPropertyValue("managingDirector.salary") as Float?
内置实现PropertyEditor
Spring 使用 a 的概念来实现 an 和 a 之间的转换。它可以很方便
以不同于对象本身的方式表示属性。例如,a 可以用人类可读的方式表示(如 :),而
我们仍然可以将人类可读的形式转换回原始日期(或者,甚至
更好的是,将以人类可读形式输入的任何日期转换回对象)。这
可以通过注册 类型的自定义编辑器来实现行为。在 or 上注册自定义编辑器,
或者,在特定的 IoC 容器中(如上一章所述),会给出
了解如何将属性转换为所需的类型。有关 的更多信息,请参阅 Oracle 的 java.beans
软件包的 javadoc。PropertyEditor
Object
String
Date
String
'2007-14-09'
Date
java.beans.PropertyEditor
BeanWrapper
PropertyEditor
在 Spring 中使用属性编辑的几个示例:
-
在 bean 上设置属性是通过使用实现来完成的。 当你将声明的某个 bean 的值用作 在 XML 文件中,Spring (如果相应属性的 setter 具有参数)用于尝试将参数解析为对象。
PropertyEditor
String
Class
ClassEditor
Class
-
在 Spring 的 MVC 框架中解析 HTTP 请求参数是通过使用各种来完成的 的实现,您可以在 .
PropertyEditor
CommandController
Spring 具有许多内置实现,使生活变得轻松。
它们都位于包中。默认情况下,大多数(但不是全部,如下表所示)由 注册。如果属性编辑器可以以某种方式进行配置,则可以
仍然注册你自己的变体来覆盖默认的变体。下表描述
Spring 提供的各种实现:PropertyEditor
org.springframework.beans.propertyeditors
BeanWrapperImpl
PropertyEditor
类 | 解释 |
---|---|
|
字节数组的编辑器。将字符串转换为相应的字节
交涉。默认情况下由 注册。 |
|
将表示类的 String 解析为实际的类,反之亦然。当
class 的 git 中,则会引发 an。默认情况下,由 注册。 |
|
用于属性的可自定义属性编辑器。默认情况下,由 registered by 但可以通过将其自定义实例注册为
自定义编辑器。 |
|
集合的 Property 编辑器,将任何源转换为给定的目标类型。 |
|
的可自定义属性编辑器 ,支持自定义 .不
registered (默认)。必须根据需要使用适当的格式进行用户注册。 |
|
任何子类的可自定义属性编辑器,例如 、 、 或 。默认情况下,由 registered by 但可以被
将其自定义实例注册为 Custom Editor。 |
|
将字符串解析为对象。默认情况下,由 注册。 |
|
单向属性编辑器,可以接受一个字符串并生成(通过
intermediate 和 ) an,以便可以直接将属性设置为字符串。请注意,默认用法不会关闭
的为你。默认情况下,由 注册。 |
|
可以将字符串解析为对象,反之亦然(字符串格式为 ,与 的方法相同)。还接受空格作为分隔符,作为下划线的替代项。
默认情况下,由 注册。 |
|
可以将字符串解析为对象,反之亦然。 |
|
可以将字符串(使用类的 javadoc 中定义的格式进行格式化)转换为对象。默认情况下,已注册
由。 |
|
修剪字符串的 Property editor。(可选)允许转换空字符串
转换为值。默认情况下未注册 — 必须由用户注册。 |
|
可以将 URL 的字符串表示形式解析为实际对象。
默认情况下,由 注册。 |
Spring 使用 来设置 属性的搜索路径
可能需要的编辑器。搜索路径还包括 ,其中
包括类型(如 、 和大多数
原始类型。另请注意,标准的 JavaBeans 基础结构
自动发现类(无需注册它们
显式地)如果它们与它们处理的类位于同一 package 中,并且具有相同的
name 作为该类,并附加例如,可以有以下内容
class 和 package 结构,这足以使 class 为
识别并用作 for -typed 属性。java.beans.PropertyEditorManager
sun.bean.editors
PropertyEditor
Font
Color
PropertyEditor
Editor
SomethingEditor
PropertyEditor
Something
com chank pop Something SomethingEditor // the PropertyEditor for the Something class
请注意,您也可以在此处使用标准的 JavaBeans 机制
(在这里有一定程度的描述)。这
以下示例使用该机制将一个或多个实例显式注册到 Associated Class 的属性中:BeanInfo
BeanInfo
PropertyEditor
com chank pop Something SomethingBeanInfo // the BeanInfo for the Something class
引用类的以下 Java 源代码
将 a 与类的属性相关联:SomethingBeanInfo
CustomNumberEditor
age
Something
-
Java
-
Kotlin
public class SomethingBeanInfo extends SimpleBeanInfo {
public PropertyDescriptor[] getPropertyDescriptors() {
try {
final PropertyEditor numberPE = new CustomNumberEditor(Integer.class, true);
PropertyDescriptor ageDescriptor = new PropertyDescriptor("age", Something.class) {
@Override
public PropertyEditor createPropertyEditor(Object bean) {
return numberPE;
}
};
return new PropertyDescriptor[] { ageDescriptor };
}
catch (IntrospectionException ex) {
throw new Error(ex.toString());
}
}
}
class SomethingBeanInfo : SimpleBeanInfo() {
override fun getPropertyDescriptors(): Array<PropertyDescriptor> {
try {
val numberPE = CustomNumberEditor(Int::class.java, true)
val ageDescriptor = object : PropertyDescriptor("age", Something::class.java) {
override fun createPropertyEditor(bean: Any): PropertyEditor {
return numberPE
}
}
return arrayOf(ageDescriptor)
} catch (ex: IntrospectionException) {
throw Error(ex.toString())
}
}
}
注册其他自定义实现PropertyEditor
当将 Bean 属性设置为字符串值时,Spring IoC 容器最终会使用
标准 JavaBeans 实现将这些字符串转换为
财产。Spring 预先注册了许多自定义实现(例如,将
将表示为 String 的类名转换为 Object)。此外
Java 的标准 JavaBeans 查找机制允许对类进行适当命名,并将其与类放在同一个包中
为此,它提供支持,以便可以自动找到它。PropertyEditor
PropertyEditor
Class
PropertyEditor
PropertyEditor
如果需要注册其他自定义,有几种机制是
可用。最手动的方法,通常不方便或
推荐,就是使用接口的方法,假设你有个参考。
另一种(稍微方便一点)机制是使用特殊的咖啡豆工厂
名为 .虽然您可以使用 Bean Factory 后处理器
对于实现,它有一个
nested 属性设置,因此我们强烈建议您将它与 一起使用,在那里您可以以与任何其他 bean 类似的方式部署它,并且
可以自动检测和应用。PropertyEditors
registerCustomEditor()
ConfigurableBeanFactory
BeanFactory
CustomEditorConfigurer
BeanFactory
CustomEditorConfigurer
ApplicationContext
请注意,所有 bean 工厂和应用程序上下文都会自动使用一些
内置属性编辑器,通过使用 TO
处理属性转换。寄存器的标准属性编辑器在上一节中列出。
此外,s 还会覆盖或添加其他编辑器来处理
资源查找。BeanWrapper
BeanWrapper
ApplicationContext
标准 JavaBeans 实例用于转换属性值
表示为属性的实际复杂类型的字符串。您可以使用 ,一个 bean factory 后处理器,方便地添加
支持将其他实例复制到 .PropertyEditor
CustomEditorConfigurer
PropertyEditor
ApplicationContext
请考虑以下示例,该示例定义了一个名为 和
另一个名为 的类,需要将其设置为属性:ExoticType
DependsOnExoticType
ExoticType
-
Java
-
Kotlin
package example;
public class ExoticType {
private String name;
public ExoticType(String name) {
this.name = name;
}
}
public class DependsOnExoticType {
private ExoticType type;
public void setType(ExoticType type) {
this.type = type;
}
}
package example
class ExoticType(val name: String)
class DependsOnExoticType {
var type: ExoticType? = null
}
当事情设置正确时,我们希望能够将 type 属性分配为
string,将其转换为实际实例。以下 Bean 定义显示了如何设置此关系:PropertyEditor
ExoticType
<bean id="sample" class="example.DependsOnExoticType">
<property name="type" value="aNameForExoticType"/>
</bean>
实现可能类似于以下内容:PropertyEditor
-
Java
-
Kotlin
package example;
import java.beans.PropertyEditorSupport;
// converts string representation to ExoticType object
public class ExoticTypeEditor extends PropertyEditorSupport {
public void setAsText(String text) {
setValue(new ExoticType(text.toUpperCase()));
}
}
package example
import java.beans.PropertyEditorSupport
// converts string representation to ExoticType object
class ExoticTypeEditor : PropertyEditorSupport() {
override fun setAsText(text: String) {
value = ExoticType(text.toUpperCase())
}
}
最后,以下示例显示了如何使用 向 注册 new,然后 将能够根据需要使用它:CustomEditorConfigurer
PropertyEditor
ApplicationContext
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="example.ExoticType" value="example.ExoticTypeEditor"/>
</map>
</property>
</bean>
用PropertyEditorRegistrar
向 Spring 容器注册属性编辑器的另一种机制是
创建并使用 .此接口在以下情况下特别有用
您需要在几种不同情况下使用同一组属性编辑器。
您可以编写相应的注册商并在每种情况下重复使用它。 实例与一个名为 的接口一起工作,该接口由 Spring(和 )实现。 实例特别方便
当与 (在此处描述) 结合使用时,它会公开一个属性
叫。 已添加的实例
以这种方式可以轻松共享给 和
Spring MVC 控制器。此外,它还避免了在自定义时进行同步的需要
editors:A 应为每次 bean 创建尝试创建新的实例。PropertyEditorRegistrar
PropertyEditorRegistrar
PropertyEditorRegistry
BeanWrapper
DataBinder
PropertyEditorRegistrar
CustomEditorConfigurer
setPropertyEditorRegistrars(..)
PropertyEditorRegistrar
CustomEditorConfigurer
DataBinder
PropertyEditorRegistrar
PropertyEditor
以下示例显示如何创建自己的实现:PropertyEditorRegistrar
-
Java
-
Kotlin
package com.foo.editors.spring;
public final class CustomPropertyEditorRegistrar implements PropertyEditorRegistrar {
public void registerCustomEditors(PropertyEditorRegistry registry) {
// it is expected that new PropertyEditor instances are created
registry.registerCustomEditor(ExoticType.class, new ExoticTypeEditor());
// you could register as many custom property editors as are required here...
}
}
package com.foo.editors.spring
import org.springframework.beans.PropertyEditorRegistrar
import org.springframework.beans.PropertyEditorRegistry
class CustomPropertyEditorRegistrar : PropertyEditorRegistrar {
override fun registerCustomEditors(registry: PropertyEditorRegistry) {
// it is expected that new PropertyEditor instances are created
registry.registerCustomEditor(ExoticType::class.java, ExoticTypeEditor())
// you could register as many custom property editors as are required here...
}
}
另请参阅 for an example implementation.请注意,在该方法的实现中,它是如何为每个属性编辑器创建新实例的。org.springframework.beans.support.ResourceEditorRegistrar
PropertyEditorRegistrar
registerCustomEditors(..)
下一个示例演示如何配置实例并注入实例
我们进入它:CustomEditorConfigurer
CustomPropertyEditorRegistrar
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="propertyEditorRegistrars">
<list>
<ref bean="customPropertyEditorRegistrar"/>
</list>
</property>
</bean>
<bean id="customPropertyEditorRegistrar"
class="com.foo.editors.spring.CustomPropertyEditorRegistrar"/>
最后(与本章的重点有点不同)给你们这些人
使用 Spring 的 MVC Web 框架,在
与数据绑定 Web 控制器结合使用可以非常方便。以下内容
example 在方法的实现中使用 a:PropertyEditorRegistrar
PropertyEditorRegistrar
@InitBinder
-
Java
-
Kotlin
@Controller
public class RegisterUserController {
private final PropertyEditorRegistrar customPropertyEditorRegistrar;
RegisterUserController(PropertyEditorRegistrar propertyEditorRegistrar) {
this.customPropertyEditorRegistrar = propertyEditorRegistrar;
}
@InitBinder
void initBinder(WebDataBinder binder) {
this.customPropertyEditorRegistrar.registerCustomEditors(binder);
}
// other methods related to registering a User
}
@Controller
class RegisterUserController(
private val customPropertyEditorRegistrar: PropertyEditorRegistrar) {
@InitBinder
fun initBinder(binder: WebDataBinder) {
this.customPropertyEditorRegistrar.registerCustomEditors(binder)
}
// other methods related to registering a User
}
这种注册样式可以产生简洁的代码(实现
的方法只有一行长),并允许将通用注册码封装在一个类中,然后在尽可能多的控制器之间共享
根据需要。PropertyEditor
@InitBinder
PropertyEditor