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();
  }

  ...

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值