• Spring框架参考手册(4.2.6版本)翻译——第三部分 核心技术 6.4.2 依赖注入和配置的细节


    6.1.1 细节上的依赖注入和配置

    如上一节所述,你可以将bean属性和构造函数参数定义为对其他托管bean(协作者)的引用,或者作为内联定义的值。为此,Spring的基于XML的配置元数据支持其<property /><constructor-arg />元素中的子元素类型。

    直接值(基本类型、String等)

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

    以下示例使用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
        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>

    前面的XML更简洁; 但是,除非你在创建bean定义时使用支持自动属性填充的IntelliJ IDEASpring Tool SuiteSTS)等IDE,否则会在运行时而不是设计时发现拼写错误。强烈建议使用IDE帮助。

    你还可以将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实例。嵌套<value />元素是一个很好的快捷方式,并且是Spring团队推荐使用的少数几个地方之一。

    idref元素

    idref元素只是一种防错方法,可以将容器中另一个beanid(字符串值 - 而不是引用)传递给<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是实际存在的。在第二个变体中,不会对传递给client beantargetName属性的值执行验证。当client bean实际实例化时,才会发现错误(最有可能导致致命结果)。 如果client bean是原型bean,则只能在部署容器后很长时间才能发现此错误和产生的异常。

    注意:4.0 beans xsd不再支持idref元素的local属性,因为它不再提供值给常规bean的引用。 在升级到4.0架构时,只需将现有的idref本地引用更改为idref bean即可。

    <idref />元素传值的常见地方(至少在Spring 2.0之前的版本中)是在AOP拦截器的配置中定义ProxyFactoryBean bean的地方。指定拦截器名称时使用<idref />元素可以防止拦截器ID拼写错误。

    对其他Bean的引用

    ref元素是<constructor-arg /><property />定义元素中的最后一个元素。在这里,你将bean的指定属性的值设置为对容器管理的另一个bean(协作者)的引用。引用的bean是属性将被设置的bean的依赖项,并且在设置属性之前根据需要按需初始化。(如果协作者是单例bean,它可能已经被容器初始化了。)所有引用最终都是对另一个对象的引用。作用范围和校验取决于你是否通过beanlocalparent属性指定其他对象的id / name

    通过<ref />标记的bean属性指定目标bean是最常用的形式,并允许创建对同一容器或父容器中的任何bean的引用,而不管它是否在同一个XML文件中。bean属性的值可以与目标beanid属性相同,也可以是目标beanname属性中的值之一。

    <ref bean="someBean"/>

    通过parent属性指定目标bean会创建一个属于当前容器的父容器中的bean的引用。 parent属性的值可以与目标beanid属性相同,也可以与目标beanname属性中的一个值相同,并且目标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>

    注意:4.0 bean xsd不再支持ref元素的local属性,因为它不再提供常规bean引用的值。 升级到4.0架构时,只需将现有的ref本地引用更改为ref bean

    内部Bean

    <property /><constructor-arg />元素中的<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>

    内部bean定义不需要定义的id或名称; 如果指定,则容器不使用此类值作为标识符。容器还会在创建时忽略scope标志:内部bean始终是匿名的,并且始终通过外部bean创建它们。 除了注入到封闭bean,不可能将内部bean注入协作bean,或者单独访问它们。

    作为极端情况,可以接收来自自定义范围的销毁回调,例如,对一个包含在单例bean中的request范围的内部bean:内部bean实例的创建将绑定到其包含的bean,但是销毁回调允许它加入到request范围的生命周期中。这不是常见的情况; 内部bean通常只是共享其包含bean的范围。

    集合

    <list /><set /><map /><props />元素中,分别设置Java Collection类型ListSetMapProperties的属性和参数。

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

    mapkey值或者value值,或者set值,也可以是以下任何元素:

    bean | ref | idref | list | set | map | props | value | null
    集合合并

    Spring容器还支持集合的合并。 应用程序开发人员可以定义<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">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>

    注意在子bean定义的adminEmails属性的<props />元素上使用merge = true属性。当容器解析并实例化子bean时,生成的实例有一个adminEmails属性集合,其中包含子项的adminEmails集合与父项的adminEmails集合的合并结果。

    administrator=administrator@example.com

    sales=sales@example.com

    support=support@example.co.uk

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

    此合并行为同样适用于<list /><map /><set />集合类型。 在<list />元素的特定情况下,保持与List集合类型相关联的语义,即有序的值集合的概念; 父级的值位于所有子级列表的值之前。对于MapSetProperties集合类型,不存在排序。因此,对于作为容器内部使用的,以MapSetProperties实现类型为基础的集合类型,没有排序语义。

    集合合并的局限性

    你不能合并不同的集合类型(例如MapList),如果你尝试这样做,则会抛出相应的Exception。必须在更低级的,继承的子定义上指定merge属性; 在父集合定义上指定merge属性是多余的,不会导致所需的合并。

    强类型的集合

    Java 5引入了泛型类型,因此你可以使用强类型集合。也就是说,例如,可以声明只能包含String元素Collection类型。 如果你使用Spring依赖注入一个强类型的Collectionbean中,你可以利用Spring的类型转换的优势去支持,在被添加到Collection之前,将这样强类型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>

    foo beanaccounts属性准备好注入时,可以通过反射获得有关强类型Map <StringFloat>的元素类型的泛型信息。因此,Spring的类型转换体系结构将各种值元素识别为Float类型,并将字符串值9.99,2.753.99转换为实际的Float类型。

    Null和空字符串值

    Spring将属性为空的参数视为空Strings。以下基于XML的配置元数据片段将email属性设置为空String值(“”)。

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

    前面的例子等同于下面的Java代码:

    exampleBean.setEmail("")

    <null/>元素处理null值,例如:

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

    上面的配置等同于下面的Java代码:

    exampleBean.setEmail(null)
    使用p命名空间简化XML配置

    p命名空间可以让你使用bean元素的属性代替嵌套的<property />元素来描述属性值和/或协作bean

    Spring支持具有命名空间的可扩展配置格式,这些命名空间基于XML Schema定义。 本章中讨论的bean配置格式定义在XML Schema文档中。然而,p命名空间未在XSD文件中定义,仅存在于Spring的核心中。

    以下示例显示了可两个解析为相同结果的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>

    该示例显示了bean定义中名为emailp命名空间中的属性。 这告诉Spring包含一个属性声明。 如前所述,p命名空间没有模式定义,因此你可以将attribute的名称设置为property的名称。

    下一个示例包含超过两个的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>

    如你所见,此示例不仅包含使用p命名空间的属性值,还使用特殊格式来声明属性引用。 第一个bean的定义使用<property name =”spouse” ref =”jane” />来创建从bean johnbean jane的引用,而第二个bean的定义使用p:spouse-ref =”jane”作为属性,去做与第一个Bean完全相同的事情。在这种情况下,spouse是属性名称,而-ref部分表示这不是直接值,而是对另一个bean的引用。

    注意:p命名空间不如标准XML格式灵活。例如,声明属性引用的格式与以Ref结尾的属性冲突,而标准XML格式则不然。 我们建议你仔细选择你的方法并将其告诉给你的团队成员,以避免生成同时使用这三种方法的XML文档。

    c命名空间简化XML配置

    类似于c命名空间简化XML配置”章节,Spring 3.1中新引入的c命名空间允许使用内联属性来配置构造函数参数代替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
            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>

    c:名称空间使用与p:(以-ref结尾的,用于bean引用)相同的惯例,用于按名称设置构造函数参数。同样,它需要声明,即使它没有在XSD模式中定义(但它存在于Spring核心中)。

    对于像构造函数参数名称不可用的这样极少的情况(通常,如果字节码是在没有调试信息的情况下编译的话),可以使用参数索引:

    <!-- c-namespace index declaration -->
    <bean id="foo" class="x.y.Foo" c:_0-ref="bar" c:_1-ref="baz"/>

    注意:由于XML语法,索引表示法要求:以_作为开头的XML属性名称不能以数字开头(即使某些IDE允许它)。

    实际上,构造函数解析机制在匹配参数方面非常有效,因此除非确实需要,否则我们建议在整个配置中使用名称表示法。

    复合属性名称

    只要除最终属性名称之外的此路径的所有组件都不为null,你可以在设置bean属性时使用复合或嵌套属性名称。请思考以下bean定义。

    <bean id="foo" class="foo.Bar">
        <property name="fred.bob.sammy" value="123" />
    </bean>

    foo bean有一个fred属性,它有一个bob属性,它有一个sammy属性,最后的sammy属性被设置为值123。为了使其生效,foofred属性和bob属性,在构造bean之后,fred禁止为null,否则会抛出NullPointerException

  • 相关阅读:
    注释总结
    C# Notes
    坑爹的Honor10开热点
    用热得快烧洗澡水
    跳转语句
    台湾书籍代购网址——2013-08-25 16
    【转】cocos2d-x 模仿计时器效果,动态增加分数——2013-08-25 16
    【转】C/C++中的日期和时间 TIME_T与STRUCT TM转换——2013-08-25 16
    【转】Cocos2d-x 2.0 拖尾效果深入分析
    cocos2d-x之CCMotionStreak类——2013-08-25 16
  • 原文地址:https://www.cnblogs.com/springmorning/p/10327832.html
Copyright © 2020-2023  润新知