写点什么

书摘与采访:依赖注入

2010 年 1 月 07 日

Dhanji R. Prasanna 的著作《依赖注入》是一本力图详细探究依赖注入领域,并呈现 Spring 和 Guice 技术的著作。Dhanji 是 Google 的一名软件工程师,从事 Google Wave 的研发,并对 Guice、MVCL 和其它开源项目做出了贡献。

本书分为 11 个章节:

  • 1-4 章介绍了可测试性以及使用依赖注入的原因,包括依赖注入的各种设计模式以及使用惯例,特别是如何选择这些模式以及怎样在不同的情形下应用模式。
  • 5-6 章集中在范围(scope)上,范围是一种不让基础结构的关注影响到上层逻辑的管理状态的方法。5-6 章还探究了一些常见问题例如静态单例反模式以及使用依赖注入的解决方案,并调查了 web 应用和其它应用的范围。
  • 第 7 章讨论了如何通过依赖注入器来管理应用的生命周期。这包括在应用的生命中发送重要事件的对象通知,设计定制的生命周期基础结构。
  • 第 8 章涉及面向方面的编程(AOP)在依赖注入中的应用,如何用 AOP 节省样板代码,如何减少错误的风险。这一章的一大部分用于说明使用这个强大技术的潜在风险和易犯的错误。
  • 9-11 章研究了并发和设计,对于性能、设计和与第三方框架的设计集成做了案例分析。11 章是对于如何使用贯穿于全书的概念来构建一个完整的 web 应用的案例分析。

在两节附录中还讨论了其他依赖注入框架,用于 Flex 的 SmartyPantsIOC 以及 Butterfly 容器。

本书的出版商 Manning 为 InfoQ 提供了第3 章的内容,标题是‘研究DI’

InfoQ 就这个书采访了作者:

InfoQ:你好 Dhanji,你能简单介绍一下自己以及为何会写一本关于 DI 的书么?

Dhanji:当然。我是在 Google 的一名软件工程师,我的日常工作是 Google Wave 产品,在空闲时间我致力于 Google Guice 和 MVEL——针对 Java 的表达式语言。我还在 Servlet 和 JAX-RS 专家组代表 Google 发言。 最初有另外一家小出版社联系我写一本 Guice 的小册子。那时候,我的好朋友(Apache Wicket 的开发者)Eelco Hillenius 正在为 Manning 写 Wicket in Action,他让我和 Manning 的人交流,他们建议我写一本更综合的关于设计模式和软件工程的书,这对我很有吸引力,我也更乐意写一本不偏倚于任何框架的书。

InfoQ:什么是“依赖注入”,它所致力解决的问题是什么?

Dhanji:非常简单的说,依赖注入的思想是不去主动获得你需要的东西,而是相反,你自己作为一种服务,让需要的东西来找 你。该模式的核心是将一个服务与它所依赖的其他服务解耦,这样一来,那些依赖可以替换为测试用的 mock 对象,或者针对其他环境替换为恰当的变体。通过保 持对于所依赖对象的不可知性,一个服务是高内聚的,功能专一的并且易于进化的,这一切都是通过坚持一个良好定义的契约实现的。 在书中我探索了与依赖注入相关的以及可能用于通用应用架构的多种设计模式。框架为日常编程工作提供了许多模式本身没有提供的增强功能。所以,本书中对依赖注入的彻底研究,在广义上是真正的对应用架构和设计的研究。我希望本书的副标题(设计模式)传达了这一信息。

InfoQ:在第 9 章你说“由一种语言以及它的工程基本原理预示的最佳实践,与依赖注入提出的最佳实践是相同的”。这个观点使得依赖注入的新老用户都有点困惑,你可以详细说明其含义么?

Dhanji:这与我之前的观点非常相似——那就是,这本书真正的是关于良好的应用设计与架构的。工程基本原理例如严格类型、松耦合、模块化设计以及组件重用也是依赖注入技术所鼓励和宣传的基本要素,尽管后者是使用声明式 API 以更有组织的形式表现的。 因此,在使用依赖注入做设计时犯的错误与通常的应用设计的反模式是类似的。我在书中力图搞清楚这些问题,有一章主要关注并发与面向对象的设计,这些在依赖注入中是要点,但是通常没有这样关联起来考虑。

InfoQ:Bob Lee,Guice 的创建者在介绍你的书的时候说对依赖注入的支持最终会成为另一个语言特征,“一个导入实例对象的构造器”。你如何看待这个观点?

Dhanji:我同意 Bob 的说法。在今天没有某种依赖注入的库的支持就开始写一个大型应用是难以想象的。几乎所有的现代企业框架都有一个核心的依赖注入组件。我认为甚至 EJB 现在也有类似的机制。 目前有一个更根本的议题,依赖注入是语言缺乏该功能的一种解决方法。它的确通过减少重复代码和使得代码更经得起变化给我们带来了巨大的好处,最终一门完备 的语言不应该需要这样的第三方库。Bob 的观点是我们最终会将依赖注入作为平台自身的一部分,而不是将它作为第三方的框架纳入平台。就如同今天你使用集合 类一样使用依赖注入。

InfoQ:在你的书中你列出了使用依赖注入的几种最佳实践和模式。你曾经看到过哪些人们误用依赖注入和依赖注入框架的方式(反模式)?

Dhanji: 噢,我看到过很多这样的例子!在我的书中警告的所有反模式都来自于真实的工作中的经验。我想主要问题是当人们将依赖注入看作一把锤子,所有的东西都变成了 钉子。方便的支持面向方面的编程(拦截方法调用和修改对象行为)可能是依赖注入框架的功能中被滥用的最严重的。当人们看到某些事情成为可能时十分兴奋,经 常会忽视可维护性、他们本来力图要解决的问题以及依赖注入可以解决的问题。 除了炒作之外,你不需要在所有看到“new”操作符的地方使用依赖注入。

InfoQ:你希望依赖注入框架向什么方向发展?你认为什么会是在将来可以期待的?

Dhanji: 我希望看到更多模块化的扩展以及对早期错误检测的更多关注。我们有一些分析工具用来描述和分析应用结构(例如,Guice 的 grapher)。我们小心地在 Guice 内部支持这个功能,我觉得将来在减少样板代码和潜在错误这个方面大有可为。 在扩展模块方面,我们计划支持统一的应用生命周期,扩充错误检查和针对 web 应用的更好的严格类型。我希望所有的依赖注入框架在这方面大步的进化,而不是急于支持一些花哨的功能或者当前的习惯。

InfoQ: 在你的书中你提到依赖注入框架已经进化了,它们已经在更好的利用领域特定语言了。你可以就此给出详细一些的解释么?

Dhanji:领域特定语言(DSL)现在很时尚,尤其是在 API 设计方面,DSL 已经被大量采用。然而,撇开时尚不 谈,DSL 在捕获声明意图方面非常简洁有用。依赖注入框架所做的许多事情(绑定实现细节,AOP 拦截,范围)是描述性的一系列声明语句或者目标。在这个意 义上,DSL 在配置一个依赖注入框架方面是非常有用的。Guice 使用一个内嵌的 DSL(有时候叫做内部的 DSL)来捕获配置,该 DSL 基本上是一个模仿 一个特定语言的 Java 构造器对象。在 Guice 2.0 中我们支持一个 DSL 可以在 web 应用中将 servlet 和过滤器映射到 URL 路径。

InfoQ:你可以告诉我们一些关于在 Google 使用依赖注入的情况么?如我在你的书中读到的,Guice 应用在一些像 Google Wave 这样高调的产品中。

Dhanji:在 Google 我们有非常严肃的测试。因此依赖注入几乎是每个工程师工具箱中的核心概念。今天在 Google 所有的 Java 应用都是 Guice 应用。我们已经发现它的特征(例如类型安全、早期检测和关注模块化)在构造大型的、可维护的应用方面是非常重要的。在公 司到处都有减少样板代码,让新来的工程师易于上手并学习遗留代码内部工作机制方面的成功案例。 在 Google Wave 中,我们几乎在应用的所有部分使用了 Guice,包括新的 servlet 模块,该模块已经彻底消除了对 servlet 和过滤器的基于 xml 配置的 需求。我们在开发过程中体会到顺畅的、模块化的 Java 程序是很容易合理化和设计的。例如,我们可以划分、合并、插入各种各样的涉及认证和站点安全的服 务,如同处理 Guice 的 servlet 模块一样简单。

这使得 Wave 灵活并且可以适应所有安全和用户加载的需求的变化。

InfoQ:最近关于 JSR-330(“Java 依赖注入”)与 JSR-299(“上下文与 Java EE 平台的依赖注入”)的争论很激烈。你如何看待这场争论?

Dhanji:很久以前(那时这个领域还很年轻),我与 Larry Cable、Rod Johnson、Bob Lee 和其他人一起努力标准化依赖注入。那次努力没有得到我们期待的结果,所以我很乐于看到这事再度发生。 按照我的理解,JSR-330 处理 Java SE 的基本依赖注入而 JSR-299 为 Java EE 容器增加了一套完整的、额外的服务。混乱最初是由一个 JSR 的变化与另外一个 JSR 一次晚些的不经意提交引起的。我相信两个 JSR 的规范负责人现在正在一起工作来达成一个令双方满意的结论,299 将建立在 330 的基础之上。

我个人不再使用 Java EE 而且也没有卷入任何一个规范,所以我对于它们没有深入的研究。

InfoQ:现在有一些关于依赖注入框架的著作,但是你的书采用了与其它书不同的方法,每当在深入框架支持之前,你会呈现依赖注入背后的基本概念。你认为对于初识依赖注入的读者来说什么是书中最值得读的部分,对于有依赖注入框架经验的读者来说哪些内容是可以帮助他们更上一层楼的?

Dhanji:我希望人们更多的考虑设计。如果我的书揭示了如何谨慎做出良好的可重用并且简明的设计,那我会非常高兴。依赖注入只是进入构建应用艺术的一扇窗——我要非常清楚地强调这一点,构建应用是艺术,不是科学。达到模块性、性能和可读性的最佳平衡点是非常困难的,只有通过大量实践和经验才能掌握该艺术。我在写着这本书的过程中以及我的职业生涯中犯了很多错误,这些错误对于教导我理解设计问题是怎样出现的以及如何规避设计问题是最宝贵的。

你可以在 InfoQ 的依赖注入 Guice Spring 专辑找到更多信息!

查看英文原文 Book Excerpt and Interview: Dependency Injection


感谢张凯峰对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家加入到 InfoQ 中文站用户讨论组中与我们的编辑和其他读者朋友交流。

2010 年 1 月 07 日 21:376889
用户头像

发布了 47 篇内容, 共 72371 次阅读, 收获喜欢 0 次。

关注

评论

发布
暂无评论
发现更多内容

架构师1期-技术选型(一)作业

ltl3884

极客大学架构师训练营

二十二、 深入Python的进程和线程(上篇)

刘润森

Python

食堂就餐卡系统设计

菜青虫

架构师训练营第五周作业——一致性哈希算法

文智

极客大学架构师训练营

架构师训练营W01作业

Geek_f06ede

极客大学架构师训练营

ping TCP端口的实用小工具tcping

网络技术平台

网络 ping tcping

2020年的Java程序员面试三件套:多线程+算法+微服务

Java架构师迁哥

介绍几种微商常见的引流方式

boshi

营销 电商

架构师训练营第1周学习总结

菜青虫

极客大学架构师训练营

【高并发】面试官问我:为什么局部变量是线程安全的?

冰河

多线程 高并发 高性能 线程安全 线程封闭

1024|推荐一个开源免费的Spring Boot教程

Java旅途

Java Spring Boot 开源项目

架构课第一课总结

路路

极客大学架构师训练营

架构师训练营 - 第五周 - 作业一

行者

第13周作业

Vincent

极客时间 极客大学

架构师训练营 1 期第 5 周:技术选型(一) - 总结

piercebn

极客大学架构师训练营

周练习 5

何毅曦

SQL优化-分治思想

墨凡

MySQL SQL优化

架构师训练营第一周作业

TONNY

程序员大保健指南,给自己的身心偶尔放松的机会

陆陆通通

Java 健康 保健 养生

一个大型的互联网应用系统使用了哪些技术手段

kawayi

架构师训练营 W01 总结

Geek_f06ede

极客大学架构师训练营

4. Validator校验器的五大核心组件,一个都不能少

YourBatman

Hibernate-Validator Bean Validation 数据校验

Netty源码解析 -- ChannelPipeline机制与读写过程

binecy

Netty nio 源码剖析

学习总结

TONNY

一个程序猿应该具备哪些能力?

伊智软件

程序员 1024讲话 1024

架构师训练营第五周作业

我是谁

极客大学架构师训练营

微服务监控:SpringBoot-Micrometer-Influx

LanLiang

监控 Influxdb springboot metrics

并发环境下,先操作数据库还是先操作缓存?

捡田螺的小男孩

数据库 缓存 后端 并发

架构师训练营 - 第五周 - 作业二

行者

第13周总结

Vincent

极客时间 极客大学

架构师训练营 第一课作业

文江

InfoQ 极客传媒开发者生态共创计划线上发布会

InfoQ 极客传媒开发者生态共创计划线上发布会

书摘与采访:依赖注入-InfoQ