Guice源码学习(一)基本原理

Guice是Google开发的一个开源轻量级的依赖注入框架,运行速度快,使用简单。

项目地址:https://github.com/google/guice/

最新的版本是4.1,本文基于此版本。

Guice的使用方法请参见我的前篇博文:《Guice 4.1教程

0. Guice的使用范例

先分析最简单的例子

public interface Dog {
    void bark();
}

public class BlackDog implements Dog{
    @Override
    public void bark() {
        System.out.println("i am black dog");
    }
}

public class GuiceTest {
    public static void main(String[] args) {
        Injector injector = Guice.createInjector(new Module() {
            @Override
            public void configure(Binder binder) {
                binder.bind(Dog.class).to(BlackDog.class);
            }
        });

        injector.getInstance(Dog.class).bark();
    }
}

从上面的代码中,我们可以清楚的看出,Guice先利用自定义的Module创建了一个Injector,然后调用这个Injector的getInstance方法获得了Dog接口的BlackDog子类的一个实例

Dog接口与BlackDog子类的的绑定,则是在Module.configure方法中设置的。

1. Guice的本质

在分析源码之间,我们不妨先考虑一下Guice的本质。

Q:Guice主要解决的是什么问题?

A:依赖注入的问题

Q:怎么知道哪里的依赖会被注入?

A:被@Injector注解修饰的属性/构造方法/Setter方法会触发注入

Q:Guice怎么知道该注入什么实例?

A:初始化Injector时传入的Module对象,或者@ImplementedBy等注解,以及属性的注解都会限定被注入的对象的类型,如果不能限定到某种唯一特定的类型,Guice会抛出错误

这样我们就有一个大概的猜想了,Guice内部肯定维护了从接口到实现类的关系

其形式应该类似于一个Key为接口的class,value为实现类的Map

每次应用调用getInstance想要获取某个接口的实现类的实例的时候,就会去这个Map里检索,找到对应的实现类后调用其构造方法并返回

如果实现类中又有需要被注入的属性,则递归调用这一注入过程即可。

实际上,Guice内部确实维护了接口到实现类(也可能是Provider或者某个实例对象)的映射。

但是考虑到泛型与注解,Guice不是直接用接口的class作为key,而是用com.google.inject.Key来描述某个可以被注入的接口的,com.google.inject.Key的定义如下所示

public class Key<T> {

  private final AnnotationStrategy annotationStrategy;//注解限定

  private final TypeLiteral<T> typeLiteral;//类型限定
  private final int hashCode;
  private String toString;
}

Key内部有两个关键属性,annotationStrategy与typeLiteral,分别表示这个接口的注解限定与类型限定。

以本文开头部分的场景为例,Dog接口对应的Key中,annotationStrategy就是NullAnnotationStrategy(无注解),typeLiteral则为com.cc.test.guice.Dog(Dog接口的全称)

在createInjector函数中,Guice会完成从Dog接口到BlackDog实现类的绑定

而在getInstance方法中,传入的Dog.class也会被组装成Key对象,Guice很容易就可以根据根据这个Key对象找到正确的实现类BlackDog,这样就可以调用构造方法创建对象并返回了

2. Guice.createInjector方法的调用链

  public static Injector createInjector(Module... modules) {
    return createInjector(Arrays.asList(modules));
  }

  public static Injector createInjector(Iterable<? extends Module> modules) {
    return createInjector(Stage.DEVELOPMENT, modules);
  }

  public static Injector createInjector(Stage stage,
      Iterable<? extends Module> modules) {
    return new InternalInjectorCreator()
        .stage(stage)
        .addModules(modules)
        .build();
  }

从这里我们可以看出,Guice会利用应用指定的Module配合InternalInjectorCreator构建出一个Injector对象。

时间: 2024-10-14 20:56:34

Guice源码学习(一)基本原理的相关文章

jquery源码学习(二)sizzle部分 【转】

一,sizzle的基本原理 sizzle是jquery选择器引擎模块的名称,早在1.3版本就独立出来,并且被许多其他的js库当做默认的选择器引擎.首先,sizzle最大的特点就是快.那么为什么sizzle当时其他引擎都快了,因为当时其他的引擎都是按照从左到右逐个匹配的方式来进行查找的,而sizzle刚好相反是从右到左找的. 举个简单的例子 “.a .b .c”来说明为什么sizzle比较快.这个例子如果按照从左到右的顺序查找,很明显需要三次遍历过程才能结束,即先在document中查找.a,然后

由JDK源码学习HashMap

HashMap基于hash表的Map接口实现,它实现了Map接口中的所有操作.HashMap允许存储null键和null值.这是它与Hashtable的区别之一(另外一个区别是Hashtable是线程安全的).另外,HashMap中的键值对是无序的.下面,我们从HashMap的源代码来分析HashMap的实现,以下使用的是Jdk1.7.0_51. 一.HashMap的存储实现 HashMap底层采用的是数组和链表这两种数据结构.当我们把key-value对put到HashMap时,系统会根据ha

FireMonkey 源码学习(5)

(5)UpdateCharRec 该函数的源码分析如下: procedure TTextLayoutNG.UpdateCharRec(const ACanvas: TCanvas; NeedBitmap: Boolean; var NewRec: PCharRec; HasItem: Boolean; const CharDic: TCharDic; const AFont: TFont; const Ch: UCS4Char; const NeedPath: Boolean = False);

jquery源码学习

jQuery 源码学习是对js的能力提升很有帮助的一个方法,废话不说,我们来开始学习啦 我们学习的源码是jquery-2.0.3已经不支持IE6,7,8了,因为可以少学很多hack和兼容的方法. jquery-2.0.3的代码结构如下 首先最外层为一个闭包, 代码执行的最后一句为window.$ = window.jquery = jquery 让闭包中的变量暴露倒全局中. 传参传入window是为了便于压缩 传入undefined是为了undifined被修改,他是window的属性,可以被修

Hadoop源码学习笔记(1) ——第二季开始——找到Main函数及读一读Configure类

Hadoop源码学习笔记(1) ——找到Main函数及读一读Configure类 前面在第一季中,我们简单地研究了下Hadoop是什么,怎么用.在这开源的大牛作品的诱惑下,接下来我们要研究一下它是如何实现的. 提前申明,本人是一直搞.net的,对java略为生疏,所以在学习该作品时,会时不时插入对java的学习,到时也会摆一些上来,包括一下设计模式之类的.欢迎高手指正. 整个学习过程,我们主要通过eclipse来学习,之前已经讲过如何在eclipse中搭建调试环境,这里就不多述了. 在之前源码初

HSQLDB源码学习——数据库安装启动及JDBC连接

HSQLDB 是一个轻量级的纯Java开发的开放源代码的关系数据库系统.因为HSQLDB的轻量(占用空间小),使用简单,支持内存运行方式等特点,HSQLDB被广泛用于开发环境和某些中小型系统中. 在http://sourceforge.net/projects/hsqldb/files/下载了HSQLDB 1.8.0版本.把下载的zip文件解压缩至任意目录例如c:\hsqldb1.8便完成安装. hsqldb有四种运行模式: 一.内存(Memory-Only)模式:所有数据都在内存里操作.应用程

lodash源码学习(10)

_.delay(func, wait, [args]) 延迟wait毫秒之后调用该函数,添加的参数为函数调用时的参数 //delay.js var baseDelay = require('./_baseDelay'),//baseDelay方法 baseRest = require('./_baseRest'),//创建使用rest参数方法 toNumber = require('./toNumber');//转化为数字 /** * * @param {Function} func 需要延迟执

lodash源码学习(2)

继续学习lodash,依然是数组的方法 “Array” Methods _.indexOf(array, value, [fromIndex=0]) 获取value在数组 array所在的索引值 使用 SameValueZero方式比较(第一个全等===的元素). 如果 fromIndex 值是负数, 则从array末尾起算 该方法依赖于strictIndexOf和baseIndexOf方法,先看它们的源码 //_strictIndexOf.js /** * _.indexOf的专业版本,对元素

jQuery源码学习感想

还记得去年(2015)九月份的时候,作为一个大四的学生去参加美团霸面,结果被美团技术总监教育了一番,那次问了我很多jQuery源码的知识点,以前虽然喜欢研究框架,但水平还不足够来研究jQuery源码,那时我不明白他们为何要求那么高,现在才知道,原来没那么高,他问的都是jQuery最基本的框架架构,不过对于不知道的来说,再简单我也是不知道,那时写了一篇博文去吐槽了一下,那时候也是我自己真正激发自己的时候,那时候我说我一定要搞好自己的jQuery基础,没想到那么快就实现了,一个月的源码学习时间就结束