如何在Java Guice中处理带自身依赖的可注入类
问题根源
- ClassA构造器参数未标记
@Assisted:ClassA的int number没有用@Assisted注解,Guice无法区分这个参数是工厂传入的动态值还是自身绑定的常量,导致参数传递混乱。 - 手动实例与自动注入冲突:你手动创建了
ClassB和ClassA实例,但ClassC构造器中的ClassA是Guice自动注入的新实例,而非你手动创建的对象,最终导致所有动态参数被错误复用。
正确整合方案
根据你的使用场景,需要明确:动态参数用@Assisted标记,外部手动创建的依赖通过工厂方法传递,而非依赖Guice自动注入。
步骤1:修正类的注解与构造器
- ClassA:给
int number和ClassB都添加@Assisted,明确二者均为外部传入
public class ClassA { private final int number; private final ClassB classB; @Inject public ClassA(@Assisted int number, @Assisted ClassB classB) { this.number = number; this.classB = classB; } public String message() { return "ClassA number: " + number + ", ClassB number: " + classB.getNumber(); } }
- ClassB:保持原有
@Assisted注解不变
@Getter public class ClassB { private final int number; @Inject public ClassB(@Assisted int number) { this.number = number; } }
- ClassC:给
ClassA添加@Assisted,明确该实例由外部传入
public class ClassC { final private int number; final private ClassA classA; @Inject public ClassC(@Assisted int number, @Assisted ClassA classA) { this.number = number; this.classA = classA; } public String message() { String message = classA.message(); return message + ", ClassC number: " + number; } }
步骤2:修正工厂接口
工厂方法参数需与构造器中@Assisted标记的参数一一对应:
// ClassAFactory public interface ClassAFactory { ClassA create(int number, ClassB classB); } // ClassBFactory public interface ClassBFactory { ClassB create(int number); } // ClassCFactory public interface ClassCFactory { ClassC create(int number, ClassA classA); }
步骤3:修正使用代码
通过工厂传递手动创建的实例,避免Guice自动生成新对象:
Injector injector = Guice.createInjector(new AppModule()); // 创建ClassB实例 ClassBFactory bFactory = injector.getInstance(ClassBFactory.class); ClassB b = bFactory.create(2); // 传入ClassB实例创建ClassA ClassAFactory aFactory = injector.getInstance(ClassAFactory.class); ClassA a = aFactory.create(1, b); // 传入ClassA实例创建ClassC ClassCFactory cFactory = injector.getInstance(ClassCFactory.class); ClassC c = cFactory.create(3, a); System.out.println(c.message());
此时输出结果为:ClassA number: 1, ClassB number: 2, ClassC number: 3,符合预期。
用Provider替代工厂的示例
Guice的Provider适合自定义实例初始化逻辑,结合AssistedInject可处理动态参数场景。
示例:用Provider创建ClassA
- 定义ClassA的Provider:
public class ClassAProvider implements Provider<ClassA> { private final int number; private final ClassB classB; // 动态参数用@Assisted标记,固定依赖由Guice注入 @Inject public ClassAProvider(@Assisted int number, ClassB classB) { this.number = number; this.classB = classB; } @Override public ClassA get() { // 可在此添加自定义初始化逻辑(如参数校验、额外配置) return new ClassA(number, classB); } }
- 定义Provider的工厂接口:
public interface ClassAProviderFactory { ClassAProvider create(int number); }
- 在模块中配置:
install(new FactoryModuleBuilder().build(ClassAProviderFactory.class)); // 绑定固定参数的ClassB实例 bind(ClassB.class).toInstance(new ClassB(2));
- 使用方式:
Injector injector = Guice.createInjector(new AppModule()); ClassAProviderFactory providerFactory = injector.getInstance(ClassAProviderFactory.class); ClassAProvider provider = providerFactory.create(1); ClassA a = provider.get();
注意:如果所有依赖都是动态参数,直接使用AssistedInject工厂更简洁;Provider更适合需要复用初始化逻辑、或部分依赖为Guice绑定常量的场景。
内容的提问来源于stack exchange,提问作者WitHeld
相关产品推荐
相关产品推荐

