1.4.2. Dependencies and configuration in detail
1.4.2. 详细的依赖和配置
As mentioned in the previous section, you can define bean properties and constructor arguments as references to other managed beans (collaborators), or as values defined inline. Spring’s XML-based configuration metadata supports sub-element types within its <property/> and <constructor-arg/> elements for this purpose.
如前一节所述,您可以将bean属性和构造函数参数定义为对其他受管Bean(协作者)的引用,或者将其定义为内联定义的值。 Spring的基于XML的配置元数据为此支持其**<property />和<constructor-arg />**元素中的子元素类型。
Straight values (primitives, Strings, and so on)
直接值(基元,字符串等)
The value attribute of the <property/> element specifies a property or constructor argument as a human-readable string representation. Spring’s conversion service is used to convert these values from a String to the actual type of the property or argument.
<property /> 元素的value属性将属性或构造函数参数指定为可读的字符串表示形式。 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="masterkaoli"/>
</bean>
The following example uses the p-namespace for even more succinct XML configuration.
以下示例使用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
http://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="masterkaoli"/>
</beans>
The preceding XML is more succinct; however, typos are discovered at runtime rather than design time, unless you use an IDE such as IntelliJ IDEA or the Spring Tool Suite (STS) that support automatic property completion when you create bean definitions. Such IDE assistance is highly recommended.
前面的XML更简洁; 然而,在运行时而不是设计时发现错字,除非您在创建bean定义时使用支持自动属性完成的IDE(如IntelliJ IDEA或Spring Tool Suite(STS))。 强烈建议这种IDE帮助。
You can also configure a java.util.Properties instance as:
您还可以将java.util.Properties实例配置为:
<bean id="mappings" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<!-- 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>
The Spring container converts the text inside the <value/> element into a java.util.Properties instance by using the JavaBeans PropertyEditor mechanism. This is a nice shortcut, and is one of a few places where the Spring team do favor the use of the nested <value/> element over the value attribute style.
Spring容器通过使用JavaBeans PropertyEditor机制将**<value />元素内的文本转换为java.util.Properties实例。 这是一个很好的捷径,也是Spring团队倾向于使用嵌套的<value />元素覆盖value**属性样式的几个地方之一。
The idref element
idref元素**
The idref element is simply an error-proof way to pass the id (string value - not a reference) of another bean in the container to a <constructor-arg/> or <property/> element.
idref元素只是一种防错的方式,可以将容器中另一个bean的id(字符串值 - 不是引用)传递给**<constructor-arg />或<property />**元素。
<bean id="theTargetBean" class="..."/>
<bean id="theClientBean" class="...">
<property name="targetName">
<idref bean="theTargetBean"/>
</property>
</bean>
The above bean definition snippet is exactly equivalent (at runtime) to the following snippet:
上面的bean定义片段与下面的片段完全等价(在运行时):
<bean id="theTargetBean" class="..." />
<bean id="client" class="...">
<property name="targetName" value="theTargetBean"/>
</bean>
The first form is preferable to the second, because using the idref tag allows the container to validate at deployment time that the referenced, named bean actually exists. In the second variation, no validation is performed on the value that is passed to the targetName property of the client bean. Typos are only discovered (with most likely fatal results) when the client bean is actually instantiated. If the client bean is a prototype bean, this typo and the resulting exception may only be discovered long after the container is deployed.
第一种形式比第二种形式要好,因为使用idref标签允许容器在部署时验证引用的命名bean实际存在。 在第二种变体中,不会对传递给客户机bean的targetName属性的值执行验证。 当客户端bean实际实例化时,才会发现Typos(最可能致命的结果)。 如果客户端bean是原型bean,则此类型错误和生成的异常可能仅在部署容器后很长时间才能发现。
The local attribute on the idref element is no longer supported in the 4.0 beans xsd since it does not provide value over a regular bean reference anymore. Simply change your existing idref local references to idref bean when upgrading to the 4.0 schema.
4.0 bean xsd中不再支持idref元素的本地属性,因为它不再提供超过常规bean引用的值。 升级到4.0架构时,只需将现有的idref本地引用更改为idref bean。
A common place (at least in versions earlier than Spring 2.0) where the <idref/> element brings value is in the configuration of AOP interceptors in a ProxyFactoryBean bean definition. Using <idref/> elements when you specify the interceptor names prevents you from misspelling an interceptor id.
一个普通的地方(至少在Spring 2.0之前的版本中)**<idref />元素带来价值的地方在于ProxyFactoryBean bean定义中的AOP拦截器的配置。指定拦截器名称时使用<idref />**元素可以防止拼写错误拦截器ID。
References to other beans (collaborators)
参考其他beans(协作者)
The ref element is the final element inside a <constructor-arg/> or <property/> definition element. Here you set the value of the specified property of a bean to be a reference to another bean (a collaborator) managed by the container. The referenced bean is a dependency of the bean whose property will be set, and it is initialized on demand as needed before the property is set. (If the collaborator is a singleton bean, it may be initialized already by the container.) All references are ultimately a reference to another object. Scoping and validation depend on whether you specify the id/name of the other object through the bean, local, or parent attributes.
ref元素是**<constructor-arg />或<property />**定义元素中的最后一个元素。在这里,您将bean的指定属性的值设置为对容器管理的另一个bean(协作者)的引用。被引用的bean是其属性将被设置的bean的依赖项,并且在属性设置之前根据需要初始化它。 (如果协作者是单例bean,它可能已被容器初始化。)所有引用最终都是对另一个对象的引用。范围和验证取决于您是通过bean,local或parent属性指定另一个对象的id / name。
Specifying the target bean through the bean attribute of the tag is the most general form, and allows creation of a reference to any bean in the same container or parent container, regardless of whether it is in the same XML file. The value of the bean attribute may be the same as the id attribute of the target bean, or as one of the values in the name attribute of the target bean.
通过标记的bean属性指定目标bean是最通用的形式,并且允许创建对同一个容器或父容器中的任何bean的引用,而不管它是否位于同一个XML文件中。 bean属性的值可以与目标bean的id属性相同,或者作为目标bean的name属性中的一个值。
<ref bean="someBean"/>
Specifying the target bean through the parent attribute creates a reference to a bean that is in a parent container of the current container. The value of the parent attribute may be the same as either the id attribute of the target bean, or one of the values in the name attribute of the target bean, and the target bean must be in a parent container of the current one. You use this bean reference variant mainly when you have a hierarchy of containers and you want to wrap an existing bean in a parent container with a proxy that will have the same name as the parent bean.
通过父属性指定目标bean将创建对当前容器的父容器中的bean的引用。父属性的值可以与目标bean的id属性相同,也可以与目标bean的name属性中的一个值相同,并且目标bean必须位于当前bean的父容器中。您主要在具有容器层次结构时使用此bean参考变体,并且想要使用与父bean名称相同的代理将父容器中的现有bean包装在父容器中。
<!-- in the parent context -->
<bean id="accountService" class="com.foo.SimpleAccountService">
<!-- insert dependencies as required as 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>
The local attribute on the ref element is no longer supported in the 4.0 beans xsd since it does not provide value over a regular bean reference anymore. Simply change your existing ref local references to ref beanwhen upgrading to the 4.0 schema.
4.0 bean xsd不再支持ref元素的本地属性,因为它不再提供超过常规bean引用的值。升级到4.0模式时,只需将现有的ref本地引用更改为ref bean。
Inner beans
内部 beans
A element inside the or elements defines a so-called inner bean.
或元素中的元素定义了一个所谓的内部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>
An inner bean definition does not require a defined id or name; if specified, the container does not use such a value as an identifier. The container also ignores the scope flag on creation: Inner beans are always anonymous and they are alwayscreated with the outer bean. It is not possible to inject inner beans into collaborating beans other than into the enclosing bean or to access them independently.
内部bean定义不需要定义的id或名称;如果指定,容器不使用这样的值作为标识符。容器在创建时也会忽略范围标志:内部bean始终是匿名的,并且它们始终使用外部bean创建。不可能将内部bean注入到除了封装bean之外的协作bean中,或者独立访问它们。
As a corner case, it is possible to receive destruction callbacks from a custom scope, e.g. for a request-scoped inner bean contained within a singleton bean: The creation of the inner bean instance will be tied to its containing bean, but destruction callbacks allow it to participate in the request scope’s lifecycle. This is not a common scenario; inner beans typically simply share their containing bean’s scope.
作为角落案例,可以从自定义范围接收销毁回调,例如,对于包含在单例bean中的请求范围的内部bean:内部bean实例的创建将绑定到它的包含bean,但是销毁回调允许它参与请求范围的生命周期。这不是一个常见的情况;内部bean通常简单地分享它们包含的bean的范围。
Collections
集合
In the <list/>, <set/>, <map/>, and <props/> elements, you set the properties and arguments of the Java Collection types List, Set, Map, and Properties, respectively.
在 <list/>, <set/>, <map/>, 和 **<props/>**元素中,分别设置Java集合类型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">administrator@example.org</prop>
<prop key="support">support@example.org</prop>
<prop key="development">development@example.org</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>
The value of a map key or value, or a set value, can also again be any of the following elements:
映射键或值或设置值的值也可以是以下任何元素:
bean | ref | idref | list | set | map | props | value | null
Collection merging
集合合并
The Spring container also supports the merging of collections. An application developer can define a parent-style ,
<beans>
<bean id="parent" abstract="true" class="example.ComplexObject">
<property name="adminEmails">
<props>
<prop key="administrator">administrator@example.com</prop>
<prop key="support">support@example.com</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">sales@example.com</prop>
<prop key="support">support@example.co.uk</prop>
</props>
</property>
</bean>
</beans>
Notice the use of the merge=true attribute on the element of the adminEmails property of the child bean definition. When the child bean is resolved and instantiated by the container, the resulting instance has an adminEmails Propertiescollection that contains the result of the merging of the child’s adminEmails collection with the parent’s adminEmails collection.
注意在子bean定义的adminEmails属性的元素上使用merge = true属性。 当子bean由容器解析并实例化时,生成的实例具有一个adminEmails属性集合,该集合包含合并子级的adminEmails集合与父级的adminEmails集合的结果。
administrator=administrator@example.com
sales=sales@example.com
support=support@example.co.uk
The child Properties collection’s value set inherits all property elements from the parent , and the child’s value for the support value overrides the value in the parent collection.
子集“属性”集合的值集继承父级中的所有属性元素,并且子级的支持值值覆盖父级集合中的值。
This merging behavior applies similarly to the ,
这种合并行为类似地适用于,
Limitations of collection merging
收集合并的限制
You cannot merge different collection types (such as a Map and a List), and if you do attempt to do so an appropriate Exception is thrown. The merge attribute must be specified on the lower, inherited, child definition; specifying the mergeattribute on a parent collection definition is redundant and will not result in the desired merging.
您不能合并不同的集合类型(例如Map和List),并且如果确实尝试这样做,则会引发适当的Exception。合并属性必须在较低的继承的子定义上指定;在父集合定义上指定合并属性是多余的,并且不会导致所需的合并。
Strongly-typed collection
强类型集合
With the introduction of generic types in Java 5, you can use strongly typed collections. That is, it is possible to declare a Collection type such that it can only contain String elements (for example). If you are using Spring to dependency-inject a strongly-typed Collection into a bean, you can take advantage of Spring’s type-conversion support such that the elements of your strongly-typed Collection instances are converted to the appropriate type prior to being added to the Collection.
随着Java 5中引入泛型类型,您可以使用强类型集合。也就是说,可以声明一个Collection类型,使其只能包含String元素(例如)。如果您使用Spring将强类型集合依赖注入到bean中,则可以利用Spring的类型转换支持,使强类型Collection实例的元素在添加到之前转换为适当的类型集合。
public class Foo {
private Map<String, Float> accounts;
public void setAccounts(Map<String, Float> accounts) {
this.accounts = accounts;
}
}
<beans>
<bean id="foo" class="x.y.Foo">
<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>
When the accounts property of the foo bean is prepared for injection, the generics information about the element type of the strongly-typed Map<String, Float> is available by reflection. Thus Spring’s type conversion infrastructure recognizes the various value elements as being of type Float, and the string values 9.99, 2.75, and 3.99 are converted into an actual Floattype.
当foo bean的accounts属性准备注入时,有关强类型Map <String,Float>的元素类型的泛型信息可通过反射获得。 因此,Spring的类型转换基础结构将各种值元素识别为类型为Float,并将字符串值9.99,2.75和3.99转换为实际的Float类型。
Null and empty string values
空和空字符串值
Spring treats empty arguments for properties and the like as empty Strings. The following XML-based configuration metadata snippet sets the email property to the empty String value (“”).
Spring将空的参数作为空字符串处理。 以下基于XML的配置元数据片段将email属性设置为空字符串值(“”)。
<bean class="ExampleBean">
<property name="email" value=""/>
</bean>
The preceding example is equivalent to the following Java code:
前面的示例等同于以下Java代码:
exampleBean.setEmail("");
The element handles null values. For example:
元素处理空值。 例如:
<bean class="ExampleBean">
<property name="email">
<null/>
</property>
</bean>
The above configuration is equivalent to the following Java code:
以上配置相当于以下Java代码:
exampleBean.setEmail(null);
XML shortcut with the p-namespace
带有p命名空间的XML快捷方式
The p-namespace enables you to use the bean element’s attributes, instead of nested elements, to describe your property values and/or collaborating beans.
p-命名空间使您可以使用bean元素的属性来代替嵌套的元素来描述属性值和/或合作bean。
Spring supports extensible configuration formats with namespaces, which are based on an XML Schema definition. The beansconfiguration format discussed in this chapter is defined in an XML Schema document. However, the p-namespace is not defined in an XSD file and exists only in the core of Spring.
Spring支持带有命名空间的可扩展配置格式,这些命名空间基于XML模式定义。 本章中讨论的bean配置格式是在XML Schema文档中定义的。 但是,p-namespace并未在XSD文件中定义,而只存在于Spring的核心中。
The following example shows two XML snippets that resolve to the same result: The first uses standard XML format and the second uses the p-namespace.
以下示例显示了解析为相同结果的两个XML片段:第一个使用标准XML格式,第二个使用p命名空间。
<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
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean name="classic" class="com.example.ExampleBean">
<property name="email" value="foo@bar.com"/>
</bean>
<bean name="p-namespace" class="com.example.ExampleBean"
p:email="foo@bar.com"/>
</beans>
The example shows an attribute in the p-namespace called email in the bean definition. This tells Spring to include a property declaration. As previously mentioned, the p-namespace does not have a schema definition, so you can set the name of the attribute to the property name.
该示例在bean定义中显示了名为email的p名称空间中的一个属性。 这告诉Spring包含一个属性声明。 如前所述,p-名称空间没有模式定义,因此您可以将该属性的名称设置为属性名称。
This next example includes two more bean definitions that both have a reference to another bean:
下一个示例包含两个更多的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
http://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>
As you can see, this example includes not only a property value using the p-namespace, but also uses a special format to declare property references. Whereas the first bean definition uses to create a reference from bean john to bean jane, the second bean definition uses p:spouse-ref=“jane” as an attribute to do the exact same thing. In this case spouse is the property name, whereas the -ref part indicates that this is not a straight value but rather a reference to another bean.
正如你所看到的,这个例子不仅包含使用p-命名空间的属性值,还使用特殊格式来声明属性引用。第一个bean定义使用<property name =“spouse”ref =“jane”/>来创建bean bean的引用,第二个bean定义使用p:spouse-ref =“jane”作为属性完全一样的东西。在这种情况下,配偶是属性名称,而-ref部分表明这不是一个正值,而是对另一个bean的引用。
The p-namespace is not as flexible as the standard XML format. For example, the format for declaring property references clashes with properties that end in Ref, whereas the standard XML format does not. We recommend that you choose your approach carefully and communicate this to your team members, to avoid producing XML documents that use all three approaches at the same time.
p-名称空间不如标准XML格式那么灵活。例如,声明属性引用的格式与以Ref结尾的属性冲突,而标准XML格式则不会。我们建议您谨慎选择您的方法,并将其传达给您的团队成员,以避免生成同时使用所有三种方法的XML文档。
XML shortcut with the c-namespace
带有c-namespace的XML快捷方式
Similar to the XML shortcut with the p-namespace, the c-namespace, newly introduced in Spring 3.1, allows usage of inlined attributes for configuring the constructor arguments rather then nested constructor-arg elements.
与带有p-名称空间的XML快捷方式类似,Spring 3.1中新引入的c-名称空间允许使用内联属性来配置构造函数参数,而不是嵌套构造函数arg元素。
Let’s review the examples from Constructor-based dependency injection with the c: namespace:
让我们回顾一下基于构造函数的依赖注入与c:namespace的例子:
<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
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="bar" class="x.y.Bar"/>
<bean id="baz" class="x.y.Baz"/>
<!-- traditional declaration -->
<bean id="foo" class="x.y.Foo">
<constructor-arg ref="bar"/>
<constructor-arg ref="baz"/>
<constructor-arg value="foo@bar.com"/>
</bean>
<!-- c-namespace declaration -->
<bean id="foo" class="x.y.Foo" c:bar-ref="bar" c:baz-ref="baz" c:email="foo@bar.com"/>
</beans>
The c: namespace uses the same conventions as the p: one (trailing -ref for bean references) for setting the constructor arguments by their names. And just as well, it needs to be declared even though it is not defined in an XSD schema (but it exists inside the Spring core).
c:命名空间使用与p:1相同的约定(尾随-ref作为bean引用),用于通过名称设置构造函数参数。 同样,即使它没有在XSD模式中定义(但它存在于Spring内核中),也需要声明它。
For the rare cases where the constructor argument names are not available (usually if the bytecode was compiled without debugging information), one can use fallback to the argument indexes:
对于构造函数参数名称不可用的罕见情况(通常如果字节码是在没有调试信息的情况下编译的),可以使用回退参数索引:
<!-- c-namespace index declaration -->
<bean id="foo" class="x.y.Foo" c:_0-ref="bar" c:_1-ref="baz"/>
Due to the XML grammar, the index notation requires the presence of the leading _ as XML attribute names cannot start with a number (even though some IDE allow it).
由于XML语法,索引表示法要求存在前导_,因为XML属性名称不能以数字开头(即使某些IDE允许)。
In practice, the constructor resolution mechanism is quite efficient in matching arguments so unless one really needs to, we recommend using the name notation through-out your configuration.
实际上,构造器解析机制在匹配参数方面非常有效,所以除非真的需要,否则我们建议在整个配置中使用名称符号。
Compound property names
复合属性名称
You can use compound or nested property names when you set bean properties, as long as all components of the path except the final property name are not null. Consider the following bean definition.
在设置bean属性时,只要最终属性名称以外的路径的所有组件都不为null,就可以使用复合或嵌套属性名称。 考虑下面的bean定义。
<bean id="foo" class="foo.Bar">
<property name="fred.bob.sammy" value="123" />
</bean>
The foo bean has a fred property, which has a bob property, which has a sammy property, and that final sammy property is being set to the value 123. In order for this to work, the fred property of foo, and the bob property of fred must not be nullafter the bean is constructed, or a NullPointerException is thrown.
foo bean有一个fred属性,它有一个bob属性,它具有sammy属性,并且最终sammy属性被设置为值123.为了使其工作,foo的fred属性和bob属性 在构造bean之后,fred一定不能为null,否则抛出NullPointerException。