(4)Spring框架----依赖注入(DI)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_27706119/article/details/88981726

Spring发展到现在遵循“约定大于配置”原则,在基本的应用配置上(如数据库配置),建议采用XML配置方式;在业务逻辑处理上,建议采用注解方式。回顾过往,XML配置方式真的让人又爱又恨。所以,本节通篇采用XML配置方式。

1.DI的配置使用

1.1  依赖和依赖注入

传统应用程序设计中所说的依赖一般指“类之间的关系”,那先让我们复习一下类之间的关系:

  1. 泛化表示类与类之间的继承关系、接口与接口之间的继承关系;
  2. 实现:表示类对接口的实现;
  3. 依赖:当类与类之间有使用关系时就属于依赖关系,不同于关联关系,依赖不具有“拥有关系”,而是一种“相识关系”,只在某个特定地方(比如某个方法体内)才有关系。
  4. 关联:表示类与类或类与接口之间的依赖关系,表现为“拥有关系”;具体到代码可以用实例变量来表示; 
  5. 聚合:属于是关联的特殊情况,体现部分-整体关系,是一种弱拥有关系;整体和部分可以有不一样的生命周期;是一种弱关联;
  6. 组合:属于是关联的特殊情况,也体现了体现部分-整体关系,是一种强“拥有关系”;整体与部分有相同的生命周期,是一种强关联;

Spring IoC容器的依赖有两层含义:Bean依赖容器容器注入Bean的依赖资源

  1. Bean依赖容器:也就是说Bean要依赖于容器,这里的依赖是指容器负责创建Bean并管理Bean的生命周期,正是由于由容器来控制创建Bean并注入依赖,也就是控制权被反转了,这也正是IoC名字的由来,此处的有依赖是指Bean和容器之间的依赖关系
  2. 容器注入Bean的依赖资源:容器负责注入Bean的依赖资源,依赖资源可以是Bean、外部文件、常量数据等,在Java中都反映为对象,并且由容器负责组装Bean之间的依赖关系,此处的依赖是指Bean之间的依赖关系可以认为是传统类与类之间的“关联”、“聚合”、“组合”关系

 

为什么要应用依赖注入,应用依赖注入能给我们带来哪些好处呢?

  1. 动态替换Bean依赖对象,程序更灵活:替换Bean依赖对象,无需修改源文件:应用依赖注入后,由于可以采用配置文件方式实现,从而能随时动态的替换Bean的依赖对象,无需修改java源文件;
  2. 更好实践面向接口编程,代码更清晰:在Bean中只需指定依赖对象的接口,接口定义依赖对象完成的功能,通过容器注入依赖实现;
  3. 更好实践优先使用对象组合,而不是类继承:因为IoC容器采用注入依赖,也就是组合对象,从而更好的实践对象组合。
    • 采用对象组合,Bean的功能可能由几个依赖Bean的功能组合而成,其Bean本身可能只提供少许功能或根本无任何功能,全部委托给依赖Bean,对象组合具有动态性,能更方便的替换掉依赖Bean,从而改变Bean功能;
    • 而如果采用类继承,Bean没有依赖Bean,而是采用继承方式添加新功能,,而且功能是在编译时就确定了,不具有动态性,而且采用类继承导致Bean与子Bean之间高度耦合,难以复用。
  4. 增加Bean可复用性:依赖于对象组合,Bean更可复用且复用更简单;
  5. 降低Bean之间耦合:由于我们完全采用面向接口编程,在代码中没有直接引用Bean依赖实现,全部引用接口,而且不会出现显示的创建依赖对象代码,而且这些依赖是由容器来注入,很容易替换依赖实现类,从而降低Bean与依赖之间耦合;
  6. 代码结构更清晰:要应用依赖注入,代码结构要按照规约方式进行书写,从而更好的应用一些最佳实践,因此代码结构更清晰。

 

从以上我们可以看出,其实依赖注入只是一种装配对象的手段,设计的类结构才是基础,如果设计的类结构不支持依赖注入,Spring IoC容器也注入不了任何东西,从而从根本上说“如何设计好类结构才是关键,依赖注入只是一种装配对象手段”。

2.依赖注入实现方式

前边IoC一章我们已经了解了Bean依赖容器,那容器如何注入Bean的依赖资源,Spring IoC容器注入依赖资源主要有以下两种基本实现方式:

  1. 构造器注入:就是容器实例化Bean时注入那些依赖,通过在在Bean定义中指定构造器参数进行注入依赖,包括实例工厂方法参数注入依赖,但静态工厂方法参数不允许注入依赖;
  2. setter注入:通过setter方法进行注入依赖;

我们已经知道注入实现方式了,接下来让我们来看看具体配置吧。

2.1 构造方法注入

先定义一个汽车类

/**
 * 依赖注入
 * 【1】构造方法的注入方式
 */
public class Car {
	
	private String name;
	private Double price;
	
	public Car(String name, Double price) {
		this.name = name;
		this.price = price;
	}
	
	@Override
	public String toString() {
		return "Car [name=" + name + ", price=" + price + "]";
	}
	
}

XML配置:

<!-- ========================依赖注入注入的几种方式========================== -->
<!-- ========================1.使用构造方法的方式注入======================== -->
<!-- 常规构造方法注入 -->
<bean id="car" class="com.hl.spring.ioc.charcater4.Car" >
<!-- 
	<constructor-arg name="name" value="大奔"/>
	<constructor-arg name="price" value="100000"/>
-->
	<constructor-arg index="0" value="奇瑞QQ"/>
	<constructor-arg index="1" value="20000"/>
</bean>

汽车出来,总得有人去开车,造个人出来吧,Person类:

public class Person {
	
	private String name;
	private Car car;
	
	public Person(String name, Car car) {
		super();
		this.name = name;
		this.car = car;
	}

	@Override
	public String toString() {
		return "Person [name=" + name + ", car=" + car + "]";
	}
}

XML配置文件:

<!-- 构造方法注入,当Java类的属性是另一个Java类时 -->
<bean id="person" class="com.hl.spring.ioc.charcater4.Person">
	<constructor-arg name="name" value="xiaoming"/>
	<constructor-arg name="car" ref="car"/>
</bean>

 2.2 set方法注入

/**
 * 依赖注入
 * 【2】set方法的注入方式
 */
public class Car2 {
	
	private String name;
	private Double price;
	
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Double getPrice() {
		return price;
	}

	public void setPrice(Double price) {
		this.price = price;
	}


	@Override
	public String toString() {
		return "Car [name=" + name + ", price=" + price + "]";
	}
}

XML配置:

<!-- ==========================2.使用Set方法的方式注入========================== -->
<bean id="car2" class="com.hl.spring.ioc.charcater4.Car2">
	<property name="name" value="赛特"/>
	<property name="price" value="998" />
</bean>

  2.3 测试程序

public class Test01 {
	@Test
	public void run(){
		ApplicationContext context = 
				new ClassPathXmlApplicationContext("/character4.xml");
		
		/*【1】构造方法注入*/
		Car c = context.getBean("car",Car.class);
		System.out.println("构造方法注入:" + c);
		
		/*【1】构造方法注入,Java类的属性是另一个Java类时*/
		Person person = context.getBean("person",Person.class);
		System.out.println("构造方法注入:" + person);
		
		/*【2】set方法注入*/
		Car2 car2 = context.getBean("car2",Car2.class);
		System.out.println("set方法注入:" + car2);
	}
}

测试结果:

构造方法注入:Car [name=奇瑞QQ, price=2000.0]
构造方法注入:Person [name=xiaoming, car=Car [name=奇瑞QQ, price=2000.0]]
set方法注入:Car [name=赛特, price=998.0]

 4. 注入复杂类型

Spring不仅能注入简单类型数据,还能注入集合(Collection、无序集合Set、有序集合List)类型、数组(Array)类型、字典(Map)类型数据、Properties类型数据,接下来就让我们一个个看看如何注入这些数据类型的数据。

 

/**
 * 复杂类型的注入
 */
public class CollectionBean {
	
	private String[] arrs;
	private List<String> list;
	private Set<String> set;
	private Map<String, Integer> map;
	private Properties properties;
	
	public void setArrs(String[] arrs) {
		this.arrs = arrs;
	}

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

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

	public void setProperties(Properties properties) {
		this.properties = properties;
	}

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

	@Override
	public String toString() {
		return "CollectionBean [arrs=" + Arrays.toString(arrs) + ", list=" + list + ", set=" + set + ", map=" + map
				+ ", properties=" + properties + "]";
	}
}

 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"
    xmlns:context="http://www.springframework.org/schema/context" 
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd"> 
	
    <!-- ===================依赖注入注入,注入复杂类型=========================== -->
    <!-- properties标签中的name名称需要与CollectionBean类中对应变量的名称一致 -->
    <bean id="collectionBean" class="com.hl.spring.ioc.charcater5.CollectionBean">
    <!-- ========================注入数组======================== -->
        <property name="arrs">
	    <list>
		<value>哈哈</value>
		<value>呵呵</value>
		<value>嘿嘿</value>
	    </list>
        </property>
     
    <!-- ========================注入list======================== -->
	<property name="list">
	    <list>
		<value>小雷</value>
		<value>小风</value>
		<value>小雨</value>
	    </list>
	</property>
	
    <!-- =======================注入set集合======================= -->
	<property name="set">
	    <set>
		<value>set</value>
		<value>集合</value>
	    </set>
	</property>
		
    <!-- =======================注入map集合======================= -->
	<property name="map">
	    <map>
		<entry key="map01" value="1"></entry>
		<entry key="map02" value="2"></entry>
		<entry key="map03" value="3"></entry>
	    </map>
	</property>
		
    <!-- ==================注入properties属性文件================== -->
	<property name="properties">
	    <props>
	        <prop key="uname">root</prop>
	        <prop key="pass">123</prop>
	    </props>
	</property>
    </bean>
    
    <!-- ===============依赖注入注入,引入其他的xml配置文件=============== -->
    <!-- <import resource="character2.xml"/> -->
    
</beans>

测试:

public class Test05 {
	@Test
	public void run(){
		ApplicationContext context = 
				new ClassPathXmlApplicationContext("/character5.xml");
		CollectionBean bean = context.getBean("collectionBean",CollectionBean.class);
		System.out.println("复杂类型注入:" + bean);
	}
}

 测试结果:

复杂类型注入:
CollectionBean [
    arrs=[哈哈, 呵呵, 嘿嘿],
    list=[小雷, 小风, 小雨],
    set=[set, 集合], map={map01=1, map02=2, map03=3}, properties={uname=root, pass=123}
]

3.配置简写

让我们来总结一下依赖注入配置及简写形式,其实我们已经在以上部分穿插着进行简化配置了:

一、构造器注入:

1)常量值

简写:<constructor-arg index="0" value="常量"/>

全写:<constructor-arg index="0"><value>常量</value></constructor-arg>

2)引用

简写:<constructor-arg index="0" ref="引用"/>

全写:<constructor-arg index="0"><ref bean="引用"/></constructor-arg>

二、setter注入:

1)常量值

 简写:<property name="message" value="常量"/>

     全写:<property name="message"><value>常量</value></ property>

2)引用

 简写:<property name="message" ref="引用"/>

     全写:<property name="message"><ref bean="引用"/></ property>

3)数组:<array>没有简写形式

4)列表:<list>没有简写形式

5)集合:<set>没有简写形式

6)字典

简写:<map>

             <entry key="键常量" value="值常量"/>

             <entry key-ref="键引用" value-ref="值引用"/>

            </map>

 全写:<map>

             <entry><key><value>键常量</value></key><value>值常量</value></entry>

             <entry><key><ref bean="键引用"/></key><ref bean="值引用"/></entry>

           </map>

7)Properties:没有简写形式

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

使用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-3.0.xsd">
<bean id="bean1" class="java.lang.String">
        <constructor-arg index="0" value="test"/>
    </bean>
<bean id="idrefBean1" class="cn.javass.spring.chapter3.bean.IdRefTestBean" 
p:id="value"/>
<bean id="idrefBean2" class="cn.javass.spring.chapter3.bean.IdRefTestBean" 
p:id-ref="bean1"/>
</beans>
  • xmlns:p="http://www.springframework.org/schema/p" :首先指定p命名空间;
  • <bean id="……" class="……" p:id="value"/> :常量setter注入方式,其等价于<property name="id" value="value"/>
  • <bean id="……" class="……" p:id-ref="bean1"/> :引用setter注入方式,其等价于<property name="id" ref="bean1"/>

 

猜你喜欢

转载自blog.csdn.net/qq_27706119/article/details/88981726