依赖注入和Guice理解

理解依赖注入,这篇文章写得非常好,结合spring的依赖注入分析的。

http://blog.csdn.net/taijianyu/article/details/2338311/

大体的意思是:

有一个类A,这个类里的属性m(属性是接口类型)需要我们通过构造器或者setter方法传入(比如传入一个B接口实现类的实例,为啥属性或方法的参数类型都是接口类型,因为这样可以传接口不同实现类的实例啊),来为这个类A的该属性m设值。类A有了m属性值,就可以实现很多逻辑了。

在spring框架里,我们不需要自己去向类A的构造器或者setter方法手动传参(甚至不用自己调用这个方法),我们把他们的依赖关系(类A和B接口的一个实现类)写在配置文件中,然后我们调用。

ApplicationContext ctx = new FileSystemXmlApplicationContext("bean.xml”);

A  a = (A)ctx.getBean(“A类在配置文件中的id名”);

这样我们生成的A的实例中属性m就已经是B接口的那个实现类的实例了。我们根本就不需要自己去手动传入B接口的那个实现类的实例。因为依赖关系已经在配置文件中生成了,那么我们生成实例时,会自动加载。并且因为我们是在配置文件中写的他们的依赖关系,所以如果我们想生成的A的实例的属性m的值是B接口的另外一个实现类实例,我们只需要稍微改下配置文件就可以了,不需要改动java代码。

再总结总结上面,就是说我们可以将一个接口类型绑定到一个特定的该接口实现类(这里更精确的说是该接口类型的参数值绑定到了某个特定的该接口实现类的实例上了)上。好处就是在某处代码中需要某个实例时,不用我们自己手动创建(甚至不用传入),而是实现写好了他们的依赖关系,要用的时候就会自动生成了,也就是可以说将某个接口实现类的实例已经注入到 某个类的某个变量中了,相偎相依。

guice也可以实现绑定,只是不再使用繁杂的配置文件,下面说说guice:

跟前面的例子类似:

  1. class RealBillingService implements BillingService {
  2. private final CreditCardProcessor processor;
  3. private final TransactionLog transactionLog;
  4. @Inject
  5. RealBillingService(CreditCardProcessor processor,
  6. TransactionLog transactionLog) {
  7. this.processor = processor;
  8. this.transactionLog = transactionLog;
  9. }
  10. @Override
  11. public Receipt chargeOrder(PizzaOrder order, CreditCard creditCard) {
  12. ...
  13. }
  14. }

我们实现了BillingService接口(实现里面的chargeOrder()方法),我们在实现的过程中需要CreditCardProcessor和TransactionLog接口实现类的实例,那么我们怎么像spring 那样去给我们这两个CreditCardProcessor和TransactionLog接口类型的变量自动注入实例值呢?是这样的:

我们先自定义一个module,在configure()这个重写方法中进行绑定:

  1. public class BillingModule extends AbstractModule {
  2. @Override
  3. protected void configure() {
  4. /*
  5. * This tells Guice that whenever it sees a dependency on a TransactionLog,
  6. * it should satisfy the dependency using a DatabaseTransactionLog.
  7. */
  8. bind(TransactionLog.class).to(DatabaseTransactionLog.class);
  9. /*
  10. * Similarly, this binding tells Guice that when CreditCardProcessor is used in
  11. * a dependency, that should be satisfied with a PaypalCreditCardProcessor.
  12. */
  13. bind(CreditCardProcessor.class).to(PaypalCreditCardProcessor.class);
  14. }
  15. }

然后我们在需要使用BillingService接口实现类即RealBillingService实例的地方(我们需要RealBillingService实例中的CreditCardProcessor 接口变量 和  TransactionLog 接口变量都要初始化值,不然没法用,接下来就是做这个事情的,但不是手动直接传参),我们就利用我们创造的BillingModule来生成一个Injector实例:Injector injector = Guice.createInjector(new BillingModule());

这个injector就具有的这样的功能,即看到标记了@Inject的方法或变量有TransactionLog类型(如果是标记的方法,那么就是方法的参数有这个类型),就弄一个DatabaseTransactionLog类的实例(这里的弄指的是比如,当外界需要获取TransactionLog时(比如一个方法(@Inject标记的方法只能是类的构造方法和setter()方法,不能是其他方法)的参数是TransactionLog类型,就是需要获取),就返回一个DatabaseTransactionLog对象引用(自动返回,不需要手动传参),如果是一个TransactionLog类型的成员变量标记了@inject,那么也是需要获取,那么也会自动给该变量赋值一个DatabaseTransactionLog对象引用

),看到CreditCardProcessor就弄成PaypalCreditCardProcessor。比如这里我们调用:injector.getInstance(RealBillingService.class); 因为RealBillingService java代码中有

  1. @Inject
  2. RealBillingService(CreditCardProcessor processor,
  3. TransactionLog transactionLog) {
  4. this.processor = processor;
  5. this.transactionLog = transactionLog;
  6. }

该方法有一个@inject,那么就会向方法参数中传入:如果是TransactionLog类型,就传入DatabaseTransactionLog这个类的实例。如果是CreditCardProcessor类型,就传入PaypalCreditCardProcessor类的实例。

这样我们通过调用injector.getInstance(RealBillingService.class)得到的RealBillingService实例中的CreditCardProcessor 接口变量和TransactionLog接口变量已经初始化赋值了,和spring注入机制一样,这里赋值的过程也不需要我们手动的赋值,不需要我们调用构造方法进行传参,按上面的流程走一遍就自动赋值了。

上面这样写有一个问题,就是如果我们的RealBillingService这里面所有的标记了@Inject 的方法中和成员变量(假设方法参数里的参数类型和成员变量类型都是TransactionLog类型)需要的TransactionLog接口类型的实现类是不同的,我们上面就不能,因为上面我们绑定的时候,我们bind(TransactionLog.class).to(DatabaseTransactionLog.class); 那么injector看到@Inject下的含TransactionLog方法和变量时,就会传入和赋值DatabaseTransactionLog类型对象。所以这里并不能对于不同的TransactionLog

地方传入或赋值不同的TransactionLog实现类对象。那么我们怎么办呢?我们会使用@Named的方式,具体看代码,很容易理解:

  1. bind(CreditCardProcessor.class)
  2. .annotatedWith(Names.named("Checkout1"))
  3. .to(Checkout1CreditCardProcessor.class);
  4. bind(CreditCardProcessor.class)
  5. .annotatedWith(Names.named("Checkout2"))
  6. .to(Checkout2CreditCardProcessor.class);
  1. public class RealBillingService implements BillingService {
  2. @Inject
  3. public RealBillingService(@Named("Checkout1") CreditCardProcessor processor,
  4. TransactionLog transactionLog) {
  5. ...
  6. }
  7. @Inject
  8. @Named("Checkout2”)
  9. private CreditCardProcessor processor;
  10. }

这样就可以了,相当于在不同的地方做了不同的标记。

除了在自己写的module里面的configure()中进行bind()绑定,我们也可以不再这里面绑定,而是在一个接口或父类中直接进行声明。如果用injector对一个java类中的标记了@Inject 的变量和方法进行转换的时候(injector和@inject都不能少,一个是需要injector = Guice.createInjector(new BillingModule()),虽然这时候BillingModule()可以是空,但是还是需要Guice这个角色进行“转换”,因为Guice起着创造(bindBtoA)类B的对象的作用。并且需要@Inject 进行标记包含想要转换的变量的成员变量和方法),如果这个需要转换的类型在创建的时候已经写了如:

@ImplementedBy (SayHello.class)

  1. public interface Talk {
  2. public void sayHello();
  3. }

那么这样就算绑定了,其实和前面的链式bind()那种方式绑定一样的功能,只是绑定的位置不一样。但和链式绑定不同的是它们的优先级,@ImplementedBy实现的是一种default绑定,当同时存在@ImplementedBy和链式绑定时,链式绑定起作用。

provider的注入需要的时候再看。

时间: 2024-08-29 17:56:14

依赖注入和Guice理解的相关文章

记录对依赖注入的小小理解和autofac的简单封装

首先,我不是一个开发者,只是业余学习者.其次我的文化水平很低,写这个主要是记录一下当前对于这块的理解,因为对于一个低水平 的业余学习者来说,忘记是很平常的事,因为接触.应用的少,现在理解,可能过段时间就会忘了,自己记录下来应该可以少走些弯路,以免从头再来查找资料. 另外,如果我的记录能帮忙到一些朋友的话,也难免会有些小满足的.学习的门槛除了理解能力,绝大部分来自于英文水平和专业术语,我希望的是我能用比较通俗易懂的表达,获得大家的理解,更希望大牛们是如是做的,所以写这个更希望的是能得到大牛的帮助.

控制反转(IOC) 和依赖注入(DI) 的理解

1.      IOC(控制反转) inverseof control是spring容器的内核,AOP.声明事务等功能在此基础上开花结果. 2.      通过实例理解IOC概念: 实例:<墨攻>电影中有一个场景:当刘德华所饰演的墨者革离到达梁国都城下,城上梁国守军问道:“来者何人?“刘德华回答道:“墨者革离”.以此场景通过一个java类为这个“城门叩问”的场景进行编剧. MoAttract:通过演员安排剧本 public class MoAttack { public voidcityuGa

对spring控制反转以及依赖注入的理解

一.说到依赖注入(控制反转),先要理解什么是依赖. Spring 把相互协作的关系称为依赖关系.假如 A 组件调用了 B 组件的方法,我们可称A 组件依赖于 B 组件. 二.什么是依赖注入. 在传统的程序设计过程中,通常由调用者来创建被调用者的实例. 在依赖注入的模式下,创建被调用者的工作不再由调用者来完成,因此称为控制反转:创建被调用者实例的工作通常由Spring 容器来完成,然后注入给调用者,因此也称为依赖注入. 自己理解:即一句话,由spring容器来控制组件A的调用的具体对象B.组件A依

工厂方法模式与IoC/DI控制反转和依赖注入

IoC——Inversion of Control  控制反转 DI——Dependency Injection   依赖注入 要想理解上面两个概念,就必须搞清楚如下的问题: 参与者都有谁? 依赖:谁依赖于谁?为什么需要依赖? 注入:谁注入于谁?到底注入什么? 控制反转:谁控制谁?控制什么?为何叫反转(有反转就应该有正转了)? 依赖注入和控制反转是同一概念吗? 下面就来简要的回答一下上述问题,把这些问题搞明白了,IoC/DI也就明白了.(1)参与者都有谁: 一般有三方参与者,一个是某个对象:一个

从头认识Spring-1.1 什么是依赖注入?为什么须要依赖注入?

这一章节我们来讨论一下什么是依赖注入?为什么须要依赖注入? 1.什么是依赖注入? 笔者理解的是:对象的生成不再是通过显示的new,并且到spring容器里面取.对象的创建是使用注入这样的形式 2.为什么须要依赖注入? (1)解耦 (2)易于測试 我们以歌唱家唱歌这个为样例,在没有使用依赖注入情况下的代码: package com.raylee.my_new_spring.my_new_spring.ch01.topic_1_1; public class Song { @Override pub

(转)依赖注入和控制反转

发现一篇介绍依赖注入和控制反转的文章,特转载以备后用. 文章地址1:http://baitai.iteye.com/blog/792980 相关文章:http://www.cnblogs.com/DebugLZQ/archive/2013/06/05/3107957.html: http://www.cnblogs.com/xingyukun/archive/2007/10/20/931331.html: http://www.cnblogs.com/zhenyulu/articles/6417

[javascript] 反射与依赖注入!

对于javascript中的反射的理解,一直都是认为,利用数组对回调函数进行保存,之后在适当的时刻利用call或是apply 方法,对回调进行调用即可,一般如下操作: 首先定义两个方法: var service = function() { return { name: 'Service' }; } var router = function() { return { name: 'Router' }; } 我们有另一个函数需要用到这两个模块. var doSomething = functio

asp.net core 依赖注入

依赖注入入门 全面理解 ASP.NET Core 依赖注入 参考https://www.cnblogs.com/tcjiaan/p/8732848.html 如何在StartUp中的ConfigureServices方法里直接调用刚刚添加好的注册? // redis注入 services.AddSingleton<IRedisConnection>(k => { return new RedisConnection(6, Configuration["RedisConnecti

[ASP.NET Core 3框架揭秘] 依赖注入:依赖注入模式

原文:[ASP.NET Core 3框架揭秘] 依赖注入:依赖注入模式 IoC主要体现了这样一种设计思想:通过将一组通用流程的控制权从应用转移到框架之中以实现对流程的复用,并按照"好莱坞法则"实现应用程序的代码与框架之间的交互.我们可以采用若干设计模式以不同的方式实现IoC,比如我们在前面介绍的模板方法.工厂方法和抽象工厂,接下来我们介绍一种更有价值的IoC模式:依赖注入(DI:Dependency Injection). 一.由容器提供对象 和前面介绍的工厂方法和抽象工厂模式一样,依