使用Guice将参数传递给构造函数

Dar*_*der 32 java dependency-injection guice

我有一个工厂如下,

public final class Application {

    private static IFoo foo;

    public static IFoo getFoo(String bar)
    {
        // i need to inject bar to the constructor of Foo
        // obvious i have to do something, not sure what
        Injector injector = Guice.createInjector();
        logger = injector.getInstance(Foo.class);
        return logger;              
    }

}
Run Code Online (Sandbox Code Playgroud)

这是Foo的定义:

class Foo
{
   Foo(String bar)
   {

   }

}
Run Code Online (Sandbox Code Playgroud)

好.我不知道如何使用Guice将此参数传递给Foo构造函数?

有任何想法吗?

Dou*_*ugA 56

所有"Guice构造函数参数"的答案在某些方面似乎都是不完整的.这是一个完整的解决方案,包括用法:

interface FooInterface{
  String getFooName();
}
Run Code Online (Sandbox Code Playgroud)

//在实现类上注释构造函数和辅助参数

class Foo implements FooInterface {
   String bar;

   @Inject
   Foo(@Assisted String bar)
   {
      this.bar = bar;
   }

   // return the final name
   getFooName(){
     return this.bar;
   }

}
Run Code Online (Sandbox Code Playgroud)

//使用create()方法创建工厂接口,该方法仅接受辅助参数.// FooFactory接口没有显式的实现类(Guice Magic)

interface FooFactory{
   Foo create(String bar);
}
Run Code Online (Sandbox Code Playgroud)

//将该工厂绑定到AssistedInject创建的提供程序

binderModule implements Module{

 void configure(Binder binder) {
   binder.install(new FactoryModuleBuilder()
         .implement(FooInterface.class, Foo.class)
         .build(FooFactory.class));
 }
}
Run Code Online (Sandbox Code Playgroud)

//现在使用它:

class FooAction{

   @Inject private FooFactory fooFactory;

   doFoo(){
      // Send bar details through the Factory, not the "injector" 
      Foo f = fooFactory.create("This foo is named bar. How lovely!");
      f.getFooName(); // "This foo is named bar. How lovely!"
   }
}
Run Code Online (Sandbox Code Playgroud)

大量的帮助这里:https://google.github.io/guice/api-docs/latest/javadoc/index.html?com/google/inject/assistedinject/FactoryModuleBuilder.html


Dav*_*nts 8

您可能正在寻找的是使用Guice工厂.AssistedInject功能特别简单,但它们在页面顶部有一个手动示例.手动示例的缺点是,您可以在非静态getFoo方法下获得工厂,您可以将任何参数传递给您需要的工具,并从那里构建对象.

如果你有方法拦截,这将无法直接工作Foo,但它将在许多其他情况下工作.

要使用AssistedInject,对我来说有一些更清晰的语义并且意味着更少的手动布线,你需要在类路径中使用guice-assistedinject扩展,然后在创建时Foo(好吧FooImpl,我们应该使用接口):

@Inject
public FooImpl(@Assisted String bar)
{
    this.baz = bar;
}
Run Code Online (Sandbox Code Playgroud)

然后你创建一个FooFactory接口:

public interface FooFactory {
    public Foo create(String bar);
}
Run Code Online (Sandbox Code Playgroud)

然后在你的guice模块中:

install(new FactoryModuleBuilder()
    .implement(Foo.class, FooImpl.class)
    .build(FooFactory.class));
Run Code Online (Sandbox Code Playgroud)

您可以查看javadoc以FactoryModuleBuilder获取更复杂工厂的示例.


小智 7

我知道这是旧线程但我今天自己就是这个问题.我只需要两个或最多三个不同的'Foo'实例,我真的不想写出Factory的所有bolierplate代码.通过一点谷歌搜索我找到了这个Stubbisms - 托尼的博客我建议这个解决方案,如果你确切知道你需要什么实例,这是完美的.

在Guice模块中:

    bind(Foo.class).annotatedWith(Names.named("firstFoo")).toProvider(new Provider<Foo>() {
        @Override
        public Foo get() {
            return new FooImpl("topic A");
        }
    });
    bind(Foo.class).annotatedWith(Names.named("secondFoo")).toProvider(new Provider<Foo>() {
        @Override
        public Foo get() {
            return new FooImpl("topic B");
        }
    });
Run Code Online (Sandbox Code Playgroud)

或者在java 8中:

    bind(Foo.class).annotatedWith(Names.named("firstFoo")).toProvider(() -> new FooImpl("first"));
    bind(Foo.class).annotatedWith(Names.named("secondFoo")).toProvider(() -> new FooImpl("second"));
Run Code Online (Sandbox Code Playgroud)

在您需要Foo实例的服务的构造函数中:

@Inject
public MyService (
    @Named("firstFoo") Foo firstFoo,
    @Named("secondFoo") Foo secondFoo) {
}
Run Code Online (Sandbox Code Playgroud)

在我的情况下和Foo:

public class FooImpl implements Foo {

    private String name;

    public FooImpl(String name) {
        this.name = name;
    }

    @Override
    public String getName() {
        return name;
    }
}
Run Code Online (Sandbox Code Playgroud)

希望它可以帮助某人.