创建Guice参数化单例:TypeLiteral绑定代码能否正确注入单例?
核心结论
你当前编写的代码可以完全实现预期目标,能够正确将Guice实例化的SomeClass<String>单例对象注入到GuiceInstantiatedClass中。
具体生效逻辑
- Guice的泛型绑定以携带完整泛型信息的类型标识作为匹配键,你在
ServiceModule中通过匿名子类继承TypeLiteral保存的SomeClass<String>类型信息,和GuiceInstantiatedClass构造器注入点声明的SomeClass<String>类型标识完全严格匹配,不存在Java泛型擦除导致的匹配失效问题。 - 绑定语句后调用的
asEagerSingleton()会为当前绑定关系启用单例作用域:Guice启动阶段就会完成SomeClass<String>的实例化,整个应用生命周期内只会创建一个该类型的实例,所有引用该绑定的注入点拿到的都是同一个对象,完全符合“由Guice完成实例化、不手动new、全局单例”的要求。 - 只要
SomeClass提供无参构造器,或是构造器上标注了@Inject注解,Guice就能自动完成实例化逻辑,不需要额外编写手动创建对象的代码。
调整代码时的常见误区
后续改动时注意避开这些会直接导致功能失效的写法:
- 不要把泛型绑定替换为裸类型绑定:比如写成
bind(SomeClass.class).asEagerSingleton(),这种写法的绑定键是不带泛型信息的裸SomeClass类型,和注入点带泛型的SomeClass<String>键不匹配,应用启动时会直接抛出找不到对应绑定的异常。 - 不需要刻意在
SomeClass类上加@Singleton注解:当前绑定的单例作用域是由模块中的绑定语句声明的,类上的注解不会改变这个绑定的属性;哪怕你在类上加了@Singleton,只要不通过TypeLiteral完成泛型绑定,依然无法匹配带泛型参数的注入点。 - 不要丢失
TypeLiteral的泛型参数信息:比如把绑定写成new TypeLiteral<SomeClass>() {},这种写法和裸类型绑定逻辑一致,依然无法匹配带泛型的注入点。
内容的提问来源于stack exchange,提问作者strawbee
相关产品推荐
相关产品推荐

