一、简介
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实现的原理
NULL 博文链接:https://m635674608.iteye.com/blog/2090042
guice.jar guice.jar guice.jar guice.jar guice.jar guice.jar guice.jar
赠送源代码: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-sources.jar; 赠送Maven依赖信息文件:guice-assistedinject-3.0.pom; 包含翻译后的API文档:guice-assistedinject-3.0-javadoc-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-sources.jar; 赠送Maven依赖信息文件:guice-multibindings-3.0.pom; 包含翻译后的API文档:guice-multibindings-3.0-javadoc-API文档-中文(简体)版.zip; Maven坐标:...
赠送源代码: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源代码解读 构架设计 分布式构建 设计模式 依赖注入等
Guice是Google开发的一个轻量级,基于Java5(主要运用泛型与注释特性)的依赖注入框架(IOC)。Guice非常小而且快。Guice是类型安全的,它能够对构造函数,属性,方法(包含任意个参数的任意方法,而不仅仅是setter...
guice 学习资料,快速掌握guice的编程技巧以及了解其机制。
赠送源代码:guice-multibindings-3.0-sources.jar; 赠送Maven依赖信息文件:guice-multibindings-3.0.pom; 包含翻译后的API文档:guice-multibindings-3.0-javadoc-API文档-中文(简体)-英语-对照版.zip; Maven...
* 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 (读作"juice")是超轻量级的,下一代的,为Java 5及后续版本设计的依赖注入容器
Guice开发手册, Guice中文开发手册
赠送源代码:guice-4.0-sources.jar; 赠送Maven依赖信息文件:guice-4.0.pom; 包含翻译后的API文档:guice-4.0-javadoc-API文档-中文(简体)-英语-对照版.zip; Maven坐标:com.google.inject:guice:4.0; 标签:...
是一个基于Java的持久层框架。iBATIS提供的持久层框架包括SQL Maps和Data Access Objects(DAO)
把struts2和guice整合起来的一个例子。
guice-2.0.jar guice-2.0.jar