- 为什么需要依赖注入?
- ServiceUser是组件,在编写者之外的环境内被使用,且使用者不能改变其源代码.
- ServiceProvider是服务,其类似于ServiceUser,都要被其他应用使用,不同是ServiceProvider会被用于非本地环境,需要对应不同环境.
- 普通的ServiceUser来负责直接创建所需Service实现的实例方法.拥有以下的局限
- 在不同的环境下,ServiceProvider是千差万别的(数据库,临时文件,内存).
- 所以,不能将ServiceUser作为组件发布(适应不了各种差异环境).
- 为了将ServiceUser所在单元作为组件发布,必须满足以下的条件.
- 将ServiceUser与具体的ServiceProvider_Imp解耦(解除编译时依赖).即不能出现new ServiceProvider_Imp()语句.
- 在运行时,根据环境来为ServiceUser来动态地提供ServiceProvider的实现实例.
- 总之,将ServiceUser和ServiceProvider之间的依赖,由编译时,推迟到运行时动态决定.
- 即在运行时"注入"这种依赖,称为依赖注入(DI).
- ServiceUser可以看做框架.其需要对外发布,被其他模块使用.
- ServiceProvider可看做插件.其在不同的环境下有差别.
- 依赖注入
- 在编译时,使用IServiceProvider接口.在运行时,再将具体的实现类型绑定到ServiceUser上.
- 从而实现了服务的使用者(框架)和服务的提供者(插件)的松耦合.
- 加入一个Assembler(容器)来完成对框架单独发布所需的要求.
-
- 构造器DI
- 构造器指的是ServiceUser的构造器,也就是在构造ServiceUser的实例时,才把具体的ServiceProvider_实现传递给它.
-
CtorDI
1 class ServiceUser 2 { 3 IServiceProvider sp; 4 ServiceUser(IServiceProver sp) 5 { 6 this.sp = sp; 7 } 8 } 9 10 private MutablePicoContainer configureContainer() { 11 MutablePicoContainer pico = new DefaultPicoContainer(); 12 //下面就是把ServiceProvider和ServiceUser都放入容器的过程,以后就由容器来提供ServiceUser的已完成依赖注入实例, 13 //其中用到的实例参数和类型参数一般是从配置档中读取的,这里是个简单的写法。 14 Parameter[] finderParams = {new ConstantParameter("movies1.txt")}; 15 pico.registerComponentImplementation(IServiceProvider.class, ServiceProvider.class, finderParams); 16 pico.registerComponentImplementation(ServiceUser.class); 17 //至此,容器里面装入了两个类型,其中没给出构造参数的那一个(ServiceUser)将依靠其在构造器中定义的传入参数类型,在容器中 18 //进行查找,找到一个类型匹配项即可进行构造初始化。 19 return pico; 20 }
相关文章: