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 公布!