• 【曹工杂谈】Maven IOC 容器-- Guice内部有什么


    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,然后构造/取出对象即可。

    总结

    不知道大家清晰一点了没,希望对大家有帮助。后续会视情况,再看看是否分析构造容器的源码。

  • 相关阅读:
    Jenkins搭建
    Hexo搭建静态博客站点
    FactoryBean简介以及Mybatis-Spring应用
    ArrayList源码分析
    BCZM : 1.8
    BCZM : 1.7
    BCZM : 1.6
    BCZM : 1.5
    BCZM : 1.4
    BCZM : 1.3
  • 原文地址:https://www.cnblogs.com/grey-wolf/p/15291571.html
Copyright © 2020-2023  润新知