Dependency injection 使用Guice的实例方法

Dependency injection 使用Guice的实例方法,dependency-injection,instance,guice,Dependency Injection,Instance,Guice,我希望其中一个组件有一个带有Guice的静态实例方法(非托管bean应该能够访问这个类)。我创造了这样的东西: public class LookupService { @Inject private static Provider<Injector> injector = null; private final ILookup<IWS> lookup; @Inject public LookupService(ILookup<I

我希望其中一个组件有一个带有Guice的静态实例方法(非托管bean应该能够访问这个类)。我创造了这样的东西:

public class LookupService {

   @Inject
   private static Provider<Injector> injector = null;

   private final ILookup<IWS> lookup;

   @Inject
   public LookupService(ILookup<IWS> lookup) {
      this.lookup = lookup;
   }

   public static LookupService instance() {
     return injector.get().getInstance(LookupService.class);
   }

   public <T extends IWS> T lookup(Class<T> localInterface) {
      return lookup.lookup(localInterface);
   }
公共类查找服务{
@注入
私有静态提供者注入器=null;
私有最终ILookup查找;
@注入
公共查找服务(ILookup查找){
this.lookup=查找;
}
公共静态LookupService实例(){
返回injector.get().getInstance(LookupService.class);
}
公共T查找(类localInterface){
返回lookup.lookup(localInterface);
}
}


你觉得这个设计怎么样?这方面还有其他想法吗?(从非托管对象访问托管bean)

基本上,您正在寻找的模式称为“请求静态注入”,并且有一个。一旦你把它写下来,你的代码看起来很像

public类MainModule扩展了AbstractModule{
@重写公共void configure(){
requestStaticInjection(LookupService.class);
}
}
公共类查找服务{
/**这将在创建喷油器后立即设置*/
@注入
静态提供程序=null;
私有最终ILookup查找;
@注入
公共查找服务(ILookup查找){
this.lookup=查找;
}
公共静态LookupService实例(){
返回provider.get();
}
公共T查找(类localInterface){
返回lookup.lookup(localInterface);
}
}
请注意:

  • 虽然您仍然可以将字段设置为
    private
    ,但请记住,这意味着您无法在测试中(或在将来的非Guice使用中)在没有Guice的private field access magic的情况下设置它。当使用注入字段时,我们通常将其打包为私有字段,然后将测试放在同一个包中

  • 静态注入通常被视为只有在迁移到Guice时,或者当您使用无法更改的其他代码时才需要认可的东西。在可能的情况下,尽量避免全局状态——即使这意味着只生成
    FooBean
    数据并创建一个注入的
    FooBeanService

  • 即使您可以在任何需要的地方注入
    注入器
    ,但如果您只注入
    提供程序
    ,您可能会发现测试更容易。只有在运行时之前不知道需要什么类型的注入器时,才能注入
    Injector
    ——例如,如果使用
    Injector
    通过将类文本传递给注入器以获取实例来实现
    LookupService.lookup(…)

  • 事实上,从这里很难说,但是
    ILookup
    的行为似乎很像,它解决了Guice通过依赖项注入解决的确切类型的问题!如果是这种情况,您最好重写ILookup以使用Guice:只需删除对
    LookupService.instance().lookup(Foo.class)
    的调用,而是创建一对匹配的
    @Inject static Provider fooProvider
    requestStaticInjection(FooUser.class)


希望有帮助

谢谢你的评论!我有类似于您在第二点(旧代码库)中描述的情况。随着时间的推移,我将尝试迁移到非静态方法。使用这种方法进行测试并不是很糟糕,但需要将Guice集成到测试框架中。然后,当您想测试类调用
LookupService.instance()
时,您需要在测试开始时为其绑定模拟实现。@sol25请记住,基于Guice的系统测试很好,但您可能会发现单元测试也非常有用,特别是使用模拟LookupService的bean测试。放松静态字段可见性可能会让您在大多数测试中完全跳过Guice。
public class MainModule extends AbstractModule {
  @Override public void configure() {
    requestStaticInjection(LookupService.class);
  }
}

public class LookupService {

  /** This will be set as soon as the injector is created. */
  @Inject
  static Provider<LookupService> provider = null;

  private final ILookup<IWS> lookup;

  @Inject
  public LookupService(ILookup<IWS> lookup) {
    this.lookup = lookup;
  }

  public static LookupService instance() {
    return provider.get();
  }

  public <T extends IWS> T lookup(Class<T> localInterface) {
    return lookup.lookup(localInterface);
  }
}