3.1.6  注入集合、数组和字典

      Spring不仅能注入简单类型数据,还能注入集合(Collection、无序集合Set、有序集合List)类型、数组(Array)类型、字典(Map)类型数据、Properties类型数据,接下来就让我们一个个看看如何注入这些数据类型的数据。

一、注入集合类型:包括Collection类型、Set类型、List类型数据:

(1)List类型:需要使用<list>标签来配置注入,其具体配置如下:

ea8eeb40b7c3710f2a898118481a2b67__8.JPG

      让我们来写个测试来练习一下吧:

            准备测试类:


java代码:
  1. package cn.javass.spring.chapter3.bean;  

  2. import java.util.List;  

  3. publicclass ListTestBean {  

  4. private List<String> values;  

  5. public List<String> getValues() {  

  6. return values;  

  7.    }  

  8. publicvoid setValues(List<String> values) {  

  9. this.values = values;  

  10.    }  

  11. }  


进行Bean定义,在配置文件(resources/chapter3/listInject.xml)中配置list注入:


java代码:
  1. <bean id="listBean"class="cn.javass.spring.chapter3.bean.ListTestBean">  

  2.    <property name="values">  

  3.        <list>  

  4.            <value>1</value>  

  5.            <value>2</value>  

  6.            <value>3</value>  

  7.        </list>  

  8.   </property>  

  9. </bean>  


测试代码:


java代码:
  1. @Test

  2. publicvoid testListInject() {  

  3.   BeanFactory beanFactory =  

  4. new ClassPathXmlApplicationContext("chapter3/listInject.xml");  

  5. ListTestBean listBean = beanFactory.getBean("listBean", ListTestBean.class);  

  6. System.out.println(listBean.getValues().size());  

  7. Assert.assertEquals(3, listBean.getValues().size());  

  8. }  


(2)Set类型:需要使用<set>标签来配置注入,其配置参数及含义和<lsit>标签完全一样,在此就不阐述了:

             准备测试类:


java代码:
  1. package cn.javass.spring.chapter3.bean;  

  2. import java.util.Collection;  

  3. publicclass CollectionTestBean {  

  4. private Collection<String> values;  

  5. publicvoid setValues(Collection<String> values) {  

  6. this.values = values;  

  7.    }  

  8. public Collection<String> getValues() {  

  9. return values;  

  10.    }  

  11. }  


进行Bean定义,在配置文件(resources/chapter3/listInject.xml)中配置list注入:


java代码:
  1. <bean id="setBean"class="cn.javass.spring.chapter3.bean.SetTestBean">  

  2. <property name="values">  

  3. <set>  

  4. <value>1</value>  

  5. <value>2</value>  

  6. <value>3</value>  

  7. </set>  

  8. </property>  

  9. </bean>  

             具体测试代码就不写了,和listBean测试代码完全一样。


(2)Collection类型:因为Collection类型是Set和List类型的基类型,所以使用<set>或<list>标签都可以进行注入,配置方式完全和以上配置方式一样,只是将测试类属性改成“Collection”类型,如果配置有问题,可参考cn.javass.spring.chapter3.DependencyInjectTest测试类中的testCollectionInject测试方法中的代码。

二、注入数组类型:需要使用<array>标签来配置注入,其中标签属性“value-type”和“merge”和<list>标签含义完全一样,具体配置如下:

3c02092e74f93282b673c99692f64d4a__9.JPG

      如果练习时遇到配置问题,可以参考“cn.javass.spring.chapter3.DependencyInjectTest”测试类中的testArrayInject测试方法中的代码。


三、注入字典(Map)类型:字典类型是包含键值对数据的数据结构,需要使用<map>标签来配置注入,其属性“key-type”和“value-type”分别指定“键”和“值”的数据类型,其含义和<list>标签的“value-type”含义一样,在此就不罗嗦了,并使用<key>子标签来指定键数据,<value>子标签来指定键对应的值数据,具体配置如下:

921eebe8c461cd57945255d261f46a96__10.JPG

      如果练习时遇到配置问题,可以参考“cn.javass.spring.chapter3.DependencyInjectTest”测试类中的testMapInject测试方法中的代码。

四、Properties注入:Spring能注入java.util.Properties类型数据,需要使用<props>标签来配置注入,键和值类型必须是String,不能变,子标签<prop key=”键”>值</prop>来指定键值对,具体配置如下:

45f141f06940ec5773d313f02e9f8ada__11.JPG

18c668a0100d6e74025f7352c2347b6a__12.JPG

如果练习时遇到配置问题,可以参考cn.javass.spring.chapter3.DependencyInjectTest测试类中的testPropertiesInject测试方法中的代码。

      到此我们已经把简单类型及集合类型介绍完了,大家可能会问怎么没见注入“Bean之间关系”的例子呢?接下来就让我们来讲解配置Bean之间依赖关系,也就是注入依赖Bean。


3.1.7  引用其它Bean

      上边章节已经介绍了注入常量、集合等基本数据类型和集合数据类型,本小节将介绍注入依赖Bean及注入内部Bean。

      引用其他Bean的步骤与注入常量的步骤一样,可以通过构造器注入及setter注入引用其他Bean,只是引用其他Bean的注入配置稍微变化了一下:可以将“<constructor-arg index="0" value="Hello World!"/>”和“<property name="message" value="Hello World!"/>”中的value属性替换成bean属性,其中bean属性指定配置文件中的其他Bean的id或别名。另一种是把<value>标签替换为<.ref bean=”beanName”>,bean属性也是指定配置文件中的其他Bean的id或别名。那让我们看一下具体配置吧:


一、构造器注入方式:

(1)通过” <constructor-arg>”标签的ref属性来引用其他Bean,这是最简化的配置:

55683bad406b9d7bb748f5b9440059e0__13.JPG

(2)通过” <constructor-arg>”标签的子<ref>标签来引用其他Bean,使用bean属性来指定引用的Bean:

7379a485e2a5ed554c09889265f27bf0__14.JPG

二、setter注入方式:

(1)通过” <property>”标签的ref属性来引用其他Bean,这是最简化的配置:

9f1acbf99307e07ca1fbdd42cb3c63a4__15.JPG

(2)通过” <property>”标签的子<ref>标签来引用其他Bean,使用bean属性来指定引用的Bean:

c7e3bd005904f3b7936069a38cadc669__16.JPG

三、接下来让我们用个具体例子来讲解一下具体使用吧:

(1)首先让我们定义测试引用Bean的类,在此我们可以使用原有的HelloApi实现,然后再定义一个装饰器来引用其他Bean,具体装饰类如下:


java代码:
  1. package cn.javass.spring.chapter3.bean;  

  2. import cn.javass.spring.chapter2.helloworld.HelloApi;  

  3. publicclass HelloApiDecorator implements HelloApi {  

  4. private HelloApi helloApi;  

  5. //空参构造器

  6. public HelloApiDecorator() {  

  7. }  

  8. //有参构造器

  9. public HelloApiDecorator(HelloApi helloApi) {  

  10. this.helloApi = helloApi;  

  11. }    

  12. publicvoid setHelloApi(HelloApi helloApi) {  

  13. this.helloApi = helloApi;  

  14.    }  

  15. @Override

  16. publicvoid sayHello() {  

  17.        System.out.println("==========装饰一下===========");  

  18.        helloApi.sayHello();  

  19.        System.out.println("==========装饰一下===========");  

  20.    }  

  21. }  


      (2)定义好了测试引用Bean接下来该在配置文件(resources/chapter3/beanInject.xml)进行配置Bean定义了,在此将演示通过构造器及setter方法方式注入依赖Bean:


java代码:
  1. <!-- 定义依赖Bean -->  

  2. <bean id="helloApi"class="cn.javass.spring.chapter2.helloworld.HelloImpl"/>  

  3. <!-- 通过构造器注入 -->  

  4. <bean id="bean1"class="cn.javass.spring.chapter3.bean.HelloApiDecorator">  

  5. <constructor-arg index="0" ref="helloApi"/>  

  6. </bean>  

  7. <!-- 通过构造器注入 -->  

  8. <bean id="bean2"class="cn.javass.spring.chapter3.bean.HelloApiDecorator">  

  9.    <property name="helloApi"><ref bean=" helloApi"/></property>  

  10. </bean>  


(3)测试一下吧,测试代码(cn.javass.spring.chapter3.DependencyInjectTest)片段如下:


java代码:
  1. @Test

  2. publicvoid testBeanInject() {  

  3.    BeanFactory beanFactory =  

  4. new ClassPathXmlApplicationContext("chapter3/beanInject.xml");  

  5. //通过构造器方式注入

  6.    HelloApi bean1 = beanFactory.getBean("bean1", HelloApi.class);  

  7.    bean1.sayHello();  

  8. //通过setter方式注入

  9.    HelloApi bean2 = beanFactory.getBean("bean2", HelloApi.class);  

  10.    bean2.sayHello();  

  11. }  


四、其他引用方式:除了最基本配置方式以外,Spring还提供了另外两种更高级的配置方式,<ref local=””/>和<ref parent=””/>

(1)<ref local=””/&gt;配置方式:用于引用通过<bean id=”beanName”>方式中通过id属性指定的Bean,它能利用XML解析器的验证功能在读取配置文件时来验证引用的Bean是否存在。因此如果在当前配置文件中有相互引用的Bean可以采用<ref local>方式从而如果配置错误能在开发调试时就发现错误。

如果引用一个在当前配置文件中不存在的Bean将抛出如下异常:

org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException: Line21 inXML document from class path resource [chapter3/beanInject2.xml] is invalid; nested exception is org.xml.sax.SAXParseException: cvc-id.1: There is no ID/IDREF binding for IDREF 'helloApi'.

<ref local>具体配置方式如下:

502163429b4a45dffb3e8fb3750be0c2__17.JPG

      (2)<ref parent=””/>配置方式:用于引用父容器中的Bean,不会引用当前容器中的Bean,当然父容器中的Bean和当前容器的Bean是可以重名的,获取顺序是直接到父容器找。具体配置方式如下:

59b072df3cd4f6af045f6afaeac0a01b__18.JPG

接下来让我们用个例子演示一下<ref local>和<ref parent>的配置过程:

首先还是准备测试类,在此我们就使用以前写好的HelloApiDecorator和HelloImpl4类;其次进行Bean定义,其中当前容器bean1引用本地的”helloApi”,而”bean2”将引用父容器的”helloApi”,配置如下:


java代码:
  1. <!-- sources/chapter3/parentBeanInject.xml表示父容器配置-->  

  2. <!--注意此处可能子容器也定义一个该Bean-->  

  3. <bean id="helloApi"class="cn.javass.spring.chapter3.HelloImpl4">  

  4. <property name="index" value="1"/>  

  5. <property name="message" value="Hello Parent!"/>  

  6. </bean>  


java代码:
  1. <!-- sources/chapter3/localBeanInject.xml表示当前容器配置-->  

  2. <!-- 注意父容器中也定义了id 为 helloApi的Bean -->  

  3. <bean id="helloApi"class="cn.javass.spring.chapter3.HelloImpl4">  

  4. <property name="index" value="1"/>  

  5.    <property name="message" value="Hello Local!"/>  

  6. </bean>  

  7. <!-- 通过local注入 -->  

  8. <bean id="bean1"class="cn.javass.spring.chapter3.bean.HelloApiDecorator">  

  9. <constructor-arg index="0"><ref local="helloApi"/></constructor-arg>  

  10. </bean>  

  11. <!-- 通过parent注入 -->  

  12. <bean id="bean2"class="cn.javass.spring.chapter3.bean.HelloApiDecorator">  

  13. <property name="helloApi"><ref parent="helloApi"/></property>  

  14. </bean>  


(3)写测试类测试一下吧,具体代码片段如下:


java代码:
  1. @Test

  2. publicvoid testLocalAndparentBeanInject() {  

  3. //初始化父容器

  4. ApplicationContext parentBeanContext =  

  5. new ClassPathXmlApplicationContext("chapter3/parentBeanInject.xml");  

  6. //初始化当前容器

  7. ApplicationContext beanContext = new ClassPathXmlApplicationContext(  

  8. new String[] {"chapter3/localBeanInject.xml"}, parentBeanContext);  

  9.    HelloApi bean1 = beanContext.getBean("bean1", HelloApi.class);  

  10.    bean1.sayHello();//该Bean引用local bean

  11. HelloApi bean2 = beanContext.getBean("bean2", HelloApi.class);  

  12. bean2.sayHello();//该Bean引用parent bean

  13. }  


“bean1”将输出“Hello Local!”表示引用当前容器的Bean,”bean2”将输出“Hello Paren!”,表示引用父容器的Bean,如配置有问题请参考cn.javass.spring.chapter3.DependencyInjectTest中的testLocalAndparentBeanInject测试方法。