使用Guice向构造函数传递参数

42

我有一个如下所示的工厂:

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;              
    }

}

这是Foo的定义:

class Foo
{
   Foo(String bar)
   {

   }

}

好的,我不确定如何使用Guice将此参数传递给Foo构造函数?

有什么想法吗?

6个回答

68

所有关于“Guice构造函数参数”的答案似乎都在某种程度上不完整。以下是一个完整的解决方案,包括用法和示意图:

enter image description here

interface FooInterface {
    String getFooName();
}

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

class Foo implements FooInterface {
    String bar;

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

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

}

// 创建一个工厂接口,其中包含一个只接受辅助参数的create()方法。

// FooFactory接口没有明确的实现类(Guice魔法)

interface FooFactory {
    Foo create(String bar);
}

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

class BinderModule implements Module {

    public void configure(Binder binder) {
        binder.install(new FactoryModuleBuilder()
                .implement(FooInterface.class, Foo.class)
                .build(FooFactory.class));
    }
}

//现在使用它:

class FooAction {
    @Inject private FooFactory fooFactory;

    public String doFoo() {
        // Send bar details through the Factory, not the "injector"
        Foo f = fooFactory.create("This foo is named bar. How lovely!");
        return f.getFooName(); // "This foo is named bar. How lovely!"
    }
}

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


对我不起作用。我有一个NullPointerException,因为Foo构造函数从未被调用。可能你需要在某个地方使用你的Module - Vitalii Korsakov
1
请修复“create”方法(FooFactory接口)的缺失返回类型。它应该是:Foo create(String bar); - frhack

11
你可能正在寻找的是使用Guice工厂。特别是使用AssistedInject功能非常容易,但是他们在页面顶部提供了一个手动示例。 手动示例的要点是,在非静态getFoo方法下获取工厂,将需要的任何参数传递给该方法,并从那里构建对象。
如果Foo中有方法拦截,这种方法将无法直接运行,但在许多其他情况下可以使用。
要使用AssistedInject,它的语义更加清晰,意味着较少的手动连接,您需要在类路径中添加guice-assistedinject扩展名,然后创建Foo(好吧,应该使用接口FooImpl):
@Inject
public FooImpl(@Assisted String bar)
{
    this.baz = bar;
}

然后您需要创建一个FooFactory接口:
public interface FooFactory {
    public Foo create(String bar);
}

然后在您的guice模块中:
install(new FactoryModuleBuilder()
    .implement(Foo.class, FooImpl.class)
    .build(FooFactory.class));

你可以查看FactoryModuleBuilder的javadoc,了解更复杂工厂的示例。

是的,很糟糕,它太复杂了,StructureMap比Guice更加灵活。 - DarthVader
我在哪里可以下载Java的StructureMap? - mark

10

我知道这是一个旧帖子,但我今天遇到了同样的问题。我只需要两个或最多三个不同的'Foo'实例,我真的不想编写Factory的所有样板代码。通过一点搜索,我发现了这篇博客文章,我建议使用这种解决方案,如果你确切地知道你需要哪些实例,那么它是完美的。

在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");
        }
    });

或者在Java 8中:

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

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

@Inject
public MyService (
    @Named("firstFoo") Foo firstFoo,
    @Named("secondFoo") Foo secondFoo) {
}

在我的情况下,Foo 是:

public class FooImpl implements Foo {

    private String name;

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

    @Override
    public String getName() {
        return name;
    }
}

希望能对某人有所帮助。


2
如果这个类是一个工厂,那么它应该是一个由Guice管理的对象,具有一个非静态的getFoo方法,而getFoo方法只需要使用。
new Foo(bar)

并非每个类都需要由Guice实例化。

另外,请参见AssistedInject,以避免自己创建工厂并让Guice为您创建一个工厂。


0
虽然这不是对你所问的问题的直接回答,但希望能有所帮助。我之前试图理解构造函数参数是在哪里传递的。如果它们是自定义类,应该在模块中进行绑定。
Class CustomHandler {

  private Config config;

  @Inject
  CustomHandler(Config config) {
    this.config = config;
  }

  public void handle() {
    // handle using config here
  }
}

绑定:

class Module extends AbstractModule {
  bind(Handler.class).to(CustomHandler.class);
  bind(Config.class).to(CustomConfig.class);
}

注入:

CustomHandler handler = injector.getInstance(CustomHandler.class);
handler.handle();

0
这是我们最终采取的解决方案。这是一个不好的解决方案,只有在没有时间且只想活下来看到另一天时才应该使用。
1. 删除所有构造函数,使类具有默认构造能力。 2. 添加一个名为“init”(或类似)的公共方法,该方法以参数形式接受依赖项并将它们分配给字段。 3. 使用Guice的“Injector.getInstance()”来进行类的发现和构造,然后使用实际需要的字段调用“init”方法。
通过进行一些积极的空值检查,并通过抛出适当形式的“IllegalStateException”来通知不知情的调用者需要调用“init”,可以获得一些原谅。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接