1.4.2.依赖关系和详细配置

如前一节所述,您可以将bean属性和构造函数参数定义为对其他bean(合作者)的引用,或者定义为内联的值。XML的配置支持其<property/><constructor arg/>元素中的子元素类型。

直接类型(基本类型 、String等)
Spring的转换服务用于将这些值从字符串转换为属性或参数的实际类型。以下示例显示了正在设置的各种值:

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

以下示例使用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="masterkaoli"/>

</beans>

前面的XML更加简洁。使用一个IDE(如Intellij IDEA或Spring Tool Suite),支持属性自动提示,不然易写错,而没有提示。

还可以配置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>

Spring容器使用JavaBeans PropertyEditor 机制将<value/>元素中的文本转换为java.util.properties实例。这是一个很好的快捷方式,也是Spring团队支持使用嵌套的<value/>元素而不是值属性样式的少数地方之一。

idref元素
idref元素只是将容器中另一个bean的id(字符串值,而不是引用)传递给<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标记可以让容器在部署时验证引用的、命名为theTargetBean的是否存在。在第二种中,不会对传递给客户机bean的targetName属性的值执行任何验证。只有当客户机bean实际被实例化时,才会发现拼写错误(最有可能是致命的结果)。如果客户机bean是prototype bean,那么只有在部署容器很长时间之后,才会发现产生的异常。

beans XSD 4.0版本idref元素不再支持local属性,因为它不再提供常规bean引用的值。在升级到4.0模式时,把现有idref local改为idref bean引用。

<idref/>元素带来的好处(至少在Spring2.0之前的版本中)是在ProxyFactoryBean Bean定义中AOP拦截器的配置中,指定拦截器名称时使用<idref/>元素可防止您拼写错误拦截器ID。

对其他bean(合作者)的引用
ref元素对另一个bean(合作者)的引用。引用的bean要先初始化(如果合作者是单例bean,那么它可能已经由容器初始化)。ref元素引用bean属性的值可以与目标bean的id属性相同,也可以与目标bean的name属性中的一个值相同。以下示例显示如何使用ref元素:

<ref bean="someBean"/>

内部类bean
<property/><constructor arg/>元素中的元素定义了一个内部bean,如下示例所示:

<bean id="outer" class="...">
    <!-- 不要使用对目标bean的引用,只需在内联中定义目标bean-->
    <property name="target">
        <bean class="com.example.Person"> <!-- 这里是内部bean -->
            <property name="name" value="Fiona Apple"/>
            <property name="age" value="25"/>
        </bean>
    </property>
</bean>

内部bean定义不需要定义的ID或名称。如果指定,则容器也不使用此类值作为标识符。容器在创建时也忽略范围标志,因为内部bean总是匿名的,并且总是用外部bean创建的。不可能单独访问内部bean,也不可能将它们注入到其它bean中。

集合类
XML文件中, , ,和 元素代表了JAVA中的这些集合类:List, Set, Map,和Properties。 下面例子显示他们如何使用:

<bean id="moreComplexObject" class="example.ComplexObject">
    <!-- setAdminEmails(java.util.Properties)调用的结果-->
    <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>
    <!-- setSomeList(java.util.List) 调用的结果 -->
    <property name="someList">
        <list>
            <value>a list element followed by a reference</value>
            <ref bean="myDataSource" />
        </list>
    </property>
    <!-- setSomeMap(java.util.Map)调用的结果 -->
    <property name="someMap">
        <map>
            <entry key="an entry" value="just some string"/>
            <entry key ="a ref" value-ref="myDataSource"/>
        </map>
    </property>
    <!-- setSomeSet(java.util.Set)调用的结果-->
    <property name="someSet">
        <set>
            <value>just some string</value>
            <ref bean="myDataSource" />
        </set>
    </property>
</bean>

map的key or value, 或set的value, 也可以是以下任何元素:

bean | ref | idref | list | set | map | props | value | null

Null 和空字符串值
Spring将空参数视为空字符串。以下XML的配置片段将email属性设置为空字符串值(""):

<bean class="ExampleBean">
    <property name="email" value=""/>
</bean>

前面的示例相当于下面的Java代码:

exampleBean.setEmail("");

<null/>元素代表空值。以下列表显示了一个示例:

<bean class="ExampleBean">
    <property name="email">
        <null/>
    </property>
</bean>

前面的示例相当于下面的Java代码:

exampleBean.setEmail(null);

具有p-namespace的XML快捷方式
p-namespace允许您使用bean元素的属性(而不是嵌套的<property/>元素)来描述协作bean或两者的属性值。
Spring支持基于XML模式定义的带有命名空间的可扩展配置格式。本章讨论的bean配置格式在XML模式文档中定义。但是,p-namespace没有在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="someone@somewhere.com"/>
    </bean>

    <bean name="p-namespace" class="com.example.ExampleBean"
        p:email="someone@somewhere.com"/>
</beans>

该示例在bean定义中显示了用p-namespace指定名为email的属性。这告诉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-namespace的属性值,还使用特殊格式声明属性引用。虽然第一个bean定义使用 <property name="spouse" ref="jane"/>来创建从john bean到 jane bean的引用,但是第二个bean定义使用p:spouse-ref="jane" 作为属性来执行完全相同的操作。在这种情况下, spouse 是属性名,而-ref部分表明这不是一个直接值,而是对另一个bean的引用。

p-namespace不如标准XML格式灵活。例如,声明属性引用的格式与以ref结尾的属性冲突,而标准XML格式则不冲突。我们建议您仔细选择方法,并将其传达给您的团队成员,以避免生成同时使用这三种方法的XML文档。

具有c-namespace的XML快捷方式
和p-namespace,因为现在很少直接写XML的配置了,这里就不讲,有兴趣可去查看。

复合属性名称
设置bean属性时,可以使用复合或嵌套属性名,只要路径上的所有组件(除了最终属性名)不为空。考虑以下bean定义:

<bean id="something" class="things.ThingOne">
    <property name="fred.bob.sammy" value="123" />
</bean>

something bean有一个fred属性,而fred有一个bob属性,bob有一个sammy属性,最后一个sammy属性被设置为123。为了使其工作,在构造bean之后,something的fred属性和fred的bob属性不能为空。否则,将引发NullPointerException。