6、依赖注入

依赖注入 (DI) 是一个过程。简单来说,就是将有依赖关系的 Bean 注入到容器中,解析出这些 Bean 的实例。

常用的注入方式:构造方法注入、 setter注入。

6.1、构造方法注入

即通过有参构造方法注入 Bean 对象的所有属性。

6.2、setter注入【重点】

通过 Beansetter 方法注入 Bean 对象的所有属性。

6.2.1、环境搭建

1、Person类

/**
 * 基本数据类型
 */
private String name;
/**
 * 引用数据类型
 */
private Reference reference;
/**
 * 数组类型
 */
private String[] stringArray;
/**
 * List类型
 */
private List<String> stringList;
/**
 * Set类型
 */
private Set<String> stringSet;
/**
 * Map类型
 */
private Map<String, String> stringStringMap;
/**
 * Properties类型
 */
private Properties props;
/**
 * 用于测试null
 */
private String nullTest;

2、配置元数据

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="person" class="indi.jaywee.pojo.Person">
        <!-- 依赖注入 -->
    </Bean>

</beans>

3、测试获取Bean对象

@Test
public void test() {
    // 实例化容器
    ApplicationContext context = new ClassPathXmlApplicationContext("personBeans.xml");
    // 获取Bean对象
    Person person = context.getBean("person", Person.class);

    System.out.println(person);
}

测试结果:

Spring:四、依赖注入和Bean的作用域_构造方法

6.2.2、依赖注入

1、配置元数据

<bean id="reference" class="indi.jaywee.pojo.Reference">
    <property name="reference" value="元素"/>
</Bean>

<bean id="person" class="indi.jaywee.pojo.Person">
    <!-- 基本数据类型 -->
    <property name="name" value="jaywee"/>
    <!-- 引用数据类型 -->
    <property name="reference" ref="reference"/>
    <!-- 数组 -->
    <property name="stringArray">
        <array>
            <value>元素1</value>
            <value>元素2</value>
            <value>元素3</value>
        </array>
    </property>
    <!-- List集合 -->
    <property name="stringList">
        <list>
            <value>元素1</value>
            <value>元素2</value>
            <value>元素3</value>
        </list>
    </property>
    <!-- Set集合 -->
    <property name="stringSet">
        <set>
            <value>元素1</value>
            <value>元素2</value>
            <value>元素3</value>
        </set>
    </property>
    <!-- Map集合-->
    <property name="stringStringMap">
        <map>
            <entry key="key1" value="value1"/>
            <entry key="key2" value="value2"/>
            <entry key="key3" value="value3"/>
        </map>
    </property>
    <!-- Properties -->
    <property name="props">
        <props>
            <prop key="prop1">value1</prop>
            <prop key="prop2">value2</prop>
            <prop key="prop3">value3</prop>
        </props>
    </property>
    <!-- 测试null -->
    <property name="nullTest">
        <null/>
    </property>
</Bean>

2、注入结果

Spring:四、依赖注入和Bean的作用域_构造方法_02

3、结论

​ 使用setter进行注入依赖,操作基本相同,注意使用对应的标签即可。

  1. 基本类型和引用类型:直接使用标签属性注入。

    • 基本类型:使用 value 属性;

    • 引用类型:使用 ref 属性。

      <property name="参数名" value="参数值"/>
      <property name="参数名" ref="引用其他Bean"/>
      
  2. 复杂类型

    • 数组、ListSet 集合

      • 使用对应类型的标签:array / list / set
      • 在标签内部,使用value标签注入,非自闭合标签。
      <property name="参数名">
          <类型>
              <value>元素1</value>
              <value>元素2</value>
              		...
          </类型>
      </property>
      
    • Map集合

      • 使用Map标签;
      • 在标签内部,使用 entry 标签注入,是自闭合标签。
      <property name="stringStringMap">
          <map>
              <entry key="key1" value="value1"/>
              <entry key="key2" value="value2"/>
      					...
          </map>
      </property>
      
    • Properties文件

      • 使用 props 标签;
      • 在标签内部,使用 prop 标签注入,非自闭合标签。
      <property name="props">
          <props>
              <prop key="prop1">value1</prop>
              <prop key="prop2">value2</prop>
                  		...
          </props>
      </property>
      
    • null空值

      • 使用 null 标签注入空值,自闭合标签。
      <property name="nullTest">
          <null/>
      </property>
      

6.3、*命名空间注入

通过p命名空间和c命名空间,需要引入 xmlns

  • p:相当于 setter 注入,需要无参构造方法setter
  • c:相当于构造方法注入,需要对应的有参构造器
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"

示例

<!-- p命名空间注入 -->
<bean id="user" class="indi.jaywee.pojo.User"
      p:name="SecretMrJ"
      p:age="17"
      p:reference-ref="reference"
/>

<!-- c命名空间注入
    需要对应的有参构造器:即要注入哪些属性,就要有对应属性的构造器。
    如以下注入:要有User(String name, int age, Reference reference)构造器
 -->
<bean id="user1" class="indi.jaywee.pojo.User"
      c:name="jaywee"
      c:age="7"
      c:reference-ref="reference"
/>

6.4、Bean的作用域

Spring:四、依赖注入和Bean的作用域_Spring_03

6.4.1、单例作用域

说明

  • Spring 默认机制:省略了scope="singleton"
  • 每次从容器中获取 Bean 时,得到的是对同一个 Bean 实例的引用;
  • 即全局共享一个实例。

测试

  1. XML 文件

    <bean id="user" class="indi.jaywee.pojo.User" scope="singleton"
          p:name="SecretMrJ"
          p:age="17"
          p:reference-ref="reference"
    />
    
  2. Test

    @Test
    public void test() {
    
        ApplicationContext context = new ClassPathXmlApplicationContext("userBeans.xml");
    
        User user = context.getBean("user", User.class);
        User user1 = context.getBean("user", User.class);
    
        System.out.println(user);
        System.out.println(user1);
    
        System.out.println("user.hashCode() = " + user.hashCode());
        System.out.println("user1.hashCode() = " + user1.hashCode());
    
        System.out.println("user == user1 -> " + (user == user1));
    }
    
  3. 测试结果hash 值相等,说明是对同一个 Bean 实例的引用。

    Spring:四、依赖注入和Bean的作用域_命名空间_04

6.4.2、原型作用域

说明

  • 需要手动设置:scope="prototype"
  • 每次从容器中获取 Bean 时,都会创建一个新的 Bean 实例;
  • 即每次请求都有一个单独的实例。

测试

  1. XML 文件

    <bean id="user" class="indi.jaywee.pojo.User" scope="prototype"
          p:name="SecretMrJ"
          p:age="17"
          p:reference-ref="reference"
    />
    
  2. Test:同上

  3. 测试结果hash 值不相等,说明是对不同Bean 实例的引用。

    Spring:四、依赖注入和Bean的作用域_Spring_05

6.4.3、其他作用域

web 开发中使用。