您的位置:首页 > 编程语言 > Java开发

spring 依赖注入配置详解

2013-10-09 13:22 363 查看
Technorati 标记: spring,依赖注入,ioc     接上一篇 spring 依赖注入 ,讲解了spring依赖注入的方式(构造器注入,set注入,静态工厂注入和实例工厂注入),这一次我们深入到spring依赖注入配置文件去。
    在 sprint 依赖注入方式上,可以知道是使用<property /> 和<constructor-arg /> 来注入依赖对象和基本值(基本数据类型和String值)。现在我们将详细谈一下各种值的配置方式。

一、基本值(基本数据类型和String)

    在xml配置文件里,<property />使用属性”value“来指定参数的值。顺带提一下的是,javaBeans 里的PropertyEditors 会将这些string值转换为对应的的数据类型。如下:
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<!-- setDriverClassName(String)调用的结果 -->
<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="123"/>
</bean>


    现在来看一下一种更加简洁的配置,使用 p 命名空间,如下:

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<!-- 引入p 命名空间 –>
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>


    使用 p 命名空间简化了配置,可也有一定的不足之处,就是需要再运行时才能发现拼写错误,而不是在设计时就可以知道。当然了,如果使用 IDEA 或者 springSource 这些具有代码提示功能的IDE,也完全可以避免这些避免错误。其实,还有另外一种方式配置 property,如下配置java.util.ProPerties:

<bean id="mappings"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="properties">
<value>
jdbc.driver.className=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mydb
</value>
</property>
</bean>


    如上配置是值得倡导的,使用<value />来配置值,而不是使用属性 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”的验证(确定它是否存在)。如果使用第二种方式,则需要到client被初始化时才可以发现,特别当这个 client 是 prototype,需要等容器初始化之后很长一段时间才能被发现。

    另外,当索引的 bean也在同一个xml配置文件时,可以使用属性 local,有助于xml解释器早一点验证此 bean 的 id。如下:

<property name="targetName">
<!-- id 为theTargetBean 的bean必须存在,否则抛出异常  -->
<idref local="theTargetBean"/>
</property>


三、其他 bean的索引(依赖对象)

    在<constructor-arg/>或<property/>元素内部还可以使用ref元素.用来将bean中指定属性的值设置为对容器中的另外一个bean的引用。ref 有三个属性 bean,local,parent。其具体区别如下:

四、内部 bean

    在<constructor-arg/>或<property/>元素内部还可以使用<bean />来定义一个内部bean,如下:

<bean id="outer" class="...">
<!-- 不是使用索引来指向其他依赖对象,而是再定义一个 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 或者 name 属,也不需要指定 scope ,这些都会自动被容器忽略。内部 bean 的创建都是伴随着 outer bean的创建而创建。

五、Collections

     可以使用元素<list />,<set />,<map />和<props />来设置java collection 里的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或 value里,Set的value,同样可以使用如下元素:

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


六、Collection 合并

    spring容器同样支持Collection的合并。我们可以在父元素里定义<list />,<map />,<set />,<props />,接着可以在子元素里定义<list />,<map />,<set />,<props />来继承或者覆盖父元素的集合。合并结果就是子元素里拥有一个合并了父、子元素里集合的Collection。如下:

<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">
<!-- 注意在子元素里设置 merge 为 true-->
<props merge="true">
<prop key="sales">sales@example.com</prop>
<prop key="support">support@example.co.uk</prop>
</props>
</property>
</bean>
<beans>


    注意在子元素里设置了 “merge = true”,那上面合并结果如下:

administrator=administrator@example.com
sales=sales@example.com
support=support@example.co.uk


    从父元素继承了<props />,同时覆盖了当中的support的元素。

    类似的,<list />,<set />,<map />也具有同样地用法。不过,在使用到<list />元素里,其内元素的顺序依然保持着,父元素的list 总所有子元素的list之前。而 Set、Map和Properties并不存在元素的顺序问题。

七、Collection 合并的限制

    在合并Collection里,不能合并类型不一致的Collection(如Set和List)。同时,如果需要抛出异常,则在子元素里的异常必须是父元素的异常的子类。需要注意的是,如果是在父元素里设置了“merge=true”,并不能得到想要的合并效果。

八、泛型集合

    在java 5 之后,可以使用泛型集合。spring的类型转换机制同样支持这种泛型集合的使用。如下:

public class Foo {
private Map<String, Float> accounts;
public void setAccounts(Map<String, Float> accounts) {
this.accounts = accounts;
}
}


   xml配置文件如下:

<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需要被注入时,Map<String,Float>的泛型信息会通过反射来获得。spring的类型转换机制可以识别出属性value的值时Float类型的,之后就将String类型的“9.99,2.75,3.99”转换为String类型。

九、null 和 空字符串值

    如下例子,会将“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 命名空间与简化配置

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<!-- 添加 p 命名空间 -->
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>


   如上所示,演示p 命名空间的使用,深入一点来看,如果使用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="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 jane。传统用法是<property name="spouse" ref="jane"/> ,而在 p 命名空间则是p:spouse-ref="jane",-ref 说明spouse不是基本的数据类型或String,而是一个索引。

十一、c 命名空间

    p 命名空间是用来简化<property />的配置,类似的有,c 命名空间可用来简化<constructor-arg />的配置。如下:

<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"/>
<-- 传统的配置方法 -->
<bean id="foo" class="x.y.Foo">
<constructor-arg ref="bar"/>
<constructor-arg ref="baz"/>
<constructor-arg value="foo@bar.com"/>
</bean>
<-- 使用 c 命名空间的配置-->
<bean id="foo" class="x.y.Foo" c:bar-ref="bar" c:baz-ref="baz" c:email="foo@bar.com">
</beans>


    同时也看一下使用 c 命名空间的索引应用,同样是使用 -ref,

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


十二、复合属性名

    有时候可能会看到如下的一些配置,

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


    如上的<property />其实是一个复合属性的名应用,怎么理解呢??在bean foo 理由有一个property fred,同样地在 property fred里有一个property bob,在property bob里有一个property sammy ,最后将“123”赋值给sammy。要让上述操作可以行,要求fred 和 bob 都不能为空。

十三、使用 depends-on

    有时候在创建某个bean之前,需要先创建另外一个bean,这时就需要用到属性 depends-on。

<bean id="beanOne" class="ExampleBean" depends-on="manager"/>
<bean id="manager" class="ManagerBean" />


    使用depends-on,就要求在实例化 beanOne 之前,先实例化 manager。那又该如何先实例化多个bean呢??可以使用逗号,分号或者空格来分开,如下:

<bean id="beanOne" class="ExampleBean" depends-on="manager,accountDao">
<property name="manager" ref="manager" />
</bean>
<bean id="manager" class="ManagerBean" />
<bean id="accountDao" class="x.y.jdbc.JdbcAccountDao" />


    如上,这就要求在实例化 beanOne之前,先实例化manager和accountDao。

十四、使用 lazy-init

    ApplicationContext实现的默认行为就是在启动时将所有singleton bean提前进行实例化(也就是依赖注入)。通常情况下这是件好事,因为这样在配置中的任何错误就会即刻被发现。有时候这种默认处理方式并不是你想要的,你希望某个bean在需要的时候才实例化,即在第一次向容器通过getBean索取bean时才实例化的。,这种方式称为“懒加载”,使用属性lazy-init可以达到这个效果。

<bean id="lazy" class="com.foo.ExpensiveToCreateBean" lazy-init="true"/>


    值得提醒一下的是,lazy-init 设置只对scop属性为singleton的bean起作用。另外,在容器层次中通过在<beans/>元素上使用'default-lazy-init'属性来控制延迟初始化也是可能的。如下面的配置:   

<beans default-lazy-init="true">
<!-- 没有bean被提前实例化 -->
</beans>

     如果一个bean的scope属性为scope=“pototype“时,即使设置了lazy-init="false",容器启动时不实例化bean,而是调用getBean方法是实例化的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  spring target style blank