二、依赖注入的应用模式

前面我们了解了依赖注入的基本概念,也对一些依赖注入框架进行了简单的介绍,这一章我们主要来讨论作为开发者如何利用依赖注入框架来实现依赖注入的设计思想。

1.     依赖注入的方式

前面我们提到,所谓“依赖”,最简单地去解释就是一个Java类里的成员变量。我们都知道,给一个类中的私有成员变量赋值的方法通常有:通过Constructor构造方法、通过Setter方法、通过反射机制将私有变量的可见性设为true这三种方法。同样道理,依赖注入框架也是利用这三种方式来完成依赖对象的设定的,我们分别称之为Constructor注入、Setter注入、成员变量注入。

这里有两点需要注意的地方。一是除了这三种常见的注入方式,还有一些其他的注入方式,例如Spring框架中提供的lookup-method为代表的方法注入模式,也被称作“装饰器”模式,还有像Guice中的方法参数注入等等,我们在此不再详加讨论。二是并不是所有的依赖注入框架都提供这三种常见的注入方式,比如Seam2.x版本里就不支持Constructor注入的方式。

1.1.    Constructor注入

利用Constructor注入,即在依赖者类的构造函数上声明注入点,而要被注入的对象则是构造函数的参数。

我们来看利用Spring框架的例子。首先我们将Bank和DepositBook两个依赖类声明为Spring容器管理的组件:

@Component // 声明此依赖为Spring组件

public class BankICBC implements Bank { // ……  }

@Component // 声明此依赖为Spring组件

public class DepositBookICBC implements DepositBook { // ……  }

这里我们采用Spring
3.x提供的@Component方式来声明Spring组件,当然还有很多其它的方式,就不再详细阐述了。将这两个依赖声明为Spring容器管理的组件之后,它们就可以在被需要的时候由容器提供给依赖者了。例如在储户Depositor类中,我们定义了以Constructor为注入点的依赖请求:

@Component

public class Depositor {

@Autowired  // Constructor注入点

public Depositor(Bank bank, DepositBook
depositBook) {

this.bank = bank;

this.depositBook = depositBook;

}

private Bank bank;

private DepositBook depositBook;

public Cash withDraw(BigDecimal amount) {

return bank.withDraw(depositBook,
amount);

}

}

之后主程序在调用这个Depositor类的时候,容器就会自动将保管的依赖对象设定好之后分发给主程序了。

public void runSpringConstructorDI() {

AnnotationConfigApplicationContext context =

new
AnnotationConfigApplicationContext("tutorial.di.ch01");

Depositor depositor =
context.getBean(Depositor.class);

depositor.withDraw(new
BigDecimal(10000));

}

1.2.    Setter注入

第二种常用的声明注入点的方法是Setter注入,即依赖注入框架利用反射机制调用依赖者类的Setter方法来完成依赖注入。

我们来看利用Seam框架的例子。首先还是要将Bank和DepositBook两个依赖类声明为Seam容器管理的组件:

@Name("bank")

public class BankICBC implements
Bank { // ……  }

@Name("depositBook")

public class DepositBookICBC
implements DepositBook { // …… 
}

之后在依赖者Depositor类中的Setter方法处声明注入点:

@Name("depositor")

public class Depositor {

private Bank bank;

private DepositBook depositBook;

@In  // bank的Setter注入点

public void setBank(Bank bank) {

this.bank = bank;

}

@In  // depositBook的Setter注入点

public void setDepositBook(DepositBook
depositBook) {

this.depositBook = depositBook;

}

public Cash withDraw(BigDecimal amount) {

return bank.withDraw(depositBook,
amount);

}

}

注意Seam框架缺省是将与该依赖字段同名的标识符所绑定的依赖对象注入进来,如果想注入与字段名不同的标识符得依赖对象,需要使用@In(“依赖对象标识符”)这样的语法。

1.3.    成员变量注入

成员变量注入是指依赖注入框架利用反射机制,直接将依赖者类的成员变量set为容器管理的依赖对象。

仍以Seam框架为例,与刚才Setter注入模式唯一不同的就是将@In标注在成员变量旁,而不是其Setter方法上。

@Name("depositor")

public class Depositor {

@In  // bank的成员变量注入点

private Bank bank;

@In  // depositBook的成员变量注入点

private DepositBook depositBook;

public Cash withDraw(BigDecimal amount) {

return bank.withDraw(depositBook,
amount);

}

}

1.4.    注入模式的选择

对于该怎么使用前面介绍的这几种注入模式,究竟在什么情况下该使用哪种,这是一个讨论非常广泛的话题。这里只举一个简单的例子来说明,比如要设计一个不可变(final)依赖的类,则必须使用Constructor注入方式:

@Component

public class Depositor {

@Autowired  // Constructor注入点

public Depositor(Bank bank, DepositBook
depositBook) {

this.bank = bank;

this.depositBook = depositBook;

}

private final Bank bank; // 不可变的依赖

private final DepositBook depositBook; //
不可变的依赖

public Cash withDraw(BigDecimal amount) {

return bank.withDraw(depositBook,
amount);

}

}

再如如果一个类所拥有的依赖数量过多、而开发者又不想构造方法的参数成为“过长参数列表”(这是一种影响代码的可读性和可维护性的反模式,Martin
Fowler于1999年在其《Refactoring:Improving the Design of Existing
Code》一书中提出),则可考虑Setter注入或者成员变量注入。此外,如果遇到了类似“循环依赖”的情况,例如宿主和寄生动物这两个对象就属于相互依存的“循环依赖”模式,这样的情况下,我们就可能需要Constructor和Setter两种混合的模式才能解决。总而言之,选择依赖注入模式是一个很大的话题,我们在此就不再深入讨论了。

依赖注入及AOP简述(五)——依赖注入的方式 .的更多相关文章

  1. 依赖注入及AOP简述(三)——依赖注入的原理

    3.     “依赖注入”登场 于是诸多优秀的IT工程师开始想出了更加轻量便利.更加具有可测试性和可维护性的设计模式——IoC模式.IoC,即Inversion of Control的缩写,中文里被称 ...

  2. 依赖注入及AOP简述(九)——单例和无状态Scope .

    三.依赖注入对象的Scope及其生命周期 在前面的章节我们讲到,依赖注入容器之所以能够区别于以往的ServiceLocator等容器,是在于其不但能够自动构建多层次的.完整的依赖关系图,并且可以管理依 ...

  3. 依赖注入及AOP简述(七)——FQCN请求模式

    2.2.    FQCN请求模式 为了弥补纯字符串请求模式中的类型安全问题,全类名(FQCN)请求模式就应运而生了.其思想便是,在向容器请求依赖对象的时候,不是通过字符串的标识符.而是通过被请求的依赖 ...

  4. 依赖注入及AOP简述(六)——字符串请求模式 .

    2.     依赖注入对象的请求模式 前一节我们讨论了关于声明注入点的几种方法,这一节主要来介绍在注入点上如何定位到所需要的标识符的话题.基本上,我们可以用字符串为标识符来请求依赖对象.或者用全类名( ...

  5. 依赖注入及AOP简述(四)——“好莱坞原则”和依赖注入框架简介 .

    3.2.    “好莱坞原则” 看了前面关于依赖注入概念的描述,我们来提炼出依赖注入的核心思想.如果说传统的组件间耦合方式,例如new.工厂模式等,是一种由开发者主动去构建依赖对象的话,那么依赖注入模 ...

  6. 依赖注入及AOP简述(一)——“依赖”的概念 .

    一.入门:依赖注入 作为一种全新的设计模式理念,“依赖注入”这个词汇在软件设计开发中已经是越来越耳熟能详了,而各种流行于开源社区的“依赖注入框架”,也越来越多的被当作软件工程开发过程中使用的基础框架. ...

  7. 依赖注入及AOP简述(十一)——生命周期管理 .

    2.     生命周期管理 各种依赖注入框架提供了替开发者管理各种Scope的便利功能,随之而来的就必然是被管理的依赖对象的生命周期管理的问题.所谓生命周期管理,就是一个对象在它所属的Scope中从被 ...

  8. 依赖注入及AOP简述(十三)——AOP应用举例(完结) .

    2.     AOP应用举例 在一般的应用程序开发中,有一些典型的AOP应用,使得开发者可以专注于业务逻辑本身,而不是与之完全无关的一些“方面”. l        首先就是关于前面介绍过的日志输出类 ...

  9. 依赖注入及AOP简述(十二)——依赖注入对象的行为增强(AOP) .

    四.依赖注入对象的行为增强(AOP) 前面讲到,依赖注入框架的最鲜明的特点就是能够提供受容器管理的依赖对象,并且可以对对象提供行为增强(AOP)功能,所以这一章我们来讨论有关AOP的话题. 1.    ...

随机推荐

  1. JDBC官方用法

    JDBC官方用法https://bitbucket.org/xerial/sqlite-jdbc/#markdown-header-usage 代码下载https://github.com/xeria ...

  2. 对Linux 专家非常有用的20 个命令

    谢谢你你给了我们在这篇文章前两个部分的喜欢,美言和支持.在第一部分文章中我们讨论了那些都只是切换到 Linux 和linux新手所需的必要知识的用户的命令. 对 Linux 新手非常有用的 20 个命 ...

  3. android createbitmap函数内存溢出,求解怎样进行处理out of memory溢出问题

    android createbitmap函数内存溢出,求解怎样进行处理out of memory溢出问题 android createbitmap函数内存溢出,求解怎样进行处理out of memor ...

  4. PHP 超强过滤函数

    PHP 超强过滤函数 你有每次要过滤的时候总是去翻曾经的过滤代码的时候么? 你有搜索过怎样防过滤,防攻击的PHP解决方法么? 你有对全然遵循'过滤输入,避免输出',Web界经典说辞么?     事实上 ...

  5. 基于angularJS和requireJS的前端架构

    1.概要描述 1.1.angularJS描述:angularJS是可以用来构建WEB应用的,WEB应用中的一种端对端的完整解决方案.通过开发者呈现一个更高层次的抽象来简化应用的开发.最适合的就是用它来 ...

  6. Oracle SQL函数之转换函数

    chartorowid(c1) [功能]转换varchar2类型为rowid值 [参数]c1,字符串,长度为18的字符串,字符串必须符合rowid格式 [返回]返回rowid值 [示例] SQL> ...

  7. C# 坦克大战学习总结

    1.学会用Resource管理资源 添加资源 在properties下的Resource.resx添加资源 使用资源 工程名.Properties.Resource.资源名 实际本质,是一个流. 2. ...

  8. Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent

    修改pom.xml文件,添加以下属性 <project> ... <properties> <project.build.sourceEncoding>UTF-8& ...

  9. 正式软件工作第一天————MVC、ext JS、和clsa

    正式上班第一天,引导人就提出了MVC.extjs和clsa 三种框架,在这之前只听说了MVC,但还木有学习过,顺便把学习过程记录下来. MVC——初学习 1.M——model 模型:应用对象,处理业务 ...

  10. Mongodb实用网址记录

    ISODate类型算出时间戳> ISODate("2012-04-16T16:00:00Z").valueOf() 1334592000000 然后根据得到的时间戳查询即可d ...