Guice中如何跨模块动态收集对象并生成全局单例ThingyService
解决方案
核心思路:直接使用Guice原生的Multibinder机制即可满足需求,它天生支持跨多个模块贡献同类型元素,自动合并为全局唯一的Set注入给依赖方,无需自己维护静态共享状态。
前置依赖确认
如果使用的Guice版本低于4.0,需要引入guice-multibindings扩展依赖;4.0及以上版本Multibinder已内置在核心库中,无需额外引入。
修改后的实现代码
import com.google.inject.AbstractModule; import com.google.inject.Provides; import com.google.inject.Singleton; import com.google.inject.multibindings.Multibinder; import java.util.Set; class ThingyModule extends AbstractModule{ final Set<Class<?>> myThingyClasses; // 保留原有构造方法逻辑,接收类列表赋值给myThingyClasses public ThingyModule(Set<Class<?>> myThingyClasses) { this.myThingyClasses = myThingyClasses; } private Set<Thingy> extractThingiesFromThingyClasses(){ // 原有提取逻辑保持不变 } @Provides @Singleton ThingyService thingyService(Set<Thingy> thingys){ // Guice会自动注入所有模块贡献的全量Thingy实例 return new ThingyService(thingys); } @Override protected void configure(){ // 声明当前模块要贡献元素到全局的Thingy类型Set中 Multibinder<Thingy> thingyBinder = Multibinder.newSetBinder(binder(), Thingy.class); extractThingiesFromThingyClasses().forEach(thingy -> // 直接绑定已创建好的实例,Guice不会托管这些Thingy的生命周期,符合你的要求 thingyBinder.addBinding().toInstance(thingy) ); } }
使用说明
- 各团队只需要在自己的业务模块中,实例化
ThingyModule并传入本团队维护的Thingy类列表,安装到当前Guice上下文即可 - Guice初始化时会自动合并所有
ThingyModule贡献的Thingy实例,全局只会创建一个ThingyService单例 - 不同Injector(比如测试环境和生产环境、不同测试用例之间)的
Thingy集合和ThingyService完全隔离,不会出现串数据的问题 - 该Java实现的模块可直接在Play/Scala技术栈中使用,和Play原生的Guice集成完全兼容
注意事项
- 确认所有业务模块的
ThingyModule都被传入到最终创建Injector的模块列表中,避免遗漏注册 ThingyService的@Singleton注解需使用com.google.inject.Singleton,不要和其他框架的单例注解混用
内容的提问来源于stack exchange,提问作者Sean Patrick Floyd
相关产品推荐
相关产品推荐

