Spring的控制反转(IoC)与依赖注入(DI)详解

1,867 阅读3分钟

个人简介:荡不羁,一生所爱。Java耕耘者(微信公众号ID:Java耕耘者),欢迎关注。可获得2000G详细的2020面试题的资料

一、概念:

**控制反转(Inversion of Control,英文缩写为IoC)****:****是一个重要的面向对象编程的法则来削减计算机程序的耦合问题,也是轻量级的Spring框架的核心。
**

控制反转一般分为两种类型,依赖注入(Dependency Injection,简称DI)和依赖查找(Dependency Lookup)(依赖注入应用比较广泛)
依赖注入:组件不做定位查询,只提供普通的Java方法让容器去决定依赖关系。容器全权负责的组件的装配,它会把符合依赖关系的对象通过JavaBean属性或者构造函数传递给需要的对象。通过JavaBean属性注射依赖关系的做法称为设值方法注入(Setter Injection);将依赖关系作为构造函数参数传入的做法称为构造子注入(Constructor Injection)

二、区别:

控制反转:创建对象实例的控制权从代码控制剥离到IOC容器控制,实际就是你在xml文件控制,侧重于原理。
依赖注入:创建对象实例时,为这个对象注入属性值或其它对象实例,侧重于实现。

**依赖注入是从应用程序的角度在描述,可以把依赖注入描述完整点:应用程序依赖容器创建并注入它所需要的外部资源;
**

控制反转是从容器的角度在描述,描述完整点:容器控制应用程序,由容器反向的向应用程序注入应用程序所需要的外部资源。

三、依赖注入机制的过程

待注入的业务对象:

Content.java
public class MyBusiness {    
private Content myContent;    
public MyBusiness(Content content) {       
myContent = content;    
}   
 public void doBusiness(){       
myContent.BusniessContent();    
}    
public void doAnotherBusiness(){      
 myContent.AnotherBusniessContent();    
}
}

MyBusniess类展示了一个业务组件,它的实现需要对象Content的注入。

代码3,代码4,代码5,6分别演示构造子注入(Constructor Injection),设值注入(Setter Injection)和接口注入(Interface Injection)三种方式。
代码3

1.构造子注入(Constructor Injection)

MyBusiness.java
public class MyBusiness {  
private Content myContent; 
public MyBusiness(Content content) {       
myContent = content;  
} 
public void doBusiness(){       
myContent.BusniessContent();  
}  
public void doAnotherBusiness(){       
myContent.AnotherBusniessContent();  
}

代码4

2.设值注入(Setter Injection)

MyBusiness.java
public interface InContent {    
void createContent(Content content);
}

代码5

设置注入接口

InContent.java
public interface InContent {    
void createContent(Content content);
}

代码6

3.接口注入(Interface Injection)

MyBusiness.java
public class MyBusiness implements InContent{    
private Content myContent;    
public void createContent(Content content) 
{       
myContent = content;    
}   
 public void doBusniess()
{      
 myContent.BusniessContent();    
}   
 public void doAnotherBusniess(){       
myContent.AnotherBusniessContent();    
}
}

四、依赖查找的过程

下面代码展示了基于JNDI实现的依赖查找机制:

public class MyBusniessObject{  
private DataSource ds; 
private MyCollaborator myCollaborator; 
 public MyBusnissObject()
{   
 Context ctx = null;
try
{    
ctx = new InitialContext();    
ds = (DataSource) ctx.lookup(“java:comp/env/dataSourceName”);   
 myCollaborator = (MyCollaborator)ctx.lookup(“java:comp/env/myCollaboratorName”);    
}……

依赖查找的主要问题是,这段代码必须依赖于JNDI环境,所以它不能在应用服务器之外运行,并且如果要用别的方式取代JNDI来查找资源和协作对象,就必须把JNDI代码抽出来重构到一个策略方法中去。

总结:

其实IoC/DI对编程带来的最大改变不是从代码上,而是从思想上,发生了“主从换位”的变化。

应用程序原本是老大,要获取什么资源都是主动出击,但是在IoC/DI思想中,应用程序就变成被动的了,被动的等待IoC/DI容器来创建并注入它所需要的资源了。
这么小小的一个改变其实是编程思想的一个大进步,这样就有效的分离了对象和它所需要的外部资源,使得它们松散耦合,有利于功能复用,更重要的是使得程序的整个体系结构变得非常灵活。