Spring 依赖注入

  • 一 依赖注入
  • 二 Spring 基于构造函数的依赖注入
  • 三 Spring 基于设值函数的依赖注入
  • 四 Spring 注入集合


一 依赖注入

  • 依赖注入

Spring框架的核心功能之一就是通过依赖注入的方式来管理Bean之间的依赖关系。

每个基于应用程序的 java 都有几个对象,由这些对象一起工作来呈现出终端用户所看到的工作的应用程序。当编写一个复杂的 Java 应用程序时,应用程序类应该尽可能独立于其他 Java 类来增加这些类重用的可能性,并且在做单元测试时,测试独立于其他类的独立性。依赖注入(或有时称为布线)有助于把这些类粘合在一起,同时保持他们独立。

  • 依赖注入的两种方式

依赖注入类型

描述

构造函数注入

当容器调用带有多个参数的构造函数类时,实现基于构造函数的 DI,每个代表在其他类中的一个依赖关系。

设值函数注入

基于 setter 方法的 DI 是通过在调用无参数的构造函数或无参数的静态工厂方法实例化 bean 之后容器调用 beans 的 setter 方法来实现的。

二 Spring 基于构造函数的依赖注入

  • Spring 基于构造函数的依赖注入
    当容器调用带有一组参数的类构造函数时,基于构造函数的 DI 就完成了,其中每个参数代表一个对其他类的依赖。
    示例:
    这是 Car.java 文件的内容:
package com.zhang.work;
public class Car {

	private Wheel wheel; 
	
	public Car(Wheel wheel) {
		System.out.println("准备汽车...");
		this.wheel = wheel;
	}
	
	public void wheelFix() {
		wheel.fixWheel();
	}
}

这是另一个依赖类文件 Wheel.java 文件的内容:

package com.zhang.work;
public class Wheel {

	public Wheel() {
		System.out.println("准备轮胎...");
	}
	
	public void fixWheel() {
		System.out.println("安装轮胎...");
	}
}

这是配置文件 Beans.xml 文件的内容,它是基于构造函数注入的配置:

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

	<bean id="fixCar" class="com.zhang.work.Car">
		<constructor-arg ref="fixWheel"></constructor-arg>
	</bean>
	
	<bean id="fixWheel" class="com.zhang.work.Wheel"></bean>
</beans>

以下是 MainApp.java 文件的内容:

package com.zhang.work;
import com.zhang.pojo.*;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {

	public static void main(String[] args){
		
		/*
		 * 使用Spring IoC容器的方法
		 */
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("Beans.xml");
		Car car = applicationContext.getBean("fixCar",Car.class);
		
		car.wheelFix();
		
		/*
		 * 不使用Spring IoC容器的方法
		 */
		Wheel wheel = new Wheel();
		Car car = new Car(wheel);
		car.wheelFix();
	}
}

输出信息:

spring 依赖注入先后 spring依赖注入作用_构造函数

  • 构造函数参数解析:
    上面这个例子里,将依赖类 Wheel.java注入到Car.java 文件。如此,便称为依赖注入。
    如果存在不止一个参数时,当把参数传递给构造函数时,可能会存在歧义。要解决这个问题,那么构造函数的参数在 bean 定义中的顺序就是把这些参数提供给适当的构造函数的顺序就可以了。
    在上面示例的基础上添加一个依赖类 Stree.java
package com.zhang.work;
public class Car {

	private Wheel wheel;
	
	private Steer steer;
	
	
	public Car(Wheel wheel,Steer steer) {
		System.out.println("准备汽车...");
		this.wheel = wheel;
		this.steer = steer;
	}
	
	public void componentsFix() {
		wheel.fixWheel();
		steer.fixSteer();
	}
	
}

配置文件 Beans.xml的内容:

<bean id="fixCar" class="com.zhang.work.Car">
	<constructor-arg ref="fixSteer"></constructor-arg>
	<constructor-arg ref="fixWheel"></constructor-arg>	
</bean>
	
<bean id="fixWheel" class="com.zhang.work.Wheel"></bean>
	
<bean id="fixSteer" class="com.zhang.work.Steer"></bean>

让我们再检查一下我们传递给构造函数不同类型的位置。考虑下面的类:

package com.zhang.work;

public class Car {

	private String brand;
	
	private Wheel wheel;
	
	private Steer steer;
	
	private int wheelCount;
	
	public Car(String brand,Wheel wheel,Steer steer,int wheelCount) {
		System.out.println("准备汽车...");
		this.brand = brand;
		this.wheel = wheel;
		this.steer = steer;
		this.wheelCount = wheelCount;
	}
	
	public void componentsFix() {
		System.out.println(brand+"汽车有"+wheelCount+"个轮胎...");
		wheel.fixWheel();
		steer.fixSteer();
	}
}

如果你使用 type 属性显式的指定了构造函数参数的类型,容器也可以使用与简单类型匹配的类型。例如:

<bean id="fixCar" class="com.zhang.work.Car">
	<constructor-arg ref="fixSteer"></constructor-arg>
	<constructor-arg ref="fixWheel"></constructor-arg>
	<constructor-arg type="String" value="宝马"></constructor-arg>
	<constructor-arg type="int" value="4"></constructor-arg>
</bean>
	
<bean id="fixWheel" class="com.zhang.work.Wheel"></bean>
	
<bean id="fixSteer" class="com.zhang.work.Steer"></bean>

最后并且也是最好的传递构造函数参数的方式,使用 index 属性来显式的指定构造函数参数的索引。下面是基于索引为 0 的例子,如下所示:

<bean id="fixCar" class="com.zhang.work.Car">
	<constructor-arg ref="fixSteer"></constructor-arg>
	<constructor-arg ref="fixWheel"></constructor-arg>
	<constructor-arg index="0" value="4"></constructor-arg>
	<constructor-arg index="3" value="4"></constructor-arg>
</bean>
	
<bean id="fixWheel" class="com.zhang.work.Wheel"></bean>
	
<bean id="fixSteer" class="com.zhang.work.Steer"></bean>

最后,如果你想要向一个对象传递一个引用,你需要使用 标签的 ref 属性,如果你想要直接传递值,那么你应该使用如上所示的 value 属性。

三 Spring 基于设值函数的依赖注入

  • Spring 基于设值函数的依赖注入
    当容器调用一个无参的构造函数或一个无参的静态 factory 方法来初始化你的 bean 后,通过容器在你的 bean 上调用设值函数,基于设值函数的 DI 就完成了。
  • 示例:
  • 这是 Car.java 文件的内容:
package com.zhang.work;

public class Car {
	
	
	private Wheel wheel;

	public Wheel getWheel() {
		return wheel;
	}

	public void setWheel(Wheel wheel) {
		
		this.wheel = wheel;
	}
	
	public void wheelFix() {
		
		wheel.fixWheel();
	}
	
}

在这里,你需要检查设值函数方法的名称转换。要设置一个变量 wheel,我们使用 setWheel() 方法,该方法与 Java POJO 类非常相似。让我们创建另一个依赖类文件 Wheel.java 的内容:

package com.zhang.work;
public class Wheel {

	public Wheel() {
		System.out.println("准备轮胎...");
	}
	
	public void fixWheel() {
		System.out.println("安装轮胎...");
	}
}

这是配置文件 Beans.xml 文件的内容,它是基于构造函数注入的配置:

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

	<bean id="fixCar" class="com.zhang.work.Car">
		<property name="wheel" ref="wheel"></property>
	</bean>
	
	<bean id="wheel" class="com.zhang.work.Wheel"></bean>
	
</beans>

你应该注意定义在基于构造函数注入和基于设值函数注入中的 Beans.xml 文件的区别。唯一的区别就是在基于构造函数注入中,我们使用的是 < bean> 标签中的 < constructor-arg> 元素,而在基于设值函数的注入中,我们使用的是 < bean> 标签中的 < property> 元素。

注意:< property>元素中的name = “wheel” 属性值应与setter方法setWheel()相对应,用小写字母。

以下是 MainApp.java 文件的内容:

package com.zhang.work;
import com.zhang.pojo.*;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {

	public static void main(String[] args){
		
		/*
		 * 使用Spring IoC容器的方法
		 */
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("Beans.xml");
		Car car = applicationContext.getBean("fixCar",Car.class);
		
		car.wheelFix();
		
		/*
		 * 不使用Spring IoC容器的方法
		 */
		Wheel wheel = new Wheel();
		Car car = new Car(wheel);
		car.wheelFix();
	}
}

输出信息:

spring 依赖注入先后 spring依赖注入作用_构造函数_02

四 Spring 注入集合

  • Spring 注入集合
    你已经看到了如何使用 value 属性来配置基本数据类型和在你的 bean 配置文件中使用 < property> 标签的 ref 属性来配置对象引用。这两种情况下处理奇异值传递给一个 bean。
    现在如果你想传递多个值,如 Java Collection 类型 List、Set、Map 和 Properties,应该怎么做呢。为了处理这种情况,Spring 提供了四种类型的集合的配置元素,如下所示:

元素

描述

< list >

它有助于连线,如注入一列值,允许重复。

< set >

它有助于连线一组值,但不能重复。

< map >

它可以用来注入名称-值对的集合,其中名称和值可以是任何类型。

< props >

它可以用来注入名称-值对的集合,其中名称和值都是字符串类型。

例子

这里是 JavaCollection.java 文件的内容:

package com.tutorialspoint;
import java.util.*;
public class JavaCollection {
   List addressList;
   Set  addressSet;
   Map  addressMap;
   Properties addressProp;
   // a setter method to set List
   public void setAddressList(List addressList) {
      this.addressList = addressList;
   }
   // prints and returns all the elements of the list.
   public List getAddressList() {
      System.out.println("List Elements :"  + addressList);
      return addressList;
   }
   // a setter method to set Set
   public void setAddressSet(Set addressSet) {
      this.addressSet = addressSet;
   }
   // prints and returns all the elements of the Set.
   public Set getAddressSet() {
      System.out.println("Set Elements :"  + addressSet);
      return addressSet;
   }
   // a setter method to set Map
   public void setAddressMap(Map addressMap) {
      this.addressMap = addressMap;
   }  
   // prints and returns all the elements of the Map.
   public Map getAddressMap() {
      System.out.println("Map Elements :"  + addressMap);
      return addressMap;
   }
   // a setter method to set Property
   public void setAddressProp(Properties addressProp) {
      this.addressProp = addressProp;
   } 
   // prints and returns all the elements of the Property.
   public Properties getAddressProp() {
      System.out.println("Property Elements :"  + addressProp);
      return addressProp;
   }
}

下面是 MainApp.java 文件的内容:

package com.tutorialspoint;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
   public static void main(String[] args) {
   
      ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
      JavaCollection jc = (JavaCollection)context.getBean("javaCollection");
      jc.getAddressList();
      jc.getAddressSet();
      jc.getAddressMap();
      jc.getAddressProp();
   }
}

下面是配置所有类型的集合的配置文件 Beans.xml 文件:

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

   <!-- Definition for javaCollection -->
   <bean id="javaCollection" class="com.tutorialspoint.JavaCollection">

      <!-- results in a setAddressList(java.util.List) call -->
      <property name="addressList">
         <list>
            <value>INDIA</value>
            <value>Pakistan</value>
            <value>USA</value>
            <value>USA</value>
         </list>
      </property>

      <!-- results in a setAddressSet(java.util.Set) call -->
      <property name="addressSet">
         <set>
            <value>INDIA</value>
            <value>Pakistan</value>
            <value>USA</value>
            <value>USA</value>
        </set>
      </property>

      <!-- results in a setAddressMap(java.util.Map) call -->
      <property name="addressMap">
         <map>
            <entry key="1" value="INDIA"/>
            <entry key="2" value="Pakistan"/>
            <entry key="3" value="USA"/>
            <entry key="4" value="USA"/>
         </map>
      </property>

      <!-- results in a setAddressProp(java.util.Properties) call -->
      <property name="addressProp">
         <props>
            <prop key="one">INDIA</prop>
            <prop key="two">Pakistan</prop>
            <prop key="three">USA</prop>
            <prop key="four">USA</prop>
         </props>
      </property>

   </bean>

</beans>

输出信息:

spring 依赖注入先后 spring依赖注入作用_spring 依赖注入先后_03