Guice+Dropwizard字段注入失效但构造器注入正常问题咨询
Guice+Dropwizard测试字段注入失败问题说明
问题复现代码
初始字段注入测试类
class SomeTest { companion object { @RegisterExtension @JvmField val app = TestGuiceyAppExtension.forApp(MyServer::class.java) .config(configFileName).hooks(GuiceyConfigurationHook { builder(it) }).create() } @Inject @Named("something") private lateinit var someClass: SomeClass }
依赖类定义
SomeClass未标注任何构造器注入注解:
class SomeClass(firstClass: FirstClass, secondClass: SecondClass) { }
绑定配置
在自定义DropwizardAwareModule中通过@Provides方法提供带命名限定的实例:
@Provides @Named("something") fun getSomeClass(firstClass: FirstClass, secondClass: SecondClass): SomeClass { return SomeClass(firstClass, secondClass) }
异常表现
- 运行字段注入版本的测试时抛出错误:提示
SomeClass既不存在无参构造器,也不存在标注@Inject注解的构造器 - 将注入方式修改为测试类构造器注入后,功能完全正常,可成功拿到
@Provides方法生成的实例,正常代码如下:
class SomeTest @Inject constructor(@Named("something") someClass: SomeClass) { }
问题根因
该现象既不是测试类存在特殊注入限制,也和@Provides方法生成实例的可变性无关,核心原因是两种注入方式下Guice接管测试实例的生命周期节点完全不同:
- 构造器注入场景下,JUnit 5识别到测试类构造器上的
@Inject注解后,会直接把测试类的实例化权完全交给Guice容器。Guice在创建测试类实例的过程中会完整遍历所有依赖绑定规则,精准匹配到@Named("something")对应的@Provides方法,直接拿到方法返回的预构造SomeClass对象,全程不会尝试自行反射创建SomeClass实例,自然不会触发构造器合法性校验,也就不会报错。 - 字段注入场景下,JUnit会先调用测试类的无参构造器自行创建好测试实例,之后Guicey扩展才会对已经存在的测试实例做后置字段注入。这个阶段受Kotlin字段注解的作用域规则、Guicey扩展的字段扫描逻辑影响,字段上的
@Named("something")限定符没有被正确识别,Guice没有匹配到预先定义的@Provides绑定,转而走默认的即时绑定逻辑尝试自行反射构造SomeClass实例,最终因为找不到无参构造或@Inject标注的构造器抛出错误。
补充说明:Kotlin的
lateinit修饰符仅在编译期做非空校验,生成的JVM字段是普通可变字段,完全满足Guice字段注入的要求,不存在不可变对象无法字段注入的限制。
内容的提问来源于stack exchange,提问作者Guy Erez
相关产品推荐
相关产品推荐

