一. Spring依赖关系的配置

UML类图中类之间的关系

     UML类图中的关系包含:依赖关系、泛化关系、关联关系、聚合关系、组合关系、实现关系

1. 依赖关系

    一种使用的关系,A类的变化引起了B类的变化,就说明B依赖于A。依赖关系有如下3种情况:
     1. A类是B类(方法中)的局部变量
     2. A类是B类方法中的参数
     3. A类向B类传递消息

2. 泛化关系

    类与类、接口和接口之间的继承关系。A类是B类和C类的父类,则A类具有B类和C类的共同特征,是B类和C类的泛化。

3. 关联关系

     类之间的联系,如:客户和订单。

  • 双向关联
  • 单项关联
  • 自关联
  • 重数性关联

4. 聚合关系

     整体与部分的关系,整体和部分可以分开。如:Car、Engine的关系,Computor、keyboard、mouse的关系

5. 组合关系

     整体与部分的关系,整体和部分不能分开,如:head、mouth的关系

6. 实现关系

     接口和类之间存在实现关系。

IoC的依赖关系

  1. Bean对Ioc容器的依赖
  2. Ioc容器注入Bean的依赖资源,如: 类、文件、常量数据等

依赖注入带来的好处?

  • 可以动态替换Bean,使程序更加灵活
  • 更好实践面向接口编程
  • 更好实践优先使用对象组合,而不是继承

面向接口编程、和优先使用对象组合可以降低耦合,增加代码复用。

Ioc容器依赖注入方式

     Ioc有2种依赖注入方式:构造器注入、setter注入

构造器注入

构造器:

public HelloServiceImpl3(String message, HelloService subService) {
    this.message = message;
    this.subService = subService;
  }

1. 通过参数索引注入

<bean id = "helloService1" class="com.kiikgu.HelloServiceImpl">
    <constructor-arg index="0" value="Hello World 1" />
  </bean>

  <bean id="helloSerivceByIndex" class="com.kiikgu.HelloServiceImpl3">
    <constructor-arg index="0" value="Hello World 3" />
    <constructor-arg index="1" ref="helloService1" />
  </bean>
  • index参数在构造器中的位置

2. 通过参数类型注入

<bean id="helloServiceByType" class="com.kiikgu.HelloServiceImpl3">
    <constructor-arg type="java.lang.String" value="hello world 4" />
    <constructor-arg type="com.kiikgu.HelloService" ref="helloService1" />
  </bean>

3. 通过参数名称注入

<bean id="helloServiceByName" class="com.kiikgu.HelloServiceImpl3">
    <constructor-arg name="message" value="hello world" />
    <constructor-arg name="subService" value="helloService1" />
  </bean>

4. 通过静态工厂和实例工厂注入

以静态工厂举例:

<bean id="helloServiceByFactoryIndex" class="com.kiikgu.HelloServiceFactory" factory-method="getHelloService">
    <constructor-arg index="0" value="Hello World 3" />
    <constructor-arg index="1" ref="helloService1" />
  </bean>

  <bean id="helloServiceByFactoryType" class="com.kiikgu.HelloServiceFactory" factory-method="getHelloService">
    <constructor-arg type="java.lang.String" value="hello world 4" />
    <constructor-arg type="com.kiikgu.HelloService" ref="helloService1" />
  </bean>

  <bean id="helloServiceByFactoryName" class="com.kiikgu.HelloServiceFactory" factory-method="getHelloService">
    <constructor-arg name="message" value="hello world 5" />
    <constructor-arg name="subService" ref="helloService1" />
  </bean>

setter注入

<bean id="helloService2"  class="com.kiikgu.HelloServiceImpl">
    <property name="message" value="hello world" />
    <property name="innerService" ref="helloService1" />
  </bean>

注入常量

<bean id="helloService2"  class="com.kiikgu.HelloServiceImpl">
    <property name="flag" value="on" />
    <property name="message" value="hello world" />
    <property name="innerService" ref="helloService1" />
  </bean>

在注入boolean类型的域时,Spring做了适配,值可以填:”true/false“、”yes/no“、”on/off“、”1/0“

注入集合、数组和词典

Bean定义

public class CollectionDIBean {
  private List<String> list;
  private Set<String> set;
  private Collection<String> collection;
  private String[] array;
  private String[][] array1;
  private Map<String, Integer> map;

  public List<String> getList() {
    return list;
  }

  public void setList(List<String> list) {
    this.list = list;
  }

  public Set<String> getSet() {
    return set;
  }

  public void setSet(Set<String> set) {
    this.set = set;
  }

  public Collection<String> getCollection() {
    return collection;
  }

  public void setCollection(Collection<String> collection) {
    this.collection = collection;
  }

  public String[] getArray() {
    return array;
  }

  public void setArray(String[] array) {
    this.array = array;
  }

  public String[][] getArray1() {
    return array1;
  }

  public void setArray1(String[][] array1) {
    this.array1 = array1;
  }

  public Map<String, Integer> getMap() {
    return map;
  }

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

  public void printList() {
    System.out.println(Arrays.toString(list.toArray()));
  }

  public void printSet() {
    System.out.println(Arrays.toString(set.toArray()));
  }

  public void printCollection() {
    System.out.println(Arrays.toString(collection.toArray()));
  }

  public void printArray() {
    System.out.println(Arrays.toString(array));
  }

  public void printArray1() {
    System.out.println(Arrays.deepToString(array1));
  }

  public void printMap() {
    for (String key : map.keySet()) {
      System.out.println(String.format("%s:%s", key, map.get(key)));
    }
  }
}

配置文件

<bean id="collectionDIBean" class="com.kiikgu.CollectionDIBean">
    <!--list -->
    <property name="list">
      <list value-type="java.lang.String">
        <value>cat</value>
        <value>dog</value>
        <value>fox</value>
        <value>panda</value>
      </list>
    </property>

    <!--set-->
    <property name="set">
      <set value-type="java.lang.String">
        <value>123</value>
        <value>123</value>
        <value>345</value>
      </set>
    </property>

    <!--collection-->
    <property name="collection">
      <list>
        <value>1</value>
        <value>2</value>
        <value>3</value>
      </list>
    </property>

    <!--array-->
    <property name="array">
      <array>
        <value>a1</value>
        <value>a2</value>
        <value>a3</value>
      </array>
    </property>

    <!--array-->
    <property name="array1">
      <array>
        <array>
          <value>a11</value>
          <value>a12</value>
        </array>
        <array>
          <value>a21</value>
          <value>a22</value>
        </array>
      </array>
    </property>

    <!--map-->
    <property name="map">
      <map>
        <entry key="k1" value="1" />
        <entry key="k2" value="2" />
        <entry key="k3" value="3" />
      </map>
    </property>
  </bean>

测试一下:

CollectionDIBean collectionDIBean = context.getBean("collectionDIBean", CollectionDIBean.class);
collectionDIBean.printList();
collectionDIBean.printSet();
collectionDIBean.printCollection();
collectionDIBean.printArray();
collectionDIBean.printArray1();
collectionDIBean.printMap();

[cat, dog, fox, panda]
[123, 345]
[1, 2, 3]
[a1, a2, a3]
[[a11, a12], [a21, a22]]
k1:1
k2:2
k3:3

注入Properites

bean定义

public class PropertiesDIBean {
  private Properties values;

  public Properties getValues() {
    return values;
  }

  public void setValues(Properties values) {
    this.values = values;
  }

  public void printValues() {
    for (Object key : values.keySet()) {
      System.out.println(String.format("%s : %s", key, values.get(key)));
    }
  }
}

配置

<bean id="propertiesDIBean" class="com.kiikgu.PropertiesDIBean">
    <property name="values">
      <props>
        <prop key="p1">v1</prop>
        <prop key="p2">v2</prop>
        <prop key="p3">v3</prop>
      </props>
    </property>
  </bean>

测试一下吧:

PropertiesDIBean propertiesDIBean = context.getBean("propertiesDIBean", PropertiesDIBean.class);
propertiesDIBean.printValues();

p3 : v3
p2 : v2
p1 : v1

引用其它Bean

基本配置:使用ref标签

<bean id="helloService3" class="com.kiikgu.HelloServiceImpl3">
    <constructor-arg type="java.lang.String" value="hello ref" />
    <constructor-arg type="com.kiikgu.HelloService">
      <ref bean="helloService1" />
    </constructor-arg>
  </bean>
<bean id="helloService3" class="com.kiikgu.HelloServiceImpl3">
    <constructor-arg type="java.lang.String" value="hello ref" />
    <constructor-arg type="com.kiikgu.HelloService" ref="helloService1"/>
  </bean>

高级配置:\

引用父容器中的bean

<!--spring-learn-parent.xml-->
<bean id = "helloService1" name="helloService1Name" class="com.kiikgu.HelloServiceImpl">
    <constructor-arg index="0" value="Hello parent" />
    <property name="flag" value="true" />
  </bean>
<!--spring-learn.xml -->
<bean id = "helloService1" name="helloService1Name" class="com.kiikgu.HelloServiceImpl">
    <constructor-arg index="0" value="hello son" />
    <property name="flag" value="yes" />
  </bean>

   <bean id="helloService3" class="com.kiikgu.HelloServiceImpl3">
    <property name="message" value="123" />
    <property name="subService">
      <ref parent="helloService1" />
    </property>
  </bean>

测试一下:

ApplicationContext parentContext = new ClassPathXmlApplicationContext("spring-learn-parent.xml");
ApplicationContext childContext = new ClassPathXmlApplicationContext(new String[]{"spring-learn.xml"}, parentContext);
HelloService helloService = childContext.getBean("helloService3", HelloService.class);
helloService.sayHello();

Hello parent
123

注入内部Bean

内部bean是在\或\内部用\标签定义的Bean,该内部bean对其它外部bean不可见

<bean id="helloService4" class="com.kiikgu.HelloServiceImpl3">
    <property name="message" value="outer bean" />
    <property name="subService">
      <bean id="innerBean" class="com.kiikgu.HelloServiceImpl">
        <constructor-arg name="message" value="inner bean" />
        <property name="flag" value="1"/>
      </bean>
    </property>
  </bean>

注入null

使用标签 \

<bean id="helloService4" class="com.kiikgu.HelloServiceImpl3">
    <property name="message"><null /></property>

对象图导航注入

Bean定义

public class NavigationDIBeanC {
  private String name;

}

public class NavigationDIBeanB {

  private NavigationDIBeanC c;

  private Map<String, String> values;

}

public class NavigationDIBeanA {

  private NavigationDIBeanB b;

}

省略了get、set方法

配置

<bean id="nc" class="com.kiikgu.NavigationDIBeanC" />
  <bean id="nb" class="com.kiikgu.NavigationDIBeanB" />
  <bean id="na" class="com.kiikgu.NavigationDIBeanA">
    <property name="b" ref="nb" />
    <property name="b.c" ref="nc" />
    <property name="b.values">
      <map>
        <entry key="123" value="123" />
      </map>
    </property>
    <property name="b.c.name" value="test" />
  </bean>
  • 这种方法不推荐使用

使用p命名空间简化setter注入

<?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"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

 <bean id="nc" class="com.kiikgu.NavigationDIBeanC" p:name="test1" />

指定命名空间:xmlns:p=”http://www.springframework.org/schema/p”

<bean id=”nc” class=”com.kiikgu.NavigationDIBeanC” p:name=”test1” />
相当于:
<property name=”name” value=”test1” />

总结

本节介绍了Spring DI的配置,包括:类之间的关系、Spring Ioc容器对Bean依赖关系的各种注入方式。