对于最新的稳定版本,请使用 Spring Framework 6.2.0! |
依赖项和配置详细信息
如上一节所述,您可以定义 bean
properties 和构造函数参数作为对其他托管 bean (协作者) 的引用
或作为内联定义的值。Spring 基于 XML 的配置元数据支持
子元素类型中的<property/>
和<constructor-arg/>
元素
目的。
Straight 值(Primitives、Strings 等)
这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-namespace 以获得更简洁的 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(例如 IntelliJ IDEA 或 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
实例PropertyEditor
机制。这
是一个不错的快捷方式,并且是 Spring 团队确实喜欢使用
嵌套的<value/>
元素覆盖在value
属性样式。
这idref
元素
这idref
元素只是一种防错的方式,用于将id
(字符串值 - not
引用)附加到容器中另一个 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="client" class="...">
<property name="targetName" value="theTargetBean"/>
</bean>
第一种形式比第二种形式更可取,因为使用idref
标签允许
容器在部署时验证引用的名为 Bean 的实际
存在。在第二个变体中,不对传递的值执行验证
到targetName
属性的client
豆。拼写错误仅被发现(大多数
可能致命的结果),当client
bean 实际上是实例化的。如果client
bean 是一个原型 bean,这个拼写错误和结果异常
只有在部署容器很久之后才能被发现。
这local 属性idref 元素在 4.0 bean 中不再受支持
XSD 的 ID,因为它没有提供比常规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,则它可能会
已由容器初始化。所有引用最终都是对
另一个对象。范围界定和验证取决于您是指定
other 对象通过bean
或parent
属性。
通过bean
属性的<ref/>
标签是最
general 形式,并允许创建对同一容器中任何 bean 的引用,或者
父容器,无论它是否在同一个 XML 文件中。的bean
属性可能与id
属性或相同
作为name
目标 Bean 的属性。以下示例
演示如何使用ref
元素:
<ref bean="someBean"/>
通过parent
attribute 创建对 Bean 的引用
即在当前容器的父容器中。的parent
属性可以与id
目标 Bean 的属性或
值中的name
目标 Bean 的属性。目标 Bean 必须位于
当前容器的父容器。您应该主要使用此 bean 引用变体
当您具有容器层次结构并且希望将现有 bean 包装在父 bean 中时
容器,其代理与父 Bean 同名。以下一对
清单 显示了如何使用parent
属性:
<!-- in the parent context -->
<bean id="accountService" class="com.something.SimpleAccountService">
<!-- insert dependencies as required here -->
</bean>
<!-- in the child (descendant) context -->
<bean id="accountService" <!-- bean name is the same as the parent bean -->
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 的 ID,因为它没有提供比常规bean 参考。改变
您现有的ref local 参考资料ref bean 升级到 4.0 架构时。 |
内部 Bean
一个<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
标记
创建,因为内部 bean 始终是匿名的,并且总是使用外部 bean 创建
豆。无法独立访问内部 bean 或将它们注入
将 bean 协作到封闭 bean 中。
作为一种极端情况,可以从自定义范围接收销毁回调 — 例如,对于包含在单例 bean 中的请求范围的内部 bean。创作 的 Bean 实例绑定到其包含的 Bean,但销毁回调允许它 参与请求范围的生命周期。这不是常见情况。内豆 通常只是共享其包含的 bean 的 scope。
收集
这<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>
map 键或值的值,或者一个 set 值,也可以是 以下元素:
bean | ref | idref | list | set | map | props | value | null
集合合并
Spring 容器还支持合并集合。应用程序
developer 可以定义父级<list/>
,<map/>
,<set/>
或<props/>
元素
并有孩子<list/>
,<map/>
,<set/>
或<props/>
元素继承和
覆盖父集合中的值。也就是说,子集合的值为
将父集合和子集合的元素与子集合的
collection 元素覆盖父集合中指定的值。
本节关于合并讨论了父子 Bean 机制。不熟悉的读者 with 父 Bean 和 Child 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
collection 替换为父级的adminEmails
收集。以下清单
显示结果:
孩子Properties
collection 的值集继承了
父母<props/>
的 API 的support
value 覆盖
父集合。
此合并行为类似于<list/>
,<map/>
和<set/>
集合类型。在<list/>
元素、语义
与List
集合类型(即ordered
值的集合)的 Collection。parent的值位于所有child列表的
值。在Map
,Set
和Properties
集合类型,无排序
存在。因此,对于作为基础的集合类型,没有排序语义
关联的Map
,Set
和Properties
implementation types 中,容器
内部使用。
集合合并的限制
您不能合并不同的集合类型(例如Map
以及List
).如果你
请尝试这样做,适当的Exception
被抛出。这merge
attribute 必须为
在较低的继承子定义上指定。指定merge
属性
父集合定义是冗余的,不会导致所需的合并。
强类型集合
由于 Java 对泛型类型的支持,您可以使用强类型集合。
也就是说,可以声明Collection
类型,使其只能包含
(例如)String
元素。如果您使用 Spring 依赖注入
强类型Collection
添加到 bean 中,您可以利用 Spring 的
type-conversion 支持,以便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>
是
由 Reflection 提供。因此,Spring 的类型转换基础结构识别
各种 value 元素为 类型Float
和字符串值 (9.99
,2.75
和3.99
) 转换为实际的Float
类型。
Null 和空字符串值
Spring 将 properties 等的空参数视为空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 命名空间允许您使用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 没有 schema 定义,因此您可以设置属性的名称
添加到属性名称。
下一个示例包括另外两个 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-namespace 的属性值
但也使用特殊格式来声明属性引用。而第一个 bean
定义用途<property name="spouse" ref="jane"/>
从 Bean 创建引用john
到 Beanjane
,第二个 bean 定义使用p:spouse-ref="jane"
作为
属性来执行完全相同的作。在这种情况下,spouse
是属性名称,
而-ref
part 表示这不是一个直接的值,而是一个
引用另一个 bean。
p 命名空间不如标准 XML 格式灵活。例如,格式
用于声明属性引用与以Ref ,而
标准 XML 格式则不需要。我们建议您仔细选择方法,并
将此内容传达给您的团队成员,以避免生成使用全部
同时有三种方法。 |
带有 c-namespace 的 XML 快捷方式
类似于 Spring 中引入的带有 p-namespace 的 XML Shortcut、c-namespace
3.1 中,允许内联属性来配置构造函数参数,而不是
然后嵌套constructor-arg
元素。
以下示例使用c:
namespace 执行与 from Constructor-based Dependency Injection 相同的作:
<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:
namespace 使用与p:
one(尾随的-ref
为
Bean 引用)来按名称设置构造函数参数。同样地
它需要在 XML 文件中声明,即使它未在 XSD 架构中定义
(它存在于 Spring 核心中)。
对于构造函数参数名称不可用的极少数情况(通常如果 字节码在没有调试信息的情况下编译),您可以使用 fallback 到 ARGUMENT 索引,如下所示:
<!-- 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> 元素,但
不常用,因为 plain order of declaration 通常就足够了。 |
在实践中,构造函数解析机制在匹配方面非常有效 参数,因此,除非你真的需要,否则我们建议使用 name 表示法 在整个配置中。
复合属性名称
在设置 Bean 属性时,可以使用复合或嵌套属性名称,只要
除最终属性名称之外,路径的所有组件都不是null
.考虑一下
遵循 bean 定义:
<bean id="something" class="things.ThingOne">
<property name="fred.bob.sammy" value="123" />
</bean>
这something
Bean 的fred
属性,该属性具有bob
属性,该属性具有sammy
property 和最终的sammy
属性设置为123
.为了
this 要起作用,则fred
的属性something
和bob
的属性fred
莫
是null
在 bean 构造之后。否则,一个NullPointerException
被抛出。