理解依赖注入,这篇文章写得非常好,结合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的注入需要的时候再看。

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

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

    首先,我不是一个开发者,只是业余学习者.其次我的文化水平很低,写这个主要是记录一下当前对于这块的理解,因为对于一个低水平 的业余学习者来说,忘记是很平常的事,因为接触.应用的少,现在理解,可能过段时间 ...

  2. C# 一个初学者对 依赖注入 IOC 的理解( 含 Unity 的使用)

    通过 人打电话 来谈谈自己对IOC的理解 版本1.0 public class Person { public AndroidPhone Phone { get; set; } public void ...

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

    1.      IOC(控制反转) inverseof control是spring容器的内核,AOP.声明事务等功能在此基础上开花结果. 2.      通过实例理解IOC概念: 实例:<墨攻 ...

  4. 【NetCore】依赖注入的一些理解与分享

    依赖注入 DI 前言 声明:我是一个菜鸟,此文是自己的理解,可能正确,可能有误.仅供学习参考帮助理解,如果直接拷贝代码使用造成损失概不负责. 相关的文章很多,我就仅在代码层面描述我所理解的依赖注入是个 ...

  5. DI(依赖注入)简单理解 NO1

    依赖注入:目的削减程序的耦合度,达到高内聚/低耦合 常用形式:Interface Driven Design接口驱动,接口驱动有很多好处,可以提供不同灵活的子类实现,增加代码稳定和健壮性等等.通过Io ...

  6. 依赖注入的方式测试ArrayList和LinkedList的效率(对依赖注入的再次理解)

    9/20 号再进行学习 在C++中,main函数尽可能的简单,只要调用子函数的一句话就实现了功能. java开发中,controller就相同于是main函数,其他类的方法不在本类中时候, 1.可以用 ...

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

    一.说到依赖注入(控制反转),先要理解什么是依赖. Spring 把相互协作的关系称为依赖关系.假如 A组件调用了 B组件的方法,我们可称A组件依赖于 B组件. 二.什么是依赖注入. 在传统的程序设计 ...

  8. 控制反转和依赖注入(对IOC,DI理解+案例)

    理解 控制反转说的官方一点就是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度.其实就是一种设计思想,大概思想就是把设计好的对象交给容器控制,而不是在你内部直接控制. 依赖注入是控制反 ...

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

    IoC——Inversion of Control  控制反转 DI——Dependency Injection   依赖注入 要想理解上面两个概念,就必须搞清楚如下的问题: 参与者都有谁? 依赖:谁 ...

随机推荐

  1. Docker Libnetwork driver API

    以下内容均在libnetwork/driverapi目录下 Driver接口如下所示: // Driver is an interface that every plugin driver needs ...

  2. 【我的Android进阶之旅】Android插件化开发学习资料

    1.目前开源的插件开发框架大致有哪些? 1. 任玉刚 的 dynamic-load-apk Github 地址:https://github.com/singwhatiwanna/dynamic-lo ...

  3. beego——session控制

    beego内置了session模块,目前session模块支持的后端引擎包括memory.cookie.file.mysql.redis.couchbase.memcache.postgres, 用户 ...

  4. 启动Django服务让其他电脑可访问

    1.修改 Django项目中的settings.py中的 ALLOWED_HOSTS 的值为 [*] # 准许那些地址访问,* 表示任意地址 ALLOWED_HOSTS = ['*'] # ALLOW ...

  5. 表单向controller传值如果没填controller取到的是null

    jsp前端表单,向controller传数据,如果没有值,后台传入的是null,比如checkbox未选中,后台设置的Integer[] ids,接收到的ids=null,hidden标签如果没有值, ...

  6. javascript Date对象 之 设置时间

    之前对js的date对象总是感觉熟悉,而不愿细细深究其所以然,所以每当自己真正应用起来的时候,总会糊里糊涂的,今日花费2个小时的时间仔细钻研了一下,感觉 豁然开朗,故,以此记录,一来 供以后查阅,二来 ...

  7. C++添加简单的日记记录

    #include<fstream>#include<iostream> using namespace std;//这是一种日记记录 b 种void LOG(char *tx, ...

  8. [转]hadoop2.x常用端口及定义方法

    端口 Hadoop集群的各部分一般都会使用到多个端口,有些是daemon之间进行交互之用,有些是用于RPC访问以及HTTP访问.而随着Hadoop周边组件的增多,完全记不住哪个端口对应哪个应用,特收集 ...

  9. 20145201《Java程序设计》第7周学习总结

    20145201 <Java程序设计>第七周学习总结 教材学习内容总结 本周学习了课本第十二.十三章内容,即Lambda.时间与日期 第十二章 Lambda 12.1 认识Lambda语法 ...

  10. react native 中的ReadableMap和WritableMap的使用

    react native跟安卓原生交互的数据类型中,有两个比较陌生的类型,ReadableMap和WritableMap. ReadableMap和WritableMap,顾名思义,反正是map. W ...