zoukankan      html  css  js  c++  java
  • 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 的键和值类型。

  • 相关阅读:
    《算法导论》笔记 第13章 总结与思考
    《算法导论》笔记 第13章 13.4 删除
    《算法导论》笔记 第13章 13.3 插入
    《算法导论》笔记 第13章 13.2 旋转
    《算法导论》笔记 第13章 13.1 红黑树的性质
    《算法导论》笔记 第12章 总结与思考
    《算法导论》笔记 第12章 *12.4 随机构造的二叉查找树
    《算法导论》笔记 第12章 12.3 插入和删除
    《算法导论》笔记 第12章 12.2 查询二叉查找树
    2018寒假多校算法寒假训练营练习比赛(第五场)
  • 原文地址:https://www.cnblogs.com/jwen1994/p/10393191.html
Copyright © 2011-2022 走看看