1.4 依赖(part2)

官方英文版地址:https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html

备注:翻译如有不对,请多指正,谢谢。

1.4.2. Dependencies and configuration in detail

依赖与配置详解

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属性或者构造函数参数用来引用其他被管理的协作beans,或者内置的基本类型值。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的转换服务( conversion service )用于将这些值从字符串转换成属性或参数的实际类型。

<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命名空间( 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更加简洁,然后,除非你使用像IntelliJ IDEA或者Spring Tool Suite(STS)类似的支持在进行bean定义时自动属性填充的IDE,否则将会在运行时而不是在设计时才会发现拼写错误。强烈推荐使用这些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>
</bean>

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>属性少数几个地方之一。

The idref element

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真实存在。在第二个变体中,不会在client对象的targetName属性上设置的值进行任何校验。只有在client初始化时才会发现输入错误(可能导致严重的后果)。如果client是原型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.

<idref>元素带来好处的一个常用地方就是在ProxyFactoryBean定义中的AOP拦截器配置(AOP interceptors )。使用<idref>元素可以防止在指定拦截器时对拦截器id的拼接错误。

References to other beans (collaborators)

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、本地或者父属性指定其他对象的id/name。

Specifying the target bean through the bean attribute of the <ref/> 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.

不管是否是在相同的xml文件中,通过<ref/>标签的bean属性指定目标bean是最常用的形式,并且允许创建对相同容器或者父容器中任何bean的引用。<ref/>元素的bean属性可能和目标bean的id属性或者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.

通过parent属性来指定目标bean,会创建一个对当前容器父容器中bean对象的引用。parent属性的值可能和目标bean的id相同,异或是和目标bean的name属性值的任何一个值相同,而目标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 bean when upgrading to the 4.0 schema.

<ref/>元素的local属性,由于不支持常规bean引用之外的值,所以在4.0 beans xsd中已经不再支持。当升级到4.0的时候,只需要简单的将存在的ref local引用改为ref bean引用即可。

Inner beans

A <bean/> element inside the <property/> or <constructor-arg/> elements defines a so-called inner bean.

在<property/>或者<constructor-arg/>元素中的<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 always created 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.

内部类定义并不需要声明的Id或者name属性,如果指定的话,容器也不会使用它们作为唯一标识符。容器在创建的时候也会忽略scope标识:内部bean总是匿名的,并且和包含它的外部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的创建是和包含它的容器联系在一起的,但是销毁回调允许在请求作用域声明周期内发生。这并不是常见的场景,内部类一般简单的和包含它的容器拥有相同的作用域。

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">[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>

The value of a map key or value, or a set value, can also again be any of the following elements:

map结构的key或者value值,以及set结构的值,可以是下面几种类型中的任何一种。

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 <list/>, <map/>, <set/> or <props/> element, and have child-style <list/>, <map/>, <set/> or <props/> elements inherit and override values from the parent collection. That is, the child collection’s values are the result of merging the elements of the parent and child collections, with the child’s collection elements overriding values specified in the parent collection.

Spring容器支持集合的合并。应用程序开发者可以定义一个父类型的<list/>、<map/>、<set/>或者<props/>元素,并且拥有一个子类型的<list/>、<map/>、<set/>或者<props/>来集成或者重写父容器中的元素值。这就是说,子集合中的值是将父集合和子集合中的元素合并后的结果,子集合中的元素可能覆写了在父集合中指定的值。

The following example demonstrates collection merging:

接下来的例子展示了集合的合并:

<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>

Notice the use of the merge=true attribute on the <props/> 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 Properties collection 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属性集合,这个集合中包含了父集合和子集合中的所有元素。

[email protected]
[email protected]
[email protected]

The child Properties collection’s value set inherits all property elements from the parent <props/>, and the child’s value for the support value overrides the value in the parent collection.

子集合中的Properties,继承了父元素<props/>中的所有元素,子集合中的support属性值覆写了父集合中的同名属性。

This merging behavior applies similarly to the <list/>, <map/>, and <set/> collection types. In the specific case of the <list/> element, the semantics associated with the List collection type, that is, the notion of an ordered collection of values, is maintained; the parent’s values precede all of the child list’s values. In the case of the Map, Set, and Properties collection types, no ordering exists. Hence no ordering semantics are in effect for the collection types that underlie the associated Map, Set, and Properties implementation types that the container uses internally.

这个合并的行为在<list/>、<map/>、<set/>集合类型中的作用是相似的。在<list/>这个特殊的例子中,维护中集合中元素的顺序,和Java类型List的元素的顺序和<list/>元素中定义的顺序一致,父集合中的值在子集合中的值的前面。在Map、Set和Properties集合类型中,不会维护元素的顺序。对于内部使用关联映射的类型,没有任何排序语义。

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 merge attribute on a parent collection definition is redundant and will not result in the desired merging.

你不能将不同集合类型(如Map和List)进行合并,如果你尝试去这么做,将会抛出一个异常。merge属性必须在子定义中进行指定,在父集合定义中指定merge属性是多余的,不会导致所需的合并效果。

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.

伴随着Java5之后泛型类型的引入,你可以使用强类型集合。这就是说,可以定义一个集合类型值包含String元素(举个例子)成为可能。如果你使用Spring将强类型集合注入到bean中,你可以充分利用Spring的类型转换支持,以便在将元素添加到集合前将这些元素转换为合适的类型。

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 Float type.

当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 <null/> element handles null values. For example:

<null/>元素处理null值。举个例子:

<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

The p-namespace enables you to use the bean element’s attributes, instead of nested <property/> elements, to describe your property values and/or collaborating beans.

你可以使用p命名空间,而不是<property>元素,来描述你的属性值或者协作bean。

Spring supports extensible configuration formats with namespaces, which are based on an XML Schema definition. The beans configuration 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支持使用命名空间形式的扩展配置,在本章中讨论的bean配置是以XML文档的方式定义的,然而,p命名空间并不是在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="[email protected]"/>
    </bean>

    <bean name="p-namespace" class="com.example.ExampleBean"
        p:email="[email protected]"/>
</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定义中有个使用p命名空间定义的email属性。p命名空间告诉Spring包含一个属性声明。如前面说明,p命名空间没有模式定义,在p后面可以设置属性的名称。

This next example includes two more bean definitions that both have a reference to another bean:

接下来的例子包含了两个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 <property name="spouse" ref="jane"/> 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命名空间的property值,还包含了特殊形式声明的property引用。第一个bean定义使用<property name="spouse" ref="jane">来创建一个对jane的引用,第二个bean定义使用p:spouse-ref="jane"来做相同的事情。在这个例子中,spouse是一个属性名,-ref用来表示它不是一个简单的值,而是一个对其他bean的引用。

XML shortcut with the c-namespace

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命名空间相似,c命名空间,是在Spring3.1之后才引入的,可以使用内联属性来配置构造参数,而不是使用<constructor-arg>元素。

Let’s review the examples from Constructor-based dependency injection with the c: namespace:

让我们使用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
        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="[email protected]"/>
    </bean>

    <!-- c-namespace declaration -->
    <bean id="foo" class="x.y.Foo" c:bar-ref="bar" c:baz-ref="baz" c:email="[email protected]"/>

</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命名空间相同的转换形式来设置构造参数,末尾使用-ref来标识bean引用。即使在XSD模式中没有定义,单同样需要声明它。

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"/>

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 null after the bean is constructed, or a NullPointerException is thrown.

foo这个bean有一个fred属性,而fred属性含有一个bob属性,这个bob属性又含有一个sammy属性,这个sammy属性的值为123。为了使这个配置生效,在bean被创建之后,fred属性和bob属性都不能为null,否则将抛出一个空指针异常。

猜你喜欢

转载自blog.csdn.net/andamajing/article/details/81711326
1.4