此版本仍在开发中,尚不被认为是稳定的。对于最新的稳定版本,请使用 Spring Framework 6.2.10! |
依赖关系和配置的详细信息
如上一节所述,您可以将 bean 属性和构造函数参数定义为对其他托管 bean 的引用(协作者)或内联定义的值。Spring 基于 XML 的配置元数据支持sub-element 类型在其<property/>
和<constructor-arg/>
元素。
直值(基元、字符串等)
这value
属性的<property/>
元素指定属性或构造函数参数作为人类可读的字符串表示。Spring 的转换服务用于转换这些值String
设置为属性或参数的实际类型。以下示例显示了设置的各种值:
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<!-- results in a setDriverClassName(String) call -->
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mydb"/>
<property name="username" value="root"/>
<property name="password" value="misterkaoli"/>
</bean>
以下示例使用 p 命名空间来更简洁地XML 配置:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close"
p:driverClassName="com.mysql.jdbc.Driver"
p:url="jdbc:mysql://localhost:3306/mydb"
p:username="root"
p:password="misterkaoli"/>
</beans>
前面的 XML 更简洁。但是,拼写错误是在运行时发现的,而不是设计时,除非您使用 IDE(例如 IntelliJIDEA 或 Spring Tools for Eclipse),支持在创建 Bean 定义时自动完成属性。此类 IDE强烈建议提供帮助。
您还可以配置java.util.Properties
实例,如下所示:
<bean id="mappings"
class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<!-- typed as a java.util.Properties -->
<property name="properties">
<value>
jdbc.driver.className=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mydb
</value>
</property>
</bean>
Spring 容器将<value/>
元素转换为java.util.Properties
使用 JavaBeansPropertyEditor
机制。 这 是一个不错的捷径,也是 Spring 团队确实喜欢使用嵌套的<value/>
元素在value
属性样式。
这idref
元素
这idref
元素只是一种传递id
(字符串值 - 不是引用)容器中另一个 bean 的<constructor-arg/>
或<property/>
元素。 以下示例演示如何使用它:
<bean id="theTargetBean" class="..."/>
<bean id="theClientBean" class="...">
<property name="targetName">
<idref bean="theTargetBean"/>
</property>
</bean>
前面的 bean 定义片段完全等同于(在运行时)以下片段:
<bean id="theTargetBean" class="..." />
<bean id="theClientBean" class="...">
<property name="targetName" ref="theTargetBean"/>
</bean>
第一种形式比第二种形式更可取,因为使用idref
标签让container 在部署时验证引用的命名 bean 实际上 存在。 在第二个变体中,不对传递的值执行验证到targetName
属性的client
豆。 拼写错误只有在client
bean 实际上是实例化的。如果client
bean 是一个原型 bean,这个拼写错误和由此产生的异常可能只有在容器部署很久之后才会被发现。
这local 属性idref 元素在 4.0 bean 中不再受支持XSD,因为它不提供比常规bean 参考更多。 改变 您现有的idref local 引用idref bean 升级到 4.0 架构时。 |
一个常见的地方(至少在 Spring 2.0 之前的版本中),其中<idref/>
元素 带来的价值在于 AOP 拦截器的配置ProxyFactoryBean
bean 定义。 用<idref/>
元素,当您指定拦截器名称时,可以防止您拼写错误拦截器 ID。
对其他 Bean(协作者)的引用
这ref
元素是<constructor-arg/>
或<property/>
definition 元素。在这里,您将 bean 的指定属性的值设置为对容器管理的另一个 bean(协作者)的引用。引用的 bean是要设置其属性的 bean 的依赖项,并且根据需要初始化在设置属性之前根据需要。(如果协作者是单例 bean,则它可能已经由容器初始化。所有引用最终都是对另一个对象的引用。范围和验证取决于您是指定 ID 还是名称其他对象通过bean
或parent
属性。
通过bean
属性的<ref/>
标签是最通用形式,并允许在同一容器或父容器中创建对任何 bean 的引用,无论它是否在同一个 XML 文件中。的值bean
属性可能与id
属性或相同作为name
属性。以下示例显示如何使用ref
元素:
<ref bean="someBean"/>
通过parent
属性创建对 bean 的引用该 bean 位于当前容器的父容器中。的值parent
属性可以与id
属性或
值name
属性。目标 Bean 必须位于
当前容器的父容器。您应该主要使用此 bean 引用变体
当您有一个容器层次结构并且想要将现有 Bean 包装在父 Bean 中时
容器,其代理与父 Bean 具有相同的名称。以下一对
listings 展示了如何使用parent
属性:
<!-- in the parent context -->
<bean id="accountService" class="com.something.SimpleAccountService">
<!-- insert dependencies as required here -->
</bean>
<!-- in the child (descendant) context, bean name is the same as the parent bean -->
<bean id="accountService"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<ref parent="accountService"/> <!-- notice how we refer to the parent bean -->
</property>
<!-- insert other configuration and dependencies as required here -->
</bean>
这local 属性ref 元素在 4.0 bean 中不再受支持XSD,因为它不提供比常规bean 参考更多。 改变 您现有的ref local 引用ref bean 升级到 4.0 架构时。 |
内豆
一个<bean/>
元素<property/>
或<constructor-arg/>
元素定义了一个
inner bean,如以下示例所示:
<bean id="outer" class="...">
<!-- instead of using a reference to a target bean, simply define the target bean inline -->
<property name="target">
<bean class="com.example.Person"> <!-- this is the inner bean -->
<property name="name" value="Fiona Apple"/>
<property name="age" value="25"/>
</bean>
</property>
</bean>
内部 Bean 定义不需要定义的 ID 或名称。如果指定,则容器
不使用此类值作为标识符。容器还忽略了scope
标记 on
creation,因为内部 bean 始终是匿名的,并且始终与外部 bean 一起创建
豆。无法独立访问内部 bean 或将它们注入
协作 Bean 以外的 Bean。
作为一种极端情况,可以从自定义作用域接收销毁回调——例如,对于单例 Bean 中包含的请求范围的内部 Bean。创作 的内部 bean 实例绑定到其包含的 bean,但销毁回调允许它 参与请求范围的生命周期。这不是一种常见的情况。内豆 通常只是共享其包含的 bean 的作用域。
收集
这<list/>
,<set/>
,<map/>
和<props/>
元素设置属性
和 Java 的论点Collection
类型List
,Set
,Map
和Properties
,
分别。以下示例显示了如何使用它们:
<bean id="moreComplexObject" class="example.ComplexObject">
<!-- results in a setAdminEmails(java.util.Properties) call -->
<property name="adminEmails">
<props>
<prop key="administrator">[email protected]</prop>
<prop key="support">[email protected]</prop>
<prop key="development">[email protected]</prop>
</props>
</property>
<!-- results in a setSomeList(java.util.List) call -->
<property name="someList">
<list>
<value>a list element followed by a reference</value>
<ref bean="myDataSource" />
</list>
</property>
<!-- results in a setSomeMap(java.util.Map) call -->
<property name="someMap">
<map>
<entry key="an entry" value="just some string"/>
<entry key="a ref" value-ref="myDataSource"/>
</map>
</property>
<!-- results in a setSomeSet(java.util.Set) call -->
<property name="someSet">
<set>
<value>just some string</value>
<ref bean="myDataSource" />
</set>
</property>
</bean>
映射键或值的值,或设置值,也可以是 以下元素:
bean | ref | idref | list | set | map | props | value | null
集合合并
Spring 容器还支持合并集合。应用程序
developer 可以定义父级<list/>
,<map/>
,<set/>
或<props/>
元素
并生孩子<list/>
,<map/>
,<set/>
或<props/>
元素继承和
覆盖父集合中的值。也就是说,子集合的值为
将父集合和子集合的元素与子集合的
集合元素覆盖父集合中指定的值。
关于合并的这一节讨论父子 Bean 机制。读者不熟悉 对于父 Bean 和子 Bean 定义,在继续之前,可能希望阅读相关部分。
以下示例演示了集合合并:
<beans>
<bean id="parent" abstract="true" class="example.ComplexObject">
<property name="adminEmails">
<props>
<prop key="administrator">[email protected]</prop>
<prop key="support">[email protected]</prop>
</props>
</property>
</bean>
<bean id="child" parent="parent">
<property name="adminEmails">
<!-- the merge is specified on the child collection definition -->
<props merge="true">
<prop key="sales">[email protected]</prop>
<prop key="support">[email protected]</prop>
</props>
</property>
</bean>
<beans>
请注意merge=true
属性<props/>
元素的adminEmails
属性的child
bean 定义。当child
bean 已解析
并由容器实例化,则生成的实例具有adminEmails
Properties
包含合并子项的adminEmails
集合与父级的adminEmails
收集。以下列表
显示结果:
孩子Properties
集合的值集从
父母<props/>
,而孩子的值support
value 覆盖
父集合。
此合并行为类似于<list/>
,<map/>
和<set/>
集合类型。在具体情况下<list/>
元素,语义
与List
集合类型(即ordered
值集合)被维护。父级的值位于所有子列表的
值。在Map
,Set
和Properties
集合类型,无排序
存在。因此,对于基础的集合类型,没有排序语义有效
关联的Map
,Set
和Properties
容器的实现类型
内部使用。
集合合并的局限性
您不能合并不同的集合类型(例如Map
和List
).如果你
尝试这样做,适当的Exception
被抛出。这merge
属性必须是
在较低的继承子定义上指定。指定merge
属性
父集合定义是冗余的,不会导致所需的合并。
强类型集合
由于 Java 对泛型类型的支持,您可以使用强类型集合。
也就是说,可以声明一个Collection
类型,使其只能包含
(例如)String
元素。如果您使用 Spring 依赖注入一个
强类型Collection
变成 bean,你可以利用 Spring 的
类型转换支持,以便强类型的元素Collection
实例在添加到Collection
. 以下 Java 类和 bean 定义显示了如何执行此作:
-
Java
-
Kotlin
public class SomeClass {
private Map<String, Float> accounts;
public void setAccounts(Map<String, Float> accounts) {
this.accounts = accounts;
}
}
class SomeClass {
lateinit var accounts: Map<String, Float>
}
<beans>
<bean id="something" class="x.y.SomeClass">
<property name="accounts">
<map>
<entry key="one" value="9.99"/>
<entry key="two" value="2.75"/>
<entry key="six" value="3.99"/>
</map>
</property>
</bean>
</beans>
当accounts
属性的something
bean 准备注入,泛型有关强类型的元素类型的信息Map<String, Float>
是 可通过反射获得。因此,Spring 的类型转换基础设施将各种值元素识别为类型Float
,字符串值 (9.99
,2.75
和3.99
) 转换为实际的Float
类型。
空字符串值和空字符串值
Spring 将属性等的空参数视为空Strings
.这
以下基于 XML 的配置元数据代码段将email
属性到空的String
值(“”)。
<bean class="ExampleBean">
<property name="email" value=""/>
</bean>
前面的示例等效于以下 Java 代码:
-
Java
-
Kotlin
exampleBean.setEmail("");
exampleBean.email = ""
这<null/>
元素句柄null
值。以下列表显示了一个示例:
<bean class="ExampleBean">
<property name="email">
<null/>
</property>
</bean>
上述配置等效于以下 Java 代码:
-
Java
-
Kotlin
exampleBean.setEmail(null);
exampleBean.email = null
带有 p 命名空间的 XML 快捷方式
p-namespace 允许您使用bean
元素的属性(而不是嵌套的<property/>
元素)来描述您的属性值、协作 bean 或两者。
Spring 支持带有命名空间的可扩展配置格式,
这些基于 XML 模式定义。这beans
配置格式在
本章在 XML Schema 文档中定义。但是,没有定义 p 命名空间
在 XSD 文件中,并且仅存在于 Spring 的核心中。
以下示例显示了两个 XML 片段(第一个使用 标准 XML 格式,第二个使用 p-namespace),解析为相同的结果:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean name="classic" class="com.example.ExampleBean">
<property name="email" value="[email protected]"/>
</bean>
<bean name="p-namespace" class="com.example.ExampleBean"
p:email="[email protected]"/>
</beans>
该示例显示了 p 命名空间中名为email
在 bean 定义中。
这告诉 Spring 包含一个属性声明。如前所述,
p-namespace 没有模式定义,因此您可以设置属性的名称
到属性名称。
下一个示例包括另外两个 bean 定义,它们都引用了 另一个 bean:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean name="john-classic" class="com.example.Person">
<property name="name" value="John Doe"/>
<property name="spouse" ref="jane"/>
</bean>
<bean name="john-modern"
class="com.example.Person"
p:name="John Doe"
p:spouse-ref="jane"/>
<bean name="jane" class="com.example.Person">
<property name="name" value="Jane Doe"/>
</bean>
</beans>
此示例不仅包括使用 p 命名空间的属性值
但也使用特殊格式来声明属性引用。而第一个 bean
定义用途<property name="spouse" ref="jane"/>
从 bean 创建引用john
到豆jane
,第二个 bean 定义使用p:spouse-ref="jane"
作为
属性来做完全相同的事情。在这种情况下,spouse
是属性名称,
而-ref
part 表示这不是一个直接值,而是一个
引用另一个 bean。
p 命名空间不如标准 XML 格式灵活。例如,格式
用于声明属性引用与结尾为Ref ,而
标准 XML 格式则不然。我们建议您谨慎选择方法,并
将此信息传达给您的团队成员,以避免生成使用
同时进行三种方法。 |
带有 c 命名空间的 XML 快捷方式
与带有 p 命名空间的 XML 快捷方式类似,
Spring 3.1 中引入的 c-namespace 允许内联属性进行配置
构造函数参数而不是嵌套constructor-arg
元素。
以下示例使用c:
命名空间来执行与基于构造函数的依赖注入相同的作:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="beanTwo" class="x.y.ThingTwo"/>
<bean id="beanThree" class="x.y.ThingThree"/>
<!-- traditional declaration with optional argument names -->
<bean id="beanOne" class="x.y.ThingOne">
<constructor-arg name="thingTwo" ref="beanTwo"/>
<constructor-arg name="thingThree" ref="beanThree"/>
<constructor-arg name="email" value="[email protected]"/>
</bean>
<!-- c-namespace declaration with argument names -->
<bean id="beanOne" class="x.y.ThingOne" c:thingTwo-ref="beanTwo"
c:thingThree-ref="beanThree" c:email="[email protected]"/>
</beans>
这c:
命名空间使用与p:
一(尾随-ref
为
bean 引用)用于按名称设置构造函数参数。同样地
它需要在 XML 文件中声明,即使它未在 XSD 模式中定义
(它存在于 Spring 核心中)。
对于构造函数参数名称不可用的极少数情况(通常如果
字节码是在没有-parameters
标志),您可以回退到
参数索引,如下所示:
<!-- c-namespace index declaration -->
<bean id="beanOne" class="x.y.ThingOne" c:_0-ref="beanTwo" c:_1-ref="beanThree"
c:_2="[email protected]"/>
由于 XML 语法,索引表示法需要存在前导 ,
因为 XML 属性名称不能以数字开头(即使某些 IDE 允许)。
相应的索引表示法也可用于_ <constructor-arg> 元素,但
不常用,因为简单的声明顺序通常就足够了。 |
在实践中,构造函数解析机制在匹配参数方面非常有效,因此除非您确实需要,否则我们建议 在整个配置中使用名称表示法。
复合属性名称
设置 bean 属性时,可以使用复合或嵌套属性名称,只要
除最终属性名称外,路径的所有组件都不是null
.考虑一下
以下 bean 定义:
<bean id="something" class="things.ThingOne">
<property name="fred.bob.sammy" value="123" />
</bean>
这something
bean 有一个fred
属性,其中具有bob
属性,其中具有sammy
属性,并且最终sammy
属性设置为123
.为了
这要工作,fred
属性something
和bob
属性fred
莫
是null
在 bean 构建之后。否则,一个NullPointerException
被抛出。