Spring 注入参数详解

在 Spring 配罝文件中,用户不但可以将 String、int 等字面值注入 Bean 中,还可以将集合、Map 等类型的数据注入 Bean 中,此外还可以注入配置文件中其他定义的 Bean。

1.字面值

所谓 "字面值" 一般是指可用字符串表示的值,这些值可以通过 <value> 元素标签进行注入,在默认情况下,基本数据类型及其封装类、String 等类型都可以采取字面值注入的方式。Spring 容器在内部为字面值提供了编辑器。它可以将以字符串表示的字面值转换为内部变量的相应类型。Spring 允许用户注册自定义的编辑器,以处理其他类型属性注入时的转换工作。

在下面的示例中,我们为 Car 注入了两个属性值,并在 Spring 配罝文件中使用字面值提供配置值,如下所示。

字面值注入字面值

<bean id="car" class="com.smart.attr.Car" lazy-init="default">
    <property name="brand">
    <value><![CDATA[红旗&CA72]]></value>
    </property>
    <property name="maxSpeed"><value>200</value>
    </property>
    <property name="price" value="2000.00" />
</bean>

由于①处的 brand 属性值包含一个 XML 的特殊符号,因此我们特意在属性值外添加了一个XML特殊标签 <![CDATA[]]>。<![CDATA[]]> 的作用是让 XML 解析器将标签中的字符串当作普通的文本对待,以防止特殊字符串对 XML 格式造成破坏。

XML中共有5个特殊的字符,分别是 &、<、>、“、'  。如果配置文件中的注入值包括这些特殊字符,就需要进行特别处理。有两种解决方法:其一,采用本例中的 <![CDATA[]]> 特殊标签,将包含特殊字符的字符串封装起来;其二,使用 XML 转义序列表示这些特殊字符,这5个特殊字符所对应的XML转义序列特殊符号

特殊符号         转义序列

     <                          &lt;

     >                          &gt;       

     &                         &amp;

     “                          &quot;

     '                           &apos;

 

如果使用XML转义序列,则可以使用以下配置替换上面代码的配置。

<property name="brand"> 
  <value>红旗&amp;CA72</va1ue>
</property>

注意:一般情况下,XML 解析器会忽略元素标签内部字符串的前后空格,但 Spring 不会忽略元素标签内部字符串的前后空格如通过以下配置为 brand 属性提供注入值

<property name="brand"><value> 红旗CT72 </value></property>

那么 Spring 会将 "红旗CT72" 连同其前后空格一起赋给 brand 属性

2.引用其他 Bean

Spring IOC 容器中定义的 Bean 可以相互引用,IOC 容器则充当 "红娘" 的角色。下面创建一个新的 Boss 类,Boss 类中拥有一个 car 类型的属性。

public class Boss {
    private Car car;
    //①设置 car 属性
    public void setCar(Car car) {
        this.car = car;
    }
    ...
}

boss 的 Bean 通过 <ref> 元素引用 car Bean,建立起 boss 对 car 的依赖。

<bean id="car" class="com.smart.attr.Car"/>
<bean id="boss" class="com.smart.attr.Boss">
    <property name="car">
        <ref bean="car" />
    </property>
</bean>    

<ref> 元素可以通过以下3个属性引用容器中的其他Bean

  1、bean:通过该属性可以引用同一容器或父容器中的 Bean,这是最常见的形式。

  2、local:通过该属性只能引用同一配置文件中定义的 Bean,它可以利用 XML 解析器自动检验引用的合法性,以便开发人员在编写配置时能够及时发现并纠正配置错误。

  3、parent:引用父容器中的Bean,如 <ref parent="car"> 的配置说明 car 的 Bean 是父容器中的 Bean。

为了说明子容器对父容器中 Bean 的引用,我们来看一个具体的例子。假设有两个配置文件 beans1.xml 和 beans2.xml,其中 beans1.xml 被父容器加载,其配置内容如下:

<bean id="car" class="com.smart.attr.Car">
    <property name="brand" value="红旗CA72" />
    <property name="maxSpeed" value="200" />
    <property name="price" value="2000.00" />
</bean>

而 beans2.xml 被子容器加载,其配置内容如下:

<bean id="car" class="com.smart.attr.Car">
    <property name="brand" value="吉利CT5" />
    <property name="maxSpeed" value="100" />
    <property name="price" value="1000.00" />
</bean>
<bean id="boss" class="com.smart.attr.Boss">
    <property name="car">
        <ref parent="car" />
    </property>
</bean>

在 beans1.xml 中配置了一个 car Bean,在bean2.xml中也配置了一个 car Bean。分别通过父、子容器加载 beans1.xml 和 beans2.xml,beans2.xml 中的 boss 通过<ref parent="car">引用父容器中的car。

下面是分别使用父、子容器加载 beans1.xml 和 beans2.xml 配置文件的代码:

//①父容器
ClassPathXmlApplicationContext pFactory = new ClassPathXmlApplicationContext(new String[]{"com/smart/attr/beans1.xml"});
//②指定 pFactory 为该容器的父容器    
ApplicationContext factory = new ClassPathXmlApplicationContext(new String[]{"com/smart/attr/beans2.xml"},pFactory);
Boss boss = (Boss)factory.getBean("boss");
assertNotNull(boss);
System.out.println(boss.getCar().toString());

运行这段代码,在控制台中打印出以下信息:

brand:红旗CA72/maxSpeed:200/price:2000.0

3.内部Bean

如果 car Bean 只被 boss Bean引用,而不被容器中任何其他的 Bean 引用,则可以将 car 以内部 Bean 的方式注入 Boss 中。

<bean id="boss" class="com.smart.attr.Boss">
    <property name="car">
        <bean class="com.smart.attr.Car">
            <property name="maxSpeed" value="200"/>
            <property name="price" value="2000,00"/>
        </bean>
    </property>
</bean>

内部 Bean 和 Java 的匿名内部类相似,既没有名字,也不能被其他 Bean 引用,只能在声明处为外部 Bean 提供实例注入。

内部 Bean 即使提供了 id、name、scope 属性,也会被忽略。

4.null 值

如果用户尝试通过以下配置方式为 car 的 brand 属性注入一个 null 值,那么将会得到一个失望的结果。

<bean id="car" class="com.smart.attr.Car">
    <property name="brand"><value></value></property>
</bean>

Spring 会将 <value></value> 解析为空字符串。那么,如何为属性设置一个 null 的注入值呢?答案是必须使用专用的 <null/> 元素标签,通过它可以为 Bean 的字符串或其他

对象类型的属性注入 null 值。

<property name="brand"><null/></property>

上面的配置代码等同于调用 car.setBrand(null) 方法。

5.级联属性

和 Struts、Hibernate 等框架一样,Spring 支持级联属性的配置。假设我们希望在定义 Boss 时直接为 car 的属性提供注入值,则可以采取以下配置方式:

<bean id="boss3" class="com.smart.attr.Boss">
    <!-- 以圆点(.)的方式定义级别属性-->
    <property name="car.brand" value="吉利CT50"/>
</bean>

按照上面的配置,Sping 将调用 Boss.getCar().setBrand("吉利CT50")方法进行属性的注入操作。这时必须对 Boss 类进行改造,为 car 属性声明一个初始化对象。

public class Boss {
    //声明初始化对象
    private Car car = new Car();
    public Car getCar() {
        return car;
    }
    public void setCar(Car car) {
        this.car = car;
    }
    ...
}

在①处为 Boss 的 car 属性提供了一个非空的 Car 实例。如果没有为 car 属性提供 Car 对象,那么 Spring 在设置级联属性时将抛出 NullValueInNestedPathExcepüon 异常。

Spring 没有对级联属性的层级数进行限制,只要配置的 Bean 拥有对应于级联属性的类结构,就可以配置任意层级的级联属性,如以下定义了具有三级结构的级联属性。

<property name="car.wheel.brand" value="双星"/>

6.集合类型属性

java.util 包中的集合类型是最常用的数据结构类型,主要包括 List、set、Map、Properties,Spring 为这些集合类型属性提供了专属的配置标签。

1)List
为 Boss 添加一个 List 类型的 favorites 属性,如下:

public class Boss {
    private List favorites = new ArrayList();
    public List getFavorites() {
        return favorites;
    }
    public void setFavorites(List favorites) {
      this.favorites = favorites;
    }
}

对应 Spring 中的配置片段如下:

<bean id="boss1" class="com.smart.attr.Boss">
    <property name="favorites">
        <list>
      <value>看报</value>
      <value>赛车</value>
      <value>高尔夫</value>
        </list>        
    </property>
</bean>

List 属性既可以通过 <value> 注入字符串,也可以通过 <ref> 注入容器中其他的Bean。

注意:假设一个属性类型可以通过字符串字面值进行配置,那么该类型对应的数组类型的属性(如String[]、int[] 等)也可以采用 <list> 方式进行配置。 

2)Set
如果 Boss 的 favorites 属性是 java.util.set,则采用如下配置方式:

<bean id="boss1" class="com.smart.attr.Boss">
    <property name="favorites">
        <set>
      <value>看报</value>
      <value>赛车</value>
      <value>高尔夫</value>
        </set>        
    </property>
</bean>

3)Map

下面为 Boss 添加一个 Map 类型的 jobs 属性:

public class Boss {
    ...
    private Map jobs = new HashMap();
    public Map getJobs() {
        return jobs;
    }

    public void setJobs(Map jobs) {
        this.jobs = jobs;
    }
    ...
}

在配置文件中可以通过以下方式为 jobs 属性提供配置值:

<bean id="boss1" class="com.smart.attr.Boss">
  <property name="jobs">
    <map>
      <entry >
        <key><value>AM</value></key>
              <value>会见客户</value>
           </entry>
           <entry>
              <key><value>PM</value></key>
              <value>公司内部会议</value>
           </entry>
       </map>
  </property>
<bean>

假如某一 Map 元素的键和值都是对象,则可以采取以下配置方式:

<entry>
    <key><ref bean="keyBean"/></key>
    <ref bean="vaIueBean"/>
</entry>

4)Properties

Properties 类型其实可以看作 Map 类型的特例。Map 元素的键和值可以是任何类型的对象,而 Properties 属性的键和值都只能是字符串。下面为 Boss 添加一个 Properties 类型的 mails 属性:

public class Boss {
    ...
    private Properties mails = new Properties();
    public Properties getMails() {
        return mails;
    }

    public void setMails(Properties mails) {
        this.mails = mails;
    }
    ...
}

下面的配置片段为 mails 提供了配置:

<bean id="boss1" class="com.smart.attr.Boss">
    <property name="mails">
        <props>
            <prop key="jobMail">john-office@smart.com</prop>
            <prop key="lifeMail">john-life@smart.com</prop>
        </props>
    </property>
</bean>

因为 Properties 键值对只能是字符串,因此其配置比 Map 的配置要简单一些,注意值的配置没有 <value> 子元素标签。

5)强类型集合

Java5.0 提供了强类型集合的新功能,允许为集合元素指定类型。如下面 Boss 类中的 jobTime 属性就采用了强类型的 Map 类型,元素的键为 String 类型,而值为 Integer类型。

public class Boss {
    ...
    private Map<String, Integer> jobTime = new HashMap<String, Integer>();
    public Map<String, Integer> getJobTime() {
        return jobTime;
    }

    public void setJobTime(Map<String, Integer> jobTime) {
        this.jobTime = jobTime;
    }
    ...
}

在 Spring 中的配置和非强类型集合相同

<bean id="boss1" class="com.smart.attr.Boss">
    <property name="jobTime">
        <map>
            <entry>
                <key><value>会见客户</value></key>
                <value>124</value>//①
            </entry>
        </map>
    </property>
</bean>    

但 Spring 容器在注入强类型集合时会判断元素的类型,将设置值转换为对应的数据类型。如①处的设置项 124 将被转换为 Integer 类型。

6)集合合并
Spring支持集合合并的功能,允许子 <bean>  继承父 <bean> 的同名属性集合元素,并将子 <bean> 中配置的集合属性值和父 <bean> 中配置的同名属性值合并起来作为最终 Bean 的属性值,如下

<bean id="parentBoss" abstract="true" class="com.smart.attr.Boss">
    <property name="favorites"> <!--①父<Bean> -->
        <set>
            <value>看报</value>
            <value>赛车</value>
            <value>高尔夫</value>
        </set>
    </property>
</bean>

<bean id="childBoss" parent="parentBoss"> <!--②指定父<Bean> -->
    <property name="favorites"> 
        <set merge="true"> <!--③和父<Bean>中同名集合属性合并 -->
            <value>爬山</value> 
            <value>游泳</value> 
        </set> 
    </property> 
</bean>

③处通过 merge="true" 属性指示子 <bean> 和父 <bean> 中的同名属性值进行合并,即子 Bean 的 favorites 集合最终将拥有5个元素。如果设置为 merge="false",则不会和父 <bean> 中的同名集合属性进行合并,即子 Bean 的 favorites 属性集合只有两个元素

7)通过 util 命名空间配置集合类型的 Bean

如果希望配置一个集合类型的 Bean,而非一个集合类型的属性,则可以通过 util 命名空间进行配置。首先需要在 Spring 配置文件头中引入命名空间的声明。

<?xml version="1.0" encoding="UTF-8" ?>
<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"
  xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd 
http://www.springframework.org/schema/util 
http://www.springframework.org/schema/util/spring-util-4.0.xsd">
...
</beans>

其次配置一个List类型的Bean,可以通过list-class显式指定List的实现类。

<util:list id="favoriteList1" list-class="java.util.LinkedList">
  <value>看报</value>
  <value>赛车</value>
  <value>高尔夫</value>
</util:list>

再次配置一个 Set 类型的 Bean,可以通过 set-class 指定 Set 的实现类。

<util:set id="favoriteSet1"  >
  <value>看报</value>
  <value>赛车</value>
  <value>高尔夫</value>
</util:set>

最后配置一个 Map 类型的Bean,可以通过 map-class 指定 set 的实现类。

<util:map id="emails1" >
  <entry key="AM" value="会见客户" />
  <entry key="PM" value="公司内部会议" />
</util:map>

 此外,<util:list> 和 <util:set> 支持 value-type 属性,指定集合中的值类型;而 <util:map> 支持 key-type 和 value-type 属性,指定 Map 的键和值类型。

原文地址:https://www.cnblogs.com/jwen1994/p/10393191.html