Spring两种依赖注入方式
Constructor-based dependency injection :基于构造函数的依赖注入
Setter-based dependency injection :基于设值函数的依赖注入
一、Spring 基于构造函数的依赖注入
当容器调用带有一组参数的类构造函数时,基于构造函数的 DI 就完成了,其中每个参数代表一个对其他类的依赖。
通过构造方法注入Bean 的属性值或依赖的对象,它保证了 Bean 实例在实例化后就可以使用。
构造器注入在 <constructor-arg> 元素里声明属性, <constructor-arg> 中没有 name 属性。
1、来看个例子
首先来看,基于构造函数的类。注意:这里需要写有参的构造方法!
public class Constructor implements DIService { private String name; private int age; private String color; public Constructor(String name,int age,String color){ this.name = name; this.age = age; this.color = color; } @Override public String say() { return toString(); } @Override public String toString() { return "Constructor{" + "name='" + name + '\'' + ", age=" + age + ", color='" + color + '\'' + '}'; } }
2、在applicationContext.xml中的配置,这里按构造方法中参数的顺序进行赋值。name+age+color
<bean id="constructor" class="com.xoyar.spring.service.Constructor"> <constructor-arg value="constructor注入的名字"></constructor-arg> <constructor-arg value="666"></constructor-arg> <constructor-arg value="green"></constructor-arg> </bean>
二、Spring 基于设值函数的依赖注入
当容器调用一个无参的构造函数或一个无参的静态 factory 方法来初始化你的 bean 后,通过容器在你的 bean 上调用设值函数,基于设值函数的 DI 就完成了。
属性注入即通过 setter 方法注入Bean 的属性值或依赖的对象。
属性注入使用 <property> 元素, 使用 name 属性指定 Bean 的属性名称,value 属性或 <value> 子节点指定属性值。
属性注入是实际应用中最常用的注入方式。
1、为每个属性写上set访问器。
package com.xoyar.spring.service;
public class Setter implements DIService {
private String name;
private int age;
private String color;
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public void setColor(String color) {
this.color = color;
}
@Override
public String say() {
return toString();
}
@Override
public String toString() {
return "Setter{" +
"name='" + name + '\'' +
", age=" + age +
", color='" + color + '\'' +
'}';
}
}
2、xml配置
<!-- 通过setter方式注入的name属性-->
<bean id="setter" class="com.xoyar.spring.service.Setter">
<property name="name" value="setter方式注入的名字"></property>
<property name="age" value="18"></property>
<property name="color" value="red"></property>
</bean>
最后我们来测试一下:
@Test
public void DITest(){
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
Setter setter = (Setter) ctx.getBean("setter");
System.out.println(setter.say());
Constructor constructor = (Constructor) ctx.getBean("constructor");
System.out.println(constructor.say());
}
测试结果为:
Setter{name='setter方式注入的名字', age=18, color='red'}
2018-11-10 17:44:34 DEBUG [main] org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:251) - Returning cached instance of singleton bean 'constructor'
Constructor{name='constructor注入的名字', age=666, color='green'}
二、Spring 注入内部 Beans与ref属性
使用 <property> 元素 ref属性,引入另一个Bean对象,完成Bean之间注入。
<bean id="bydCar" class="com.xoyar.spring.dao.BydCarDaoImpl">
<constructor-arg value="比亚迪汽车"></constructor-arg>
<constructor-arg value="Byd"></constructor-arg>
<constructor-arg value="200000"></constructor-arg>
</bean>
<bean id="user" class="com.xoyar.spring.service.Impl.UserServiceImpl">
<property name="name" value="小明"></property>
<!-- 引用外部声明的list-->
<property name="car" ref="bydCar"></property>
</bean>
三、Spring 注入集合
在<list/>, <set/>, <map/>, 和<props/>元素中,也可以设置值和参数分别对应Java的集合类型List, Set, Map, 和 Properties。
p标签用法: p:<属性名>="xxx" 引入常量值 p:<属性名>-ref="xxx" 引用其它Bean对象
使用p必须引用p名称空间。改写<property>注入为 p名称空间注入。
<bean id="user1" class="com.xoyar.spring.service.Impl.UserServiceImpl">
<property name="name" value="小明"></property>
<!-- 引用外部声明的list-->
<property name="cars" ref="cars"></property>
</bean>
<!--声明集合类型的bean-->
<util:list id="cars">
<ref bean="bydCar"></ref>
<ref bean="foodCar"></ref>
</util:list>
使用p标签的写法
<!-- 简化写法-->
<bean id="user2" class="com.xoyar.spring.service.Impl.UserServiceImpl" p:cars-ref="cars" p:name="小红帽"/>
新建一个Gather类,全面地了解一下所有的集合类的注入方式。
1、新建Gather类,包含基本类型以及集合类型的属性。
package com.xoyar.spring.bean;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class Gather {
private String strVal;
private int intVal;
private List<String> listVal;
private Set<String> setVal;
private Map mapVal;
//所有的getter、setter方法。这里只写了map的以作实例
public Map getMapVal() {
return mapVal;
}
public void setMapVal(Map mapVal) {
this.mapVal = mapVal;
}
}
2、在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:p="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">
<bean id="gather" class="com.xoyar.spring.bean.Gather">
<property name="strVal" value="I am String"></property>
<property name="intVal" value="100"></property>
<property name="listVal">
<list>
<value>list1</value>
<value>list2</value>
<value>list3</value>
<value>list4</value>
<value>list5</value>
</list>
</property>
<property name="setVal">
<set>
<value>set1</value>
<value>set2</value>
<value>set3</value>
</set>
</property>
<property name="mapVal">
<map>
<entry key="k1" value="map1"></entry>
<entry key="k2" value="map2"></entry>
<entry key="k3" value="map3"></entry>
<entry key="k4" value="map4"></entry>
<entry key="k5" value="map5"></entry>
</map>
</property>
</bean>
</beans>
3、在测试类中测试一下
@Test
public void testGather(){
ApplicationContext ctx = new ClassPathXmlApplicationContext("bean-property.xml");
Gather gather = (Gather) ctx.getBean("gather");
System.out.println("String : "+gather.getStrVal());
System.out.println("Int : "+gather.getIntVal());
System.out.println("List : "+gather.getListVal());
System.out.println("Set : "+gather.getSetVal());
System.out.println("Map : "+gather.getMapVal());
}
4、控制台打印结果如下
String : I am String
Int : 100
List : [list1, list2, list3, list4, list5]
Set : [set1, set2, set3]
Map : {k1=map1, k2=map2, k3=map3, k4=map4, k5=map5}
Spring IOC总结
Spring 的IOC(控制反转)是通过依赖注入(dependency injection)来实现的。
优点 :
* 大量减少了对象的创建和管理 ,使代码层次更加清晰。
* Spring 的IOC容器是一个轻量级的容器 ,没有侵入性(不依赖容器的API) ,不需要实现一些特殊接口,这是一个合理设计的基本要求。
* 鼓励我们面向接口编程。
* 减少了代码的耦合,将耦合的部分推到了配置文件中 ,如果他们的关系发生了改变,只需要修改配置文件。
* 提供了aop声明式的服务能力。