依赖注入及AOP简述(三)——依赖注入的原理
3. “依赖注入”登场
于是诸多优秀的IT工程师开始想出了更加轻量便利、更加具有可测试性和可维护性的设计模式——IoC模式。IoC,即Inversion of Control的缩写,中文里被称作“控制反转”。至于为什么会有这么一个看似古怪的名字,我们稍后会做解释。2004年著名软件工程学者和工程师Martin Fowler在其论文《Inversion ofControl Containers and the Dependency Injection pattern》中将IoC更名为DependencyInjection,从此依赖注入模式成为实现组件间松耦合的主流设计思想。
3.1. 依赖注入的原理
那么应用了依赖注入,我们的开发模式将会发生什么样的变化呢?我们还是先来看看刚才的例子。下面的代码就是应用了依赖注入之后的储户Depositor类:
|
可以看到,这个Depositor类几乎就是最开始我们定义的那个最简单的、没有任何初始化依赖的过程的类!唯一不同的是在定义依赖成员变量的时候,多加了一个JavaSE5标准的注解——@In。这里@In注解是现今主流依赖注入框架之一JBoss
Seam所提供的一个注解,对于其它的依赖注入框架有着同样的使用方式,例如SpringFramework中提供了@Autowired注解等同于Seam的@In,Google
Guice框架中提供了@Inject注解等同于Seam的@In。关于依赖注入框架的话题我们稍候再做介绍,现在先来了解一下依赖注入框架的关于依赖注入的实现过程,这里我们还是以Seam框架为例进行介绍。
依赖注入框架的核心是依赖注入容器,也常被称为IoC容器或者叫Injector。其起的作用是管理一切注册到其中的依赖以及将这些依赖提供给请求依赖的依赖者。说到此或许有人会问,那这个依赖注入容器与前一节提到的ServiceLocator容器有什么不一样,不都是一个管理依赖对象的容器吗?答案是非常的不一样。不一样在于,首先依赖注入容器是极其轻量可控的,注册到其中的依赖对象可以方便的由开发者决定其标识符以及注册过程等,并且可以方便的放到单元测试环境中执行;其次依赖注入容器不仅仅是替开发者管理依赖,更重要的是它能够根据需要自动的去管理依赖对象的作用域及其生命周期,以及增强依赖对象的行为(即AOP),这一点我们在后面的章节中还会有详细的介绍。
回到刚才的例子:
|
这里被@In标注的地方被称作“注入点”(injectionpoint),声明注入点起到的作用就是,告诉依赖注入容器“在这里请把依赖对象给我!”,也就是@In向依赖注入容器发出了一个请求,之后容器会利用Java的反射机制将其保管的对象set到注入点,即完成了一次依赖注入。
如果@In注入点所请求的依赖对象自身还有依赖,那么依赖注入容器同样会以同样的方式先去设定好这个“依赖的依赖”,也就是说,依赖注入容器会帮助开发者构建一套完整的依赖关系图,最后将一个完全初始化好的依赖对象提供给依赖者。
严格地讲,依赖注入同样有很多种模式,当遇到诸如循环依赖模式、部分依赖模式等情况时,依赖注入容器并不能将“完全初始化”的对象提供给依赖者。这些情况比较特殊,各种依赖注入框架也有不同的解决方式,我们在此就不再详加讨论了。
至于如何将依赖注册到容器中,每种依赖注入框架都有不同的运用方式,但是基本上都是大同小异,这里我们看一段以Seam框架为例的代码:
|
这里@Name标注的类代表这个类需要作为依赖对象被注册到Seam容器中,在Seam容器随着应用程序启动过程中即可完成这个注册过程。之后注册到Seam容器的这两个依赖就可以在被请求的时候提供给依赖者了。Seam框架中除了@Name标注,还可以用XML文件的<component>标签配置的方式来声明一个需要被注册到容器中的组件类。而如果使用的是Spring框架,则可通过@Component或者XML的<bean>标签等方式来声明组件类;Guice框架中则是通过Module的binding等方式来完成这一过程,总而言之各种依赖注入框架都提供了方便的向其容器去注册依赖的方法。
需要注意的是,注解(如前面举例的@In)并不是定义注入点的唯一方式。一般依赖注入框架还会提供API的方式和XML配置的方式来声明注入点。例如API的方式中,使用Seam框架时调用其Component#getInstance的API,或者使用Spring框架时调用其BeanFactory#getBean的API,或者使用Guice时调用其Injector#
getInstance的API等,都是声明注入点的一种方法。再比如XML配置方式中,Seam和Spring框架都提供了<property>标签用于声明依赖者类中的注入点。
我们可以看到,应用了依赖注入设计思想之后,我们的Depositor类就可以以一种最简单的姿态出现在我们的代码库中。对于今后的维护,不管Bank和DepositBook两个依赖类发生了什么样的构造方法的变化,都不会影响到Depositor类本身。并且在单元测试中,我们可以方便的用Mock类替换掉实际的依赖。只需将Mock类绑定为相同的标识符,那么当依赖者请求依赖的时候,容器就会将Mock类提供给依赖者。例如:
|
依赖注入及AOP简述(三)——依赖注入的原理的更多相关文章
- 依赖注入及AOP简述(九)——单例和无状态Scope .
三.依赖注入对象的Scope及其生命周期 在前面的章节我们讲到,依赖注入容器之所以能够区别于以往的ServiceLocator等容器,是在于其不但能够自动构建多层次的.完整的依赖关系图,并且可以管理依 ...
- 依赖注入及AOP简述(五)——依赖注入的方式 .
二.依赖注入的应用模式 前面我们了解了依赖注入的基本概念,也对一些依赖注入框架进行了简单的介绍,这一章我们主要来讨论作为开发者如何利用依赖注入框架来实现依赖注入的设计思想. 1. 依赖注入的方 ...
- 依赖注入及AOP简述(七)——FQCN请求模式
2.2. FQCN请求模式 为了弥补纯字符串请求模式中的类型安全问题,全类名(FQCN)请求模式就应运而生了.其思想便是,在向容器请求依赖对象的时候,不是通过字符串的标识符.而是通过被请求的依赖 ...
- 依赖注入及AOP简述(六)——字符串请求模式 .
2. 依赖注入对象的请求模式 前一节我们讨论了关于声明注入点的几种方法,这一节主要来介绍在注入点上如何定位到所需要的标识符的话题.基本上,我们可以用字符串为标识符来请求依赖对象.或者用全类名( ...
- 依赖注入及AOP简述(一)——“依赖”的概念 .
一.入门:依赖注入 作为一种全新的设计模式理念,“依赖注入”这个词汇在软件设计开发中已经是越来越耳熟能详了,而各种流行于开源社区的“依赖注入框架”,也越来越多的被当作软件工程开发过程中使用的基础框架. ...
- 依赖注入及AOP简述(十一)——生命周期管理 .
2. 生命周期管理 各种依赖注入框架提供了替开发者管理各种Scope的便利功能,随之而来的就必然是被管理的依赖对象的生命周期管理的问题.所谓生命周期管理,就是一个对象在它所属的Scope中从被 ...
- 依赖注入及AOP简述(十三)——AOP应用举例(完结) .
2. AOP应用举例 在一般的应用程序开发中,有一些典型的AOP应用,使得开发者可以专注于业务逻辑本身,而不是与之完全无关的一些“方面”. l 首先就是关于前面介绍过的日志输出类 ...
- 依赖注入及AOP简述(十二)——依赖注入对象的行为增强(AOP) .
四.依赖注入对象的行为增强(AOP) 前面讲到,依赖注入框架的最鲜明的特点就是能够提供受容器管理的依赖对象,并且可以对对象提供行为增强(AOP)功能,所以这一章我们来讨论有关AOP的话题. 1. ...
- 依赖注入及AOP简述(十)——Web开发中常用Scope简介 .
1.2. Web开发中常用Scope简介 这里主要介绍基于Servlet的Web开发中常用的Scope. l 第一个比较常用的就是Application级Scope,通常我们会将一 ...
随机推荐
- eclipse中误删了servers文件
Eclipse中误删了servers文件,需要重新添加tomcat服务器,这时就会遇到在New Server对话框中选择了Tomcat 6/7后却无法单击"Next"按钮的问题,如 ...
- APPCAN学习笔记004---AppCan与Hybrid,appcan概述
APPCAN学习笔记004---AppCan与Hybrid,appcan概述 技术qq交流群:JavaDream:251572072 本节讲了appcan的开发流程,和开发工具 笔记不做具体介绍了,以 ...
- wcf 给net.tcp 加mex
<?xml version="1.0" encoding="utf-8" ?><configuration> <system.s ...
- 使用CSC.EXE编译第一个HELLO WORLD
坐的没事,下了个C#2008,看帮助文件写了个HELLO.CS的源文件: //hello.cs //Show "Hello Word!" using system; class h ...
- SonarQube 项目配置文件
费话不说,直接上代码: 需要注意的地方: 1. 每个项目的key不能重复. 2. 注意编码方式. 3. 注意分模块的写法. 4. 忽略源码文件的写法. # Required metadatasonar ...
- Hibernate 关联关系映射实例
双向多对一/一对多(many-to-one/one-to-many) 例子,多个学生对应一个班级,一个班级对应多个学生: 班级类,Grade.java: public class Grade { pr ...
- 关于JS变量和作用域
ECMAScript 变量:1.基本类型值(简单数据段) 2.引用类型值(可能由过个值构成的对象) → 保存在内存中的对象 动态属性: 只能给引用型值动态添加新属性,以便将来使用. 复制变量值 : 基 ...
- python 基础篇(一)--linux命令篇
期末下一门考试还有些时间,那就来看看python的视频吧,基于python2.7.6,用的是xubuntu(vm搭建虚拟机). 先花了2,3个小时安装了xubuntu,配置了搜狗输入法,gedit也配 ...
- android ellipsize 属性详解
TextView中内容过长时添加省略号的属性,即ellipsize 用法如下: 在XML文件中设置: android:ellipsize = "end" //省略号在结尾 andr ...
- 【Android类型SDK测试(二)】环境基础
(一)语言 Android使用的Java语言,所以要测试Android类型的SDK,Java的基础知识还是需要的. 另外,Android中有NDK类型的编程,需要知道C相关的知识. (二)环境准备 A ...