Google Guice容器外部有什么

前言

Maven系列,好几天没写了,次要是这几天被Google Guice卡住了,原本是能够轻易带过Guice,讲讲guice的用法就够了(Maven容器的下半场:Guice,据说仅次于Spring),然而,想着guice作为maven的底层IOC容器,对guice的了解深刻一些,对后续的Maven源码学习也会比拟有帮忙,因而,就在那开始剖析guice的源码。

guice作为一个仅次于Spring的IOC容器,代码也不是那么好懂的,毕竟也迭代了十来年了;代码量不少,另外,我感觉代码也有点绕,就看得真心有点打瞌睡。

因为上班回来也9点多了,学习的工夫也不多,因而,花了好几天工夫来单步debug,有一点点头绪,因而,这里先分享给大家,等后续了解深刻了再补充。

针对Guice的源码分析法

一般来说,我debug源码,都是从头开始,单步debug过来,很多时候,这种IOC框架啥的,启动非常复杂,一个小时也跟不完一趟;过程简短,一篇几千字的文章根本都讲不完,读者也记不住那么多货色,博主也很难讲清那么多货色。

我明天也想着换个思路吧,IOC容器,不是分两个阶段吗,启动时,个别是筹备IOC容器;而运行时,就是去容器拿货色。依据我的发现,个别为了保障运行时足够快,都会事后把数据筹备好,比方,针对singleton类型的实例,都会事后生成(eager-initilization),寄存到容器中,就无需运行时再去生成,归根结底,就是一个空间换工夫的办法。

采纳这种空间换工夫的办法,就会有个问题,就是在数据筹备阶段(比方容器初始化阶段),要做的工作相当多,debug过程也十分长;甚至,有时候筹备的很多数据,对于咱们的场景,基本用不上。

因而,上面我会先给大家看看,初始化胜利后的容器,是什么样的;再去简略剖析背地的启动过程。

简略demo

一共三个类。

public interface HelloInterface {    void hello();}public class HelloInterfaceImpl implements HelloInterface {    @Override    public void hello() {        System.out.println("hello world");    }}

再下边是启动类:

这个启动类,也就是三个局部:

  • 第一个局部,就是配置:HelloInterface这个class,要映射到 HelloInterfaceImpl这个实现类,后续,容器能力依据HelloInterface来new一个HelloInterface的实例进去。
  • 初始化容器
  • 运行时,从容器获取HelloInterface的对象

容器中有什么

假如咱们跳过初始化容器的阶段,不关怀容器如何结构,如何启动,只看:结构好的容器,是什么样的。

// 结构容器        Injector injector = Guice.createInjector(module);

在执行完下面这句后,容器就曾经初始化结束,此时,咱们打上断点,看看容器的外部:

类型

实在类型是:

// Default Injector implementation.final class InjectorImpl implements Injector, Lookups

从它实现的接口com.google.inject.Injector来看,次要有以下一些外围办法:

// 获取以后容器内的全副绑定关系Map<Key<?>, Binding<?>> getBindings();// 依据key,获取这个key对应的绑定关系。key其实根本就是一个接口的Class类名<T> Binding<T> getBinding(Key<T> key);// 依据class,获取这个class对应的绑定<T> Binding<T> getBinding(Class<T> type);// 依据key,获取对应的工厂类<T> Provider<T> getProvider(Key<T> key);// 依据class,获取对应的工厂类<T> Provider<T> getProvider(Class<T> type);//依据key/class,间接获取对应的实例<T> T getInstance(Key<T> key);<T> T getInstance(Class<T> type);

大家看到这里,是不是感觉和Spring的容器很像呢?

字段

  • 父容器

    final InjectorImpl parent;

    相似于spring,spring也有父子容器的概念;大体就是,以后容器找不到实例,还能够去父容器找

    咱们这个demo里,parent是null

  • 绑定map

    final ListMultimap<TypeLiteral<?>, Binding<?>> bindingsMultimap;

    存储了一些绑定关系,包含了三个默认的绑定,如:容器injector自身、日志logger、stage。

  • 容器选项

    final InjectorOptions options;

    这边是一些配置项,比方jitdisabled,禁止隐式依赖。禁止后,你要向容器获取Class X的实例,那么必须先配置X对应的实例化形式,不会再默认尝试调用Class X的结构器(如果有的话)

  • 隐式绑定

    final Map<Key<?>, BindingImpl<?>> jitBindings = Maps.newHashMap();

    比方咱们的这个实现类,就是个隐式绑定,因为咱们没配置如何实例化HelloInterfaceImpl。

  • 结构器缓存

      final ConstructorInjectorStore constructors = new ConstructorInjectorStore(this);

    比方咱们实现类的结构器,就被缓存了。

  • 外部状态:state

    看了以上几个字段,感觉也没有很特地。其实,真正重要的字段,是上面将出场的这个。

    final State state;

    大家看下图,会发现state下有不少字段,次要就有:每个class对应的绑定(value就是这个class的实例化形式)、还有咱们代码里配了个切面也在这里;基本上,这里才是真正的容器的各种数据的存放处

接下来,咱们再看看这个绑定关系的map。key就是对应的接口类,value就是说:怎么去实例化一个这个类型的实例进去,所以呢,guice外部,为了对立,根本把value这部分对立成了一个工厂。如下:

而工厂类里是什么样呢?

就是蕴含了对应的实现类的结构器了。

在真正要找容器获取这个HelloInterface的实例时,就能够找到HelloInterfaceImpl的构造函数,从而结构一个实例进去。

不同的binding形式,外部不同的工厂类

当咱们配置了一个如下的绑定关系时:

binder.bind(String.class).toInstance("xxx");

此时,外部又是什么样呢?

这里,咱们发现外部工厂internalFactory的类型,和之前也不太一样了。同时,下图能够看见,工厂外部间接存了这个String实例的值。

总之呢,也是保障后续间接就能在容器须要一个String类型实例时,找到“xxx”这个对象返回回去。

从容器中获取

容器初始化好了,怎么获取呢?即如下代码怎么执行呢?

HelloInterface instance = injector.getInstance(HelloInterface.class);

咱们略微跟了下,发现就会走到如下中央,会去查问state外部的显示绑定map。

获取到binding后,即取出internalFactory,而后结构/取出对象即可。

总结

不晓得大家清晰一点了没,心愿对大家有帮忙。后续会视状况,再看看是否剖析结构容器的源码。

我是逐日, 深圳腾讯打工人,成都深圳两地重复横跳的后端java程序猿一枚. 之前在深圳3年,起初去了成都4年,当初又来了深圳,也开始写写前端,有须要内推的能够找我。对于一线编码实战、网络、数据库、高并发等有浓厚兴趣。

也欢送加我,拉进技术群一起交换;腾讯内推也能够找我。

本文由博客一文多发平台 OpenWrite 公布!