Spring 的控制反转(IOC)和依赖注入(DI)
控制反转(Inversion of Control)
就是当一个对象需要依赖于另一个对象时,通常由调用对象来创建被调用对象的实例。在Spring中,创建被调用对象的工作不再由调用对象来完成,而由Spring 容器来完成,然后注入调用对象,这就是Spring的控制反转IOC。(IOC是一种设计模式 )
依赖注入(Dependency Injection)
是目Q最优秀的解耦方式。使用依赖注入时,J2EE应用中的各种组件不需要以硬编码方式耦合在一起,当某个java实例需要其它java实例时,系统会自动提供需要的实例,无需程序显示获取. (DI是一种具体实现方式 )
依赖注入,是spring 的核心机制,可以使Spring 的bean 以配置文件组织在一起,而不是硬编码的方式耦合在一起。
Spring 控制反转和依赖注入是一个意思,不同的叫法,简单的说就是你需要的对象不需要你自己创建了,而是Spring给你创建好以后注入进去。Spring的依赖注入对调用对象和被调对象几乎没有任何要求,完全支持POJO之间的依赖关系的管理。依赖注入通常的两种方式是设值注入和构造注入。
(01)设置注入
设置注入是指通过setter方法传入被调用者的实例。这种注入方式简单、直观。设置注入也称set注入,即在程序中给每个变量都增加一个set方法,用来设置属性的值。So…上实例
这里定义接口
package com.ym.dao.imple;
public interface IAnimal {
/**
* 定一个到招呼的方法:
*/
public void animalWay1();
}
next:
还是定义一个接口
package com.ym.dao.imple;
public interface ICallType {
/**
* 定一个到叫声的方法:
*/
void call();
}
next:
这里定一个 DCallType 实现类继承 ICallType 接口
package com.ym.dao;
import com.ym.dao.imple.ICallType;
public class DCallType implements ICallType {
@Override
public void call() {
System.out.println("hellow !!! 我是一只小猫 ,喵喵叫....");
}
}
next:
这里定一个 DAnimal 实现类继承 IAnimal 接口
package com.ym.dao;
import com.ym.dao.imple.IAnimal;
import com.ym.dao.imple.ICallType;
import com.ym.entity.Animal;
public class DAnimal implements IAnimal {
//定义一个ICallType 接口参数
private ICallType call;
//get方法
public ICallType getCall() {
return call;
}
//set方法
public void setCall(ICallType call) {
this.call = call;
}
//默认构造函qi
public DAnimal() {
}
//接口实现方法
@Override
public void animalWay1() {
//调用叫声方法
call.call();
}
}
next:
applicationContext.xml中配置这样写的
<bean id="animal011" class="com.ym.dao.DAnimal" >
<property name="call">
<ref bean="dCallType"/>
</property>
</bean>
<bean id="dCallType" class="com.ym.dao.DCallType" />
Last:
我们来测试一哈
public void animalTest02(){
//通过配置文件获得Spring容器
ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
//获得接口 IAnimal
IAnimal ianimal1=(IAnimal)ac.getBean("animal011");
ianimal1.animalWay1();
}
结果:
So, as you can see from the above:
配置文件里bean的class元素中不能是接口,而必须是真正的实现类。
另外,Spring会自动接管每个bean定义里的property元素定义。Spring会在执行无参数的构造器后,创建默认的bean实例,并调用对应的setter方法为程序注入属性值。这里 property 定义的属性值将不再由该bean来主动创建和管理,而是接受Spring的注入
每个bean的id属性是该bean的唯一标识,程序通过id属性来访问bean,bean与bean的依赖关系也通过id属性关联。
(02)构造注入
指通过构造函数来完成依赖关系的设定,而不是通过setter方法。
对qing面的 DAnimal 类简单修改哈:
public class DAnimal implements IAnimal {
//定义一个ICallType 接口参数
private ICallType call;
//这里说明哈:此时方式下就不需要setCall方法了
//默认构造函qi
public DAnimal() {
}
//构造注入需要的带参数的构造qi
public DAnimal(ICallType call) {
super();
this.call = call;
}
//接口实现方法
@Override
public void animalWay1() {
//调用叫声方法
call.call();
}
}
next:
applicationContext.xml中配置这样写的
<bean id="dCallType" class="com.ym.dao.DCallType" />
<!--depends-on="call" 表示在 animal01的bean 初始化qing先必须qiang制初始化call 这个、bean的实例 -->
<bean id="animal01" class="com.ym.dao.DAnimal" depends-on="dCallType">
<!-- 给类中接口赋值 必须有有参构造函数 -->
<constructor-arg>
<ref bean="dCallType"/>
</constructor-arg>
</bean>
Last:
测试同上测试方法一样
From the above point of view:
两种注入方式效果是一样的,区别在于创建DAnimal 实例中 ICallType 属性的时候不同而已。
设值注入是先创建一个默认的bean实例,然后调用对应的setter方法注入依赖关系;
构造注入则在创建bean实例时,已经完成了依赖关系的注入。
然后看哈两个注入方式的比较
(01)设值注入的优点:
a、设值注入与传统的javaBean的写法更相似,so 对于我们来说更容易理解and 通过setter方法设定依赖关系显得更加直观、自然。
b、对于复杂的依赖关系,如果采用构造注入,就会导致构造qi过于臃肿。
c、在某些属性可选的时候,多参数的构造qi更加笨重。
(02)设值注入的优点:
a、可以在构造qi中决定依赖关系的注入顺序,eg:组件中qi它依赖关系的注入,常常需要依赖于Datasource的注入。采用构造注入 时,可以在代码中qing 晰的决定注入顺序,优先依赖的优先注入。
b、对于依赖关系无需变化的bean。构造注入更有用处。因为没有setter方法,所有的依赖关系quan部在构造qi内设定,因此无须担心后续代码对依赖关系产生破换。