《Spring揭秘》-第二章- 学习记录

打印 上一主题 下一主题

主题 640|帖子 640|积分 1920

1、IoC的理念

IoC全称为Inversion of Control,中文翻译为控制反转,同时还有一个别名叫 依赖注入DI(Dependency Injection)。大多将IoC与DI看作同等概念,也有部分观点认为 依赖注入可以看作IoC的一种实现方式。
在没有Spring的时候,当我们需要依赖某个类或服务时,一般通过new创建一个对象(或者通过ServiceLocator解决直接的依赖耦合),这些都需要主动的去获取需要的对象。
ServiceLocator是通过引入中间代理者消除对象间复杂的耦合关系,并统一管理分散的复杂耦合关系。
IoC的出现就为我们提供了更加简洁的方式,不用主动去构造对象,将“主动获取”转变为“被动接收”,下图即为IoC在整个过程中的所承担的角色

通常情况下,被注入对象会直接依赖于被依赖对象。但是在IoC的场景中,二者通过IoC Service Provider来交互,全部由IoC Service Provider统一管理。控制权由被注入对象转变为了IoC Service Provider 那里。
  1. public class NewsProvider {
  2.         // NewsProvider 为被注入对象
  3.         // INewsListener和INewsPersister为被依赖对象
  4.         private INewsListener newsListener;
  5.         private INewsPersister newsPersister;
  6. }
复制代码
其实IoC就是这么简单!以前是需要什么自己去拿,现在是需要什么东西别人主动送过来。下图形象的说明了使用IoC模式的前后差别

2、IoC(DI)的几种依赖注入的方式

IoC模式最常用的有三种依赖注入方式,分别是构造方法注入(Constructor Injection)、setter方法注入(Setter Injection)以及接口注入(Interface Injection)。
2.1、构造方法注入

构造方法注入即 被注入对象可以通过在其构造方法中声明所依赖对象的参数列表,让IoC容器知道它所需要的依赖对象列表。由于同一个对象是不可能是被构造两次的,因此,被注入对象的构造乃至其整个生命周期,都是由IoC Service Provider来管理的。
IoC Service Provider会检查被注入对象的构造方法,取得它所需要的依赖对象列表,进而为其注入相应的对象。具体代码示例如下
  1. public class NewsProvider {
  2.         // NewsProvider 为被注入对象
  3.         // INewsListener和INewsPersister为被依赖对象
  4.         private INewsListener newsListener;
  5.         private INewsPersister newsPersister;
  6.        
  7.         public NewsProvider(INewsListener newsListener, INewsPersister newsPersister) {
  8.                 this.newsListener = newsListener;
  9.                 this.newsPersister = newsPersister;
  10.         }
  11. }
复制代码
构造方法注入的方式比较直观,对象被构造完成后,就进入了就绪装填,可以马上使用。
2.2、setter方法注入

对于JavaBean对象来说,通常会通过setter方法来更改相应的对象属性。所以,当前对象只要为其依赖对象所对应的属性添加setter方法,就可以通过setter方法将相应的依赖对象设置到被注入对象中。代码示例如下
  1. public class NewsProvider {
  2.     // NewsProvider 为被注入对象
  3.     // INewsListener和INewsPersister为被依赖对象
  4.     private INewsListener newsListener;
  5.     private INewsPersister newsPersister;
  6.    
  7.     public void setNewsListener(INewsListener newsListener) {
  8.         this.newsListener = newsListener;
  9.     }
  10.     public void setNewsPersister(INewsPersister newsPersister) {
  11.         this.newsPersister = newsPersister;
  12.     }
  13. }
复制代码
这样,外界就可以通过调用setNewsListener和setNewsPersister方法来注入依赖对象了。
需要注意的是,setter方法注入不像构造方法注入那样,对象构造完成后即可使用,相对而言更加宽松一些,可以在对象构造完成之后再注入。
2.3、接口注入(基本废弃)

相对前面的两种注入方式来说,接口注入会更加复杂。被注入对象如果想让IoC Service Provider为其注入依赖对象,就必须实现某个接口。这个接口提供一个方法,用来为其注入依赖对象。IoC Service Provider 最终会通过这些接口来获取被注入对象所需要的依赖对象列表。
NewsProvicer为了让IoC Service Provider 为其注入所依赖的NewsListener对象,首先需要实现一个接口 INewsListenerCallable(名称随意),这个接口会声明一个injectNewsListener方法(名称随意),重要的是该方法的参数,必须是所依赖对象的类型。这样,对应的IoC Service Provider 就可以通过这个接口方法将依赖对象注入到 被注入对象 NewsProvider 当中。代码示例如下。
  1. public interface NewsListenerCallable {
  2.     // 声明方法
  3.     void injectNewsListener(INewsListener newsListener);
  4. }
  5. public class NewsProvider implements NewsListenerCallable{
  6.     private INewsListener newsListener;
  7.     @Override
  8.     public void injectNewsListener(INewsListener newsListener) {
  9.         this.newsListener = newsListener;
  10.     }
  11. }
复制代码
2.3、三种注入方式的比较


  • 构造方法注入。这种注入方式的优点就是,对象在构造完成之后,就已进入就绪状态,可以马上使用。缺点就是,当依赖对象变多时,构造方法的参数列表会比较长。同时通过反射构造对象时,对相同类型的参数处理会比较困难,维护和使用上也比较麻烦。而且在Java中,构造方法无法被继承,无法设置默认值。对于非必须的依赖处理,可能还需要引入多个构造方法,维护不便。
  • setter方法注入优点就是,在描述性上会比构造方法注入要好,同时可以被继承,允许设置默认值,而且有良好的IDE支持。缺点就是对象无法在构造完成后立马进入就绪状态。
  • 接口注入。从注入方式的使用上来说,接口注入是目前不提倡的一种方法,基本处于“退役状态”。因为需要被注入对象实现不必要的接口,带有侵入性。
综上,构造方法注入和setter注入因为其侵入性较弱,且易于理解和使用,所以是现在使用最多的注入方式;而接口注入由于其侵入性,已经不流行了。
本文由博客一文多发平台 OpenWrite 发布!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

tsx81428

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表