Guice源码学习基本原理
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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对象。
以上是关于Guice源码学习基本原理的主要内容,如果未能解决你的问题,请参考以下文章
《Druid源码解析 Guice和Realtime流程》——图较精简,不错