Spring | IOC之bean基于XML的注入(装配)


前面讲到基于XML的bean的 三种实例化,这篇文章来学习下基于XML如何构建bean与bean之间的关系以及如何实现依赖关系的注入。

1 依赖关系的理解

如何理解依赖,在代码中是怎么体现的?

假设有两个元素X、Y,如果修改元素X的定义可能会引起对另一个元素Y的修改,则称元素Y依赖于元素X。在OOP对象中,元素为类或者应用,则类间的依赖现象有多种:

  • 如一个类向另一个类发消息;这是类与类之间交流的方式,可以理解为依赖关系的总称。
  • 一个类是另一个类的数据成员
    public class B {
        private A a;   // B依赖A
    }
  • 一个类是另一个类的某个方法的参数
    public class B {
        void method(A a){   // B依赖A
            // doSomething;
        }
    }

关于更多类之间的关系,可查看参考资料。

2 bean间的依赖

bean间的依赖在IOC容器中怎么体现?注意循环依赖问题。
传统对象间依赖的实现,都是依赖的对象或者资源在被依赖类内部进行实例化或者初始化,而Spring则把这种依赖的实现(即装配)放入IOC容器中,由IOC容器来负责实例化bean或者所依赖的资源。之前讲过注入的含义,那么这里出现了“装配”,两者之前有什么关联?我们后续回讲到。

3 bean的依赖注入

既然已经知道bean之间的依赖关系放到IOC容器中建立,且通过注入的方式来实现bean间的依赖,那么注入又是如何实现的呢?在基于XML实现的注入方式中,分为两种:构造器注入和setter方法注入。下面分别进行说明。

3.1 构造器注入

概念:构造器注入顾名思义是通过参数构造器进行注入,把依赖的对象或者资源通过构造器参数注入到被依赖对象中,实现两者的依赖关系。

3.1.1 实例1:含参构造器注入

创建ElectronicProducts接口:

package com.starry.bean.xml.constructorInjection;
public interface ElectronicProducts {
    void doSomething();
}

创建Computer类:

package com.starry.bean.xml.constructorInjection;
  public class Computer implements ElectronicProducts {
      private Mouse mouse;
      public Computer(Mouse mouse) {
          this.mouse = mouse;
      }
      @Override
      public void doSomething() {
          System.out.println("computer...");
          mouse.doSomething();
      }
  }

PS:实现ElectronicProducts接口,且包含一个带参数的构造函数。

Mouse类很简单,里面有个doSomething()方法:

package com.starry.bean.xml.constructorInjection;
 public class Mouse {
     void doSomething(){
         System.out.println("mouse...");
     }
 }

上面是所有的接口和类,重点在Computer类里面,要想让Computer类的实例doSomething()方法正确执行,则必须要实例化Mouse类生成mouse对象;目前代码中只是建立一个表面的Computer类依赖Mouse类的关系,为什么说是表面的,因为编译并不报错,而运行必然报错。Spring把这种依赖放到IOC容器中,具体体现在XML配置文件中:

<bean id="mouse" class="com.starry.bean.xml.constructorInjection.Mouse" />
<bean id="computer" class="com.starry.bean.xml.constructorInjection.Computer">
      <constructor-arg ref="mouse" />
</bean>

XML配置中通过bean标签生成两个bean对象(mouse和computer);通过constructor-arg标签把mouse对象注入到computer对象中。
xml文件执行过程:当IOC容器遇到第一个bean元素时,它会创建id为mouse的bean对象;当IOC容器遇到第二个bean元素时,它会创建一个computer对象,同时constructor-arg元素会告知IOC容器要将一个id为mouse的bean引用传递到Computer的构造器中。这里可以思考下调换两个bean实例化的顺序会发生什么?

注意:测试Test类在源码中,可下载执行测试。

还有一种替代构造器注入的方案,即Spring的c-命名空间,这种方案是在3.0中引入的,它之所以能够成为一种替代方案,是因为其比上面构造器注入简洁。

3.1.2 实例2:c-命名空间

首先在xml文件顶部声明其模式:(新增)

xmlns:c="http://www.springframework.org/schema/c"

上述第二个bean声明改为:

<bean id="computer" class="com.starry.bean.xml.constructorInjection.Computer" c:mouse-ref="mouse" />
  • c:mouse-rsf中,c是constructor的首字母;
  • mouse是构造器参数名称;
  • -ref表示注入的是对象的引用;
  • mouse是注入bean实例的id。

注意:也可以使用参数在参数列表中的位置信息来代替参数名称:c:_0-ref=”mouse”(xml中不允许数字开头的标识符,所以以下划线作前缀)
注意:测试Test类在源码中,可下载执行测试。

到这里你可能发现上面注入的都是对象引用,而实际情况还会注入字符串值、整形值以及集合。

3.1.3 实例3:注入字符串和整形

给电脑添加品牌(字符串类型)和价格(整形类型)

public class Computer implements ElectronicProducts {
      // 实例1
      private Mouse mouse;
      // 实例3
      private String name;
      private int pri·ce;
      public Computer(Mouse mouse, String name, int price) {
          this.mouse = mouse;
          this.name = name;
          this.price = price;
      }
      @Override
      public void doSomething() {
          // 实例1
          //System.out.println("computer...");
          //mouse.doSomething();
          
          // 实例3
          System.out.println("computer... 品牌:" + name + ", 价格:" + price );
          mouse.doSomething();
      }
  }

xml配置文件constructorInjection.xml修改为:

<bean id="mouse" class="com.starry.bean.xml.constructorInjection.Mouse" />
<bean id="computer" class="com.starry.bean.xml.constructorInjection.Computer">
      <constructor-arg ref="mouse" />
      <constructor-arg name="name" value="HP"/>
      <constructor-arg name="price" value="5000"/>
</bean>

没错,这个跟上篇“bean的实例化”类似,可以通过name、type和index注入字符串和整形类型。

如果要用c-命名空间注入字符串和整形,可用如下两种方式:

<bean id="computer" class="com.starry.bean.xml.constructorInjection.Computer"
      c:_0-ref="mouse" 
      c:_1="hp"
     c:_2="5000"
/>
<bean id="computer" class="com.starry.bean.xml.constructorInjection.Computer" 
 c:mouse-ref="mouse" 
 c:name="hp"
 c:price="5000" />

注意:可以思考下当有多个含参构造器时,c-命名空间形式改如何写?

3.1.4 实例4:注入集合

给电脑添加多个CPU,修改如下:

<bean id="computer" class="com.starry.bean.xml.constructorInjection.Computer">
      <constructor-arg ref="mouse" />
      <constructor-arg name="name" value="HP"/>
      <constructor-arg name="price" value="5000"/>
      <constructor-arg>
          <list>
              <value>cpu1</value>
              <value>cpu2</value>
              <value>cpu3</value>
          </list>
      </constructor-arg>
</bean>

注意:注入set也一样,把list标签换成set标签。

如果是引用列表,则改成:

<bean id="computer" class="com.starry.bean.xml.constructorInjection.Computer">
     <constructor-arg ref="mouse" />
     <constructor-arg name="name" value="HP"/>
     <constructor-arg name="price" value="5000"/>
     <constructor-arg>
         <list>
             <ref bean="cpu1"/>
             <ref bean="cpu2"/>
             <ref bean="cpu3"/>
         </list>
     </constructor-arg>
</bean>

注意:c-命名空间的形式无法实现集合的注入。

3.2 setter方法注入

概念:setter方法注入是指通过setter方法把依赖的对象注入到某对象中,也经常被称为属性注入。

3.2.1 实例5:setter注入

修改Computer类,其他类保持不变:

import com.starry.bean.xml.constructorInjection.ElectronicProducts;
import com.starry.bean.xml.constructorInjection.Mouse;
public class Computer implements ElectronicProducts {
      private Mouse mouse;
      public void setMouse(Mouse mouse) {
          this.mouse = mouse;
      }
      @Override
      public void doSomething() {
          System.out.println("computer...");
          mouse.doSomething();
      }
  }

很明显,用setMouse()方法代替了原来的带参构造函数。

新建xml配置文件setterInjection.xml,内容如下:

<bean id="mouse" class="com.starry.bean.xml.constructorInjection.Mouse" />
  <!-- 实例1-->
  <bean id="computer" class="com.starry.bean.xml.setterInjection.Computer">
      <property name="mouse" ref="mouse" />
</bean>

用元素代替了元素,其注入是通过setMouse()方法完成的。

构造函数注入可以用c-命名空间代替,setter方法注入可用p-命名空间代替。

3.2.2 实例6:p-命名空间

首先在xml头文件中进行p标签声明:

xmlns:p="http://www.springframework.org/schema/p"

在xml文件中配置p标签:

<bean id="computer" class="com.starry.bean.xml.setterInjection.Computer" p:mouse-ref="mouse" />

p:mouse-ref=”mouse”

  • 其中p表示property首字母,表明我们所设置的是一个属性;
  • mouse表示要注入的属性名;
  • -ref表示注入的是一个对象;
  • 最后的mouse表示要注入对象的id,而不是普通的字面量。

注意:测试Test类在源码中,可自行下载测试。

下面简单说一下对字面量,即字符串、整形和集合的注入。

3.2.3 实例7:setter注入字符串、整形和集合
<bean id="computer" class="com.starry.bean.xml.setterInjection.Computer">
      <property name="mouse" ref="mouse" />
      <property name="name" value="hp" />
      <property name="price" value="5000" />
      <property name="cpuList">
          <list>
              <value>cpu1</value>
              <value>cpu2</value>
              <value>cpu3</value>
          </list>
      </property>
</bean>

通过p标签注入如下:

<bean id="computer" class="com.starry.bean.xml.setterInjection.Computer"
        p:mouse-ref="mouse" 
        p:name="hp"
        p:price="5000">
       <property name="cpuList">
           <list>
               <value>cpu1</value>
               <value>cpu2</value>
               <value>cpu3</value>
           </list>
       </property>
</bean>

可见p标签虽然实现集合注入,但是并没有使用p标签的特性,而是按照setter的方式注入集合。
虽然不能使用p-命名空间来注入集合,但是可以通过Spring提供的util-命名空间方式来简化集合注入。

3.2.4 实例8:util-命名空间

首先在xml文件头声明util-标签:

xmlns:util=http://www.springframework.org/schema/util
xsi:schemaLocation="http://www.springframework.org/schema/beans
                    http://www.springframework.org/schema/beans/spring-beans.xsd
                    http://www.springframework.org/schema/util
                    http://www.springframework.org/schema/util/spring-util.xsd

xml配置文件修改如图所示:

<util:list id="cpuListTemp">
  <value>cpu1</value>
  <value>cpu2</value>
  <value>cpu3</value>
</util:list> 
  
<bean id="computer" class="com.starry.bean.xml.setterInjection.Computer"
        p:mouse-ref="mouse" 
        p:name="hp"
        p:price="5000"
        p:cpuList-ref="cpuListTemp"
/>

可见把集合通过util:list元素当做一个单独的实例,在实际使用的bean中作为引用注入。

注意:util-提供其他多种集合的注入途径,具体可参考下表:

元素描述
util:constant某个类型的public static域,并将其暴露为bean
util:list建一个java.util.List类型的bean,其中包含值或引用
util:map建一个java.util.Map类型的bean,其中包含值或引用
util:property建一个java.util.Property型的bean
util:property-path引用一个bean的属性,并将其暴露为bean
util:set创建一个java.util.Set类型的bean,其中包含值或引用

4 总结

我们学习了以下几点内容:

  • 依赖关系的理解;

  • 基于xml,依赖注入的两种方式:带参构造函数注入和setter方法注入;

  • 带参构造函数注入和c-命名空间注入;(引用、字符串、整形和集合)

  • setter方法注入和p-命名空间注入;(util-标签的使用)

5 参考资料

类之间关系资料:http://www.uml.org.cn/oobject/201211231.asp
《Spring实战4》

源码下载

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值