`
zhuhui_zj
  • 浏览: 36229 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Guice源代码分析(一)

阅读更多

一、简介

    Guice中通过自定义Module实现中的bind、to等语法实现绑定信息的注册,在绑定中存在着一种特殊的情形:范型绑定,如下:

public class ListUser { 
    @Inject @Named("list") List<String> strings; 
    @Inject @Named("list") List<Integer> integers; 
}

    Java的范型实现采用了擦除的方式 ,为此无法在运行时区分List<String>和List<Integer>类,因为模板参数的信息在运行时都已经被擦除了。为了能在运行时得到模板参数的信息,Guice引入了TypeLiteral类,它代表类的型别信息,在Guice文档中将其称为"Super Type Tokens"。

    Guice运行时的一个核心数据结构是存储绑定信息的一个Map实例,该Map将一个接口以及附加的注释映射到实现类上。在Guice中通过Key这个类来标示唯一的绑定信息。

二、TypeLiteral类

    TypeLiteral类主要的目的是在运行时得到模板参数的信息,并以统一的方式代表非范型类和范型类的型别。

public abstract class TypeLiteral<T> {

  final Class<? super T> rawType;
  final Type type;
  final int hashCode;

  ...
}

    TypeLiteral是抽象类,其中的rawType代表擦除模板参数后的普通类型,如List<Integer>在擦除之后的rawType是List。type代表完整的类型信息,可以是Class或ParameterizedType。

2.1、非范型的情况

    为了代表非范型类,TypeLiteral使用内联的SimpleTypeLiteral:

public abstract class TypeLiteral<T> {

  @SuppressWarnings("unchecked")
  TypeLiteral(Type type) {
    this.rawType = (Class<? super T>) getRawType(nonNull(type, "type"));
    this.type = type;
    this.hashCode = hashCode(type);
  }

  private static class SimpleTypeLiteral<T> extends TypeLiteral<T> {
    public SimpleTypeLiteral(Type type) {
      super(type);
    }
  }

  ...
}

    可以通过TypeLiteral.get(...)工厂方法得到普通类的TypeLiteral:

  public static <T> TypeLiteral<T> get(Class<T> type) {
    return new SimpleTypeLiteral<T>(type);
  }

2.2、范型类的TypeLiteral   

    为了让TypeLiteral在运行时得到范型类的模板参数信息,必须采用如下特殊的方法:

 

public class StringListTypeLiteral extends TypeLiteral<List<String>>{
}

public abstract class TypeLiteral<T> {

  @SuppressWarnings("unchecked")
  protected TypeLiteral() {
    this.type = getSuperclassTypeParameter(getClass());
    this.rawType = (Class<? super T>) getRawType(type);
    this.hashCode = hashCode(type);
  }

  ...
}

    StringListTypeLiteral初始化时调用TypeLiteral的默认constructor,它可以获得继承时TypeLiteral<T>中模板参数T(例子中是List<String>)的信息。实现中是通过使用范型反射的方法:

public abstract class TypeLiteral<T> {

  static Type getSuperclassTypeParameter(Class<?> subclass) {
    Type superclass = subclass.getGenericSuperclass();
    if (superclass instanceof Class) {
      throw new RuntimeException("Missing type parameter.");
    }
    // Java5中新引入的一种针对范型的反射语法,可以得到继承时父类的模板参数信息
    // 在Hibernate的Generic DAO中也有用到,是一个获得模板参数信息的特殊方法
    return ((ParameterizedType)superclass).getActualTypeArguments()[0];
  }


  @SuppressWarnings({ "unchecked" })
  private static Class<?> getRawType(Type type) {
    if (type instanceof Class<?>) {
      // 是非范型类      
      return (Class<?>) type;
    }
    else {
      if (type instanceof ParameterizedType) {
        ParameterizedType parameterizedType = (ParameterizedType) type;

        Type rawType = parameterizedType.getRawType();
        if (!(rawType instanceof Class<?>)) {
          throw unexpectedType(rawType, Class.class);
        }
        return (Class<?>) rawType;
      }

      if (type instanceof GenericArrayType) {
        return Object[].class;
      }

      throw unexpectedType(type, ParameterizedType.class);
    }
  } 
  ...
}

    针对StringListTypeLiteral,getSuperclassTypeParameter(..)方法返回的是代表List<String>的ParameterizedType。再对得到的type调用getRawType(..)得到Class<List>。

2.3、类型相等的判定

    当用TypeLiteral取代Class作为Type Tokens时,还需要解决如何判定两个类型相等的问题,自然通过重载equals(..)方法:

public abstract class TypeLiteral<T> {

  public boolean equals(Object o) {
    if (o == this) {
      return true;
    }
    if (!(o instanceof TypeLiteral<?>)) {
      return false;
    }
    TypeLiteral<?> other = (TypeLiteral<?>) o;

    return equals(type, other.type);
  }

  static boolean equals(Type a, Type b) {
    if (a instanceof Class) {
      // 非范型类
      return a.equals(b);
    }

    // 针对范型类,可能存在嵌套的模板参数,如List<Map<Integer,List<Double>>>
    //故需要递归调用
    if (a instanceof ParameterizedType) {
      if (!(b instanceof ParameterizedType)) {
        return false;
      }

      ParameterizedType pa = (ParameterizedType) a;
      ParameterizedType pb = (ParameterizedType) b;

      // 擦除后类型比较
      if (!pa.getRawType().equals(pb.getRawType())) {
        return false;
      }

      Type[] aa = pa.getActualTypeArguments();
      Type[] ba = pb.getActualTypeArguments();
      if (aa.length != ba.length) {
        return false;
      }

      for (int i = 0; i < aa.length; i++) {
        // 递归调用
        if (!equals(aa[i], ba[i])) {
          return false;
        }
      }

      return true;
    }

    ...
    return false;
  }

2.4、范型绑定问题的解决

    为了区别List<Integer>和List<String>的绑定,我们需要使用TypeLiteral。简洁的使用方法是匿名类:

public class TypeLiteralModule extends AbstractModule { 
    protected void configure() { 
        bind(new TypeLiteral<List<String>>(){}) 
            .annotatedWith(Names.named("list")) 
            .to(new TypeLiteral<ArrayList<String>>(){}); 

        bind(new TypeLiteral<List<Integer>>(){}) 
            .annotatedWith(Names.named("list")) 
            .to(new TypeLiteral<ArrayList<Integer>>(){}); 
    } 
}

三、Key类

    在Guice的Injector中为了唯一确定一个绑定信息,需要一个绑定类型(一般为一个Interface的Class)和一个可选的Annotation。Key类就是将两者封装作为一个完整的键值,用于在Injector内部的Map中存取绑定信息。

public abstract class Key<T> {

  final AnnotationStrategy annotationStrategy;
  final TypeLiteral<T> typeLiteral;
  final int hashCode;
  
  ...
}

    AnnotationStrategy是一个内联接口,它代表一个Annotation;TypeLiteral是绑定类型。Key也是一个抽象类,为了得到它的实例仍然需要通过get(..)工厂方法。Key中一个SimpleKey内联类是Key的简单实现。

public abstract class Key<T> {

  @SuppressWarnings("unchecked")
  private Key(Type type, AnnotationStrategy annotationStrategy) {
    this.annotationStrategy = annotationStrategy;
    this.typeLiteral = (TypeLiteral<T>) TypeLiteral.get(type);
    this.hashCode = computeHashCode();
  }

  private static class SimpleKey<T> extends Key<T> {

    private SimpleKey(Type type, AnnotationStrategy annotationStrategy) {
      super(type, annotationStrategy);
    }

    ...
  }

  ...
}

    一个简单工厂方法的实现:

  public static <T> 
  Key<T> get(Class<T> type,
      Class<? extends Annotation> annotationType) {
    return new SimpleKey<T>(type, strategyFor(annotationType));
  }

    作为键值最关键的两个方法:equals和hashCode的实现也很直接:

public abstract class Key<T> {

  public boolean equals(Object o) {
    if (o == this) {
      return true;
    }
    if (!(o instanceof Key<?>)) {
      return false;
    }
    Key<?> other = (Key<?>) o;
    //  绑定类型和注释完全相等
    return annotationStrategy.equals(other.annotationStrategy)
        && typeLiteral.equals(other.typeLiteral);
  }

  private int computeHashCode() {
    return typeLiteral.hashCode() * 31 + annotationStrategy.hashCode();
  }

  ...

 

分享到:
评论

相关推荐

    google guice 3.0源码

    google guice 3.0源码,官方下载,帮助你更好理解google guice实现的原理

    Google guice

    NULL 博文链接:https://m635674608.iteye.com/blog/2090042

    guice.jar/guice.jar

    guice.jar guice.jar guice.jar guice.jar guice.jar guice.jar guice.jar

    guice-4.0-API文档-中文版.zip

    赠送源代码:guice-4.0-sources.jar; 赠送Maven依赖信息文件:guice-4.0.pom; 包含翻译后的API文档:guice-4.0-javadoc-API文档-中文(简体)版.zip; Maven坐标:com.google.inject:guice:4.0; 标签:google、...

    guice-assistedinject-3.0-API文档-中英对照版.zip

    赠送源代码:guice-assistedinject-3.0-sources.jar; 赠送Maven依赖信息文件:guice-assistedinject-3.0.pom; 包含翻译后的API文档:guice-assistedinject-3.0-javadoc-API文档-中文(简体)-英语-对照版.zip; ...

    guice-3.0-API文档-中英对照版.zip

    赠送源代码:guice-3.0-sources.jar; 赠送Maven依赖信息文件:guice-3.0.pom; 包含翻译后的API文档:guice-3.0-javadoc-API文档-中文(简体)-英语-对照版.zip; Maven坐标:com.google.inject:guice:3.0; 标签:...

    guice-multibindings-3.0-API文档-中文版.zip

    赠送源代码:guice-multibindings-3.0-sources.jar; 赠送Maven依赖信息文件:guice-multibindings-3.0.pom; 包含翻译后的API文档:guice-multibindings-3.0-javadoc-API文档-中文(简体)版.zip; Maven坐标:...

    guice-3.0-API文档-中文版.zip

    赠送源代码:guice-3.0-sources.jar; 赠送Maven依赖信息文件:guice-3.0.pom; 包含翻译后的API文档:guice-3.0-javadoc-API文档-中文(简体)版.zip; Maven坐标:com.google.inject:guice:3.0; 标签:google、...

    druid 源码分析 逐层详解

    druid源代码解读 构架设计 分布式构建 设计模式 依赖注入等

    google guice基础例子

    Guice是Google开发的一个轻量级,基于Java5(主要运用泛型与注释特性)的依赖注入框架(IOC)。Guice非常小而且快。Guice是类型安全的,它能够对构造函数,属性,方法(包含任意个参数的任意方法,而不仅仅是setter...

    guice入门学习资料

    guice 学习资料,快速掌握guice的编程技巧以及了解其机制。

    guice-multibindings-3.0-API文档-中英对照版.zip

    赠送源代码:guice-multibindings-3.0-sources.jar; 赠送Maven依赖信息文件:guice-multibindings-3.0.pom; 包含翻译后的API文档:guice-multibindings-3.0-javadoc-API文档-中文(简体)-英语-对照版.zip; Maven...

    Google Guice: Agile Lightweight Dependency Injection Framework

    * What the future has in store, including Guice IDE, the next Guice version and the standardization of Guice's concepts through JSR 299. * How you can build real world, Guice-powered web ...

    Guice用户中文指南

    Guice用户中文指南,Guice (读作"juice")是超轻量级的,下一代的,为Java 5及后续版本设计的依赖注入容器

    Guice_1.0_Manual.pdf

    Guice开发手册, Guice中文开发手册

    guice-4.0-API文档-中英对照版.zip

    赠送源代码:guice-4.0-sources.jar; 赠送Maven依赖信息文件:guice-4.0.pom; 包含翻译后的API文档:guice-4.0-javadoc-API文档-中文(简体)-英语-对照版.zip; Maven坐标:com.google.inject:guice:4.0; 标签:...

    mybatis-guice-3.6.zip

    是一个基于Java的持久层框架。iBATIS提供的持久层框架包括SQL Maps和Data Access Objects(DAO)

    struts2 整合guice

    把struts2和guice整合起来的一个例子。

    guice-2.0.jar

    guice-2.0.jar guice-2.0.jar

Global site tag (gtag.js) - Google Analytics