Spring学习----------深入理解Spring IoC容器

IoC他是Spring容器的内核,AOP、声明式事务等功能都依赖于此功能,它涉及代码解耦,设计模式、代码优化等问题的考量。

接下来使用电影与演员的关系来详细解释一下IoC:
我们来使用电影《无间道》中刘德华所饰演的角色刘建明在天台对白来作为我们学习IoC的示例场景。
那么我们现在便有:
接口类:ActorArrangable、LiuJianming
Java Bean:WuJianDao
接口实现类:LiuDeHua实现LiuJianming接口
执行类:Director
在传统的表演模式中,是剧本与演员直接耦合。即剧本直接指定LiuDeHua来表演

Spring学习----------深入理解Spring IoC容器

那么在引入角色接口LiuJianming之后,类与类之间的关系变为:

Spring学习----------深入理解Spring IoC容器

在这种情况下,WuJianDao还是和角色LiuJianming、演员LiuDeHua之间存在耦合关系。

那么我们该如何实现让演员与剧本无关,即剧本只与角色有关,但却必须使LiuDeHua来完成角色的表演。
那么,我们便引入导演类Director
这时,由导演选择剧本,并为剧本定义一个角色LiuJianming,让LiuJianming这个角色插入到剧本当中去。
最后让LiuDeHua来饰演LiuJianming这个角色。
Spring学习----------深入理解Spring IoC容器

对应到软件当中,导演就像是一个装配器。他来安排演员表演具体的角色。
那么我们现在便可以来谈谈IoC的概念,
IoC从字面意思上可以理解为:
  • 其一 控制
  • 其二 反转
那到底是什么东西的控制被反转了呢?
对应到前面的例子
控制指的是选择LiuJianming角色扮演着的控制权
反转是指这种控制权从WuJianDao剧本中移除,转交到了导演的手中。
那么对于软件来说:就是对应某个接口的控制权从调用类当中来移除,转交到了第三方来决定。
由此也引出了DI的概念:让调用类对某一接口实现类的依赖关系由第三方注入,以移除调用类对某一接口实现类的依赖
接下来看一下IoC的注入类型
IoC从注入方法上看,主要划分为三种类型:
1.构造函数注入:通过调用类的构造函数,将接口实现类通过构造函数变量传入
  1. Public class WuJianDao {  
  2.   private LiuJianming ljm;  
  3.   //1:注入刘建明的具体扮演者  
  4.   public WuJianDao(LiuJianming ljm) {  
  5.      this.ljm = ljm;  
  6.   }  
  7.     public void tianTai() {  
  8.              ljm.declare(“我想做一个好人!”)  
  9.     }  
  10. }  
  11.   
  12. Public class Director {  
  13.   public void direct() {  
  14.      //2.指定角色的扮演者  
  15.      LiuJianming ljm = new LiuDeHua();  
  16.      //3.注入具体扮演者到剧本中  
  17.      WuJianDao wjd = new WuJianDao(ljm);  
  18.      wjd.tianTai();  
  19.    }  
  20. }  

2.属性注入:通过Setter方法完成调用类所需依赖的注入,更加灵活方便
  1. Public class WuJianDao {  
  2.   private LiuJianming ljm;  
  3.   //1.属性注入方法  
  4.   public void setLjm(LiuJianmin ljm) {  
  5.      this.ljm = ljm;  
  6.   }  
  7.   public void tianTai() {  
  8.      ljm.declare(“我想做一个好人!”)  
  9.     }  
  10. }  
  11.   
  12. Public class Director {  
  13.   public void direct() {  
  14.      LiuJianming ljm = new LiuDeHua();  
  15.      WuJianDao wjd = new WuJianDao();  
  16.      //2.调用属性Setter方法注入  
  17.      wjd.setLjm(ljm);  
  18.      wjd.tianTai();  
  19. }  

3.接口注入:将调用类所有依赖注入的方法抽取到一个接口中,调用类通过实现该接口提供相应的注入方法。
  1. Public interface ActorArrangable {  
  2.   void injectLjm(LiuJianming ljm);  
  3. }  
  4.   
  5. Public class WuJianDao  
  6. implements ActorArrangable {  
  7.   private LiuJianming ljm;  
  8.   //1.实现接口方法  
  9.   public void injectLjm(LiuJianming ljm)  
  10.     {this.ljm = ljm; }  
  11.   public void tianTai() {  
  12.      ljm.declare(“我想做一个好人!”)  
  13.     }  
  14. }  
  15.   
  16. Public class Director {  
  17.   public void direct() {  
  18.      LiuJianming ljm = new LiuDeHua();  
  19.      WuJianDao wjd= new WuJianDao();  
  20.      wjd.injectLjm(ljm);  
  21.      wjd.tianTai();  
  22.    }  
  23. }  

由于采用接口注入需要额外声明一个接口,这无疑就增加了类的数目。
而且他的效果和属性注入并没有本质上的区别。所以,我们在Spring IoC当中并不提倡采用这种方式。
Spring作为一个容器,通过配置文件或者注解描述类和类之间的依赖关系,自动完成类的初始化和依赖注入的工作,
下面是对以上实例进行配置的配置文件:
  1. <?xml version="1.0" encoding="UTF-8" ?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.   xmlns:p="http://www.springframework.org/schema/p"  
  5.   xsi:schemaLocation="http://www.springframework.org/schema/beans  
  6.       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">  
  7.   <bean id="ljm" class="cn.lovepi.chapter02.ioc.LiuDeHua"/>  
  8.   <bean id="wjd" class="cn.lovepi.chapter02.ioc.WuJianDao"  
  9.         p:geli-ref="ljm"/>  
  10. </beans>  

那么,Spring为什么会有这种神奇般的力量呢?
仅凭一个简单的配置文件,就能魔法般的实现实例化并装配好程序所用的Bean呢。这种神奇的力量归功与JAVA语言本身的类反射功能。
下面,我们就来了解下JAVA语言的反射机制。