依赖注入与JSR-330的参考实现——Guice
2015-08-03 16:41
477 查看
依赖注入(控制反转的一种形式),它是Java开发主流中一个重要的编程范式(思维方式)。简单的说,使用DI技术可以让对象从别处获得依赖项,而不是由它自己来构造。使用DI有很多好处,它能降低代码之间的耦合度,让代码更易于测试、更易读。Java DI的官方标准是JSR-330,本文我们还会介绍
使用IoC范式编程时,程序逻辑的流程通常是由一个功能中心来控制的。而使用IoC,这个“中心控制”的设计原则会被反转过来。调用者的代码处理程序的执行顺序,而程序逻辑则被封装在接受调用的子流程中。通过一个例子来理解IoC:
在GUI应用中,GUI框架负责控制调用事件处理器,而不是应用逻辑。当用户点击了一个动作,比如“向前”,GUI框架会自动调用 对应的事件处理器,而应用逻辑可以把重点放在处理动作上。程序的控制被反转了,将控制权由应用逻辑转移到了GUI框架。
IoC也被称为
不要给我们打电话,我们会打给你。——好莱坞原则
IoC有多种不同的实现,包括工厂模式、服务器定位模式,当然还有依赖注入。需要注意的是,DI并不等于IoC,DI只是IoC的一种实现方式,IoC是一种机制。
DI是IoC的一种特定形态,是指寻找依赖项的过程不在当前执行代码的直接控制之下。Java中为DI提供的容器有Guice、Spring、PicoContainer等。DI的好处有:松耦合、易测试、强内聚、可重用、更轻盈的代码。
下面编写代码来解释到底什么是DI,如何使用DI。我们首先编写传统的代码,然后使用工厂模式解耦,进而再使用DI来改进代码,通过这个过程,你将了解到DI的精妙之处。这些改进都基于同一个关键技术,即面向接口编程。
假设你想找到所有对Java可开发人员比较友善的好莱坞经纪人。首先,我们有了一个
为了找到经纪人,项目中有个默认的
这是最传统的编码方式,显然,
为了改进这个问题,通常我们会想到一个常用的设计模式——工厂模式。工厂模式可以一定程度上解耦程序,它也是IoC的一种实现方式。
利用工厂模式(其实这里用到的是一个简单工厂)重新编写上面的代码,如下:
如你所见,这里不再有具体的实现来黏住你,而是通过注入
代码注入的仅仅是一个引用凭据(
方法
我们需要通过DI来达成这两个目标。
上面的代码是一个纯手工打造的DI方案,
但是,这种手工方式的DI显然存在问题,如何配置
Java中DI方面的标准规范是
6以上版本的流行的、轻量级的DI框架。
下面我们使用Guice来解决手工方式实现DI的不足问题:
首先我们需要创建一个定义绑定关系的AgentFinderModule模块(配置类)。
绑定关系的确立在调用Guice的
下面我们来Guice版本的HollywoodService:
我们在模块中声明了绑定关系,下面我们就可以让注入器构建对象关系图了。接下来我们看看在独立Java程序和Web应用程序这两种情况下分别要如何实现:
1.构建Guice对象关系图——独立Java程序
2.构建Guice对象关系图——Web应用程序 把
3.然后是标准动作,扩展
4.最好,将其加入到
经由注入器创建
关于JSR-330和Guice的更多用法,请参考其Github页面。
JSR-330的参考实现
Guice 3,一个轻量级 的DI框架。
IoC and DI
使用IoC范式编程时,程序逻辑的流程通常是由一个功能中心来控制的。而使用IoC,这个“中心控制”的设计原则会被反转过来。调用者的代码处理程序的执行顺序,而程序逻辑则被封装在接受调用的子流程中。通过一个例子来理解IoC:在GUI应用中,GUI框架负责控制调用事件处理器,而不是应用逻辑。当用户点击了一个动作,比如“向前”,GUI框架会自动调用 对应的事件处理器,而应用逻辑可以把重点放在处理动作上。程序的控制被反转了,将控制权由应用逻辑转移到了GUI框架。
IoC也被称为
好莱坞原则:会有另一段代码拥有最初的控制线程,并且由它来调用你的代码,而不是由你的代码调用它。
不要给我们打电话,我们会打给你。——好莱坞原则
IoC有多种不同的实现,包括工厂模式、服务器定位模式,当然还有依赖注入。需要注意的是,DI并不等于IoC,DI只是IoC的一种实现方式,IoC是一种机制。
DI是IoC的一种特定形态,是指寻找依赖项的过程不在当前执行代码的直接控制之下。Java中为DI提供的容器有Guice、Spring、PicoContainer等。DI的好处有:松耦合、易测试、强内聚、可重用、更轻盈的代码。
Example
下面编写代码来解释到底什么是DI,如何使用DI。我们首先编写传统的代码,然后使用工厂模式解耦,进而再使用DI来改进代码,通过这个过程,你将了解到DI的精妙之处。这些改进都基于同一个关键技术,即面向接口编程。假设你想找到所有对Java可开发人员比较友善的好莱坞经纪人。首先,我们有了一个
AgentFinder接口,及其两个实现类
SpreadSheetAgentFinder和
WebServiceAgentFinder。
AgentFinder接口如下:
传统方式寻找友善经纪人
为了找到经纪人,项目中有个默认的HollywoodService类,它会从
SpreadSheetAgentFinder里得到一个经纪人列表,并且过滤出友善的经纪人,最终返回该列表。
HollywoodService被
SpreadsheetAgentFinder这个
AgentFinder的具体实现死死的绑定住了。
为了改进这个问题,通常我们会想到一个常用的设计模式——工厂模式。工厂模式可以一定程度上解耦程序,它也是IoC的一种实现方式。
工厂模式
利用工厂模式(其实这里用到的是一个简单工厂)重新编写上面的代码,如下:agentFinderType的方式让你选择想要的AgentFinder。但这里仍然还有问题:
代码注入的仅仅是一个引用凭据(
agentFinderType),而不是真正实现
AgentFinder的对象
方法
getFriendlyAgents中还有获取其依赖的代码,达不到只关注自身智能的理想状态
我们需要通过DI来达成这两个目标。
手工实现DI
AgentFinder被直接注入到
getFriendlyAgents方法中。现在这个
getFriendlyAgents方法干净利落,只专注于纯业务逻辑。
但是,这种手工方式的DI显然存在问题,如何配置
AgentFinder具体实现的问题并没有解决,原本
AgentFinderFactory要做的工作还是要找一个地方去做。解决这个问题的方式是借助DI框架,而DI框架就是把你的代码打包起来的运行时环境,在你需要的时候注入依赖项。
使用Guice
Java中DI方面的标准规范是JSR-330,它提供了统一的DI通用功能的标准,而且提供了你需要了解的幕后规则及限制。这里不具体介绍
JSR-330,有兴趣的可以查找相关资料阅读。我们重点介绍
JSR-330的参考实现
Guice,它是一个由Google实现的针对Java
6以上版本的流行的、轻量级的DI框架。
下面我们使用Guice来解决手工方式实现DI的不足问题:
首先我们需要创建一个定义绑定关系的AgentFinderModule模块(配置类)。
bind方法时发生,把要绑定的类(
AgentFinder)传给它,然后调用to方法指明要注入到哪个实现类。
下面我们来Guice版本的HollywoodService:
1.构建Guice对象关系图——独立Java程序
Gucie-servlet.jar加到web应用的类库中,然后再
web.xml中添加下面的配置项:
ServletContextListener以便使用Guice的
ServeltModule:
web.xml文件中,以便servlet容器在部署应用时触发该类:
HollywoodServiceGuice,你得到一个配置完备的类,马上就可以调用其中的
getFriendlyAgents方法了。
关于JSR-330和Guice的更多用法,请参考其Github页面。
相关文章推荐
- iOS开发系列--UITableView全面解析
- USACO 2.1.3 Sorting A Three-Valued Sequence
- 【控件】iOS8新控件之UIAlertController
- Selenium2学习-029-WebUI自动化实战实例-027-判断元素是否存在
- UITalbeView - 3
- UITextField隐藏软键盘心得(隐藏自身软键盘、点击Return自动转到下个文本框、轻触背景隐藏软键盘)
- 自定义导航按钮UIBarButtonItem
- hdu 4027 Can you answer these queries? (区间线段树,区间数开方与求和,经典题目)
- Curator: delay queue
- could not build module ‘Foundation’, could not build module ‘UIKit’……23个错误
- POJ2299 Ultra-QuickSort(归并排序求逆序数)
- poj1679.The Unique MST(最小生成树是否唯一)
- IOS 错误:Failed to instantiate the default view controller for UIMainStoryboardFile
- flask中的request.form对象方法
- Selenium2学习-028-WebUI自动化实战实例-026-获取页面元素值或者元素属性值
- UIScrollView 与 Use Auto Layout
- 运用UI制作简单的 登陆系统
- C# 获取URL参数 NameValueCollection
- ViewPager,java.lang.UnsupportedOperationException: Required method destroyItem was not overridden
- iOS开发UI篇—使用UItableview完成一个简单的QQ好友列表(二)