我可以使用Guice在方法中获取实例吗?

时间:2013-07-30 18:45:22

标签: java dependency-injection guice

我刚开始使用Guice,所以我的理解可能完全错误。

我有一个界面Foo和一个实施FooImp

我在我的模块中使用了以下代码来注入它:

bind(Foo.class).annotatedWith("Foo").toInstance(foo);  // foo is an instance of FooImp

然后我现在想在我的代码中,名称注释为“Foo”的Foo实例将被foo替换?

@Named("Foo")
Foo fooInst;   // fooInst will be foo at runtime?

如果我是对的,我怎么能做到这一点:

public Foo doSomething() {  // for some reason there must be no arguments
    @Named("Foo")
    Foo fooInst;   // injecting here seems not allowed...?
    fooInst.do();
}

3 个答案:

答案 0 :(得分:3)

你所假设的并不完全正确:Guice用于依赖注入,这意味着你可以将一些接口/类注入到另一个类的构造函数中。

假设您有一个界面Foo,它的实现FooImpl。然后你还有一个类Bar,它取决于Foo的实现。

public class Bar {

    private Foo foo;

    @Inject
    public Bar(@Named("foo") Foo foo) {
        this.foo = foo;
    }

    //some other methods
}

在你的Guice模块中你必须写

bind(Foo.class).annotatedWith(Names.named("Foo")).toInstance(foo);
//let's say this is part of the module MyModule extends AbstractModule

设置完成后,您可以使用Guice的Injector - 类创建一个主方法来创建对象。像这样:

Injector injector = Guice.createInjector(new MyModule());
Bar bar = injector.getInstance(Bar.class);
//do something with bar

希望这能帮到你。如果您有更多问题,请随时问我!

提示:查看Guice的网站,观看视频并仔细阅读维基。 Guice是一个非常棒的工具,但在使用之前你需要做一些研究。 祝你好运!


另外:在我看来,使用@Named是一种糟糕的代码风格。您可以更好地定义自己的注释。例如:

@BindingAnnotation
@Target({ FIELD, PARAMETER, METHOD })
@Retention(RUNTIME)
public @interface FooAnnotation {
}

然后将@Named("foo")替换为@FooAnnotation类中的Bar,并将Names.named("Foo")替换为模块中的FooAnnotation.class

答案 1 :(得分:1)

不幸的是,您无法在局部变量上添加注释。这种限制来自Java,而不是来自Guice。根据{{​​3}},我们希望在未来的Java版本中获得此功能。

但请注意,即使这样可行,也不是一个好习惯。依赖注入的想法是能够从类外部更改依赖关系。局部变量不适合这个,因为它不能从类外部更改。

答案 2 :(得分:0)

其他答案是正确的 - 您只能注入构造函数或字段。将实例保留为字段是标准做法,这也允许您交换自己的实现进行测试。

如果每次调用方法时都需要生成新实例,则可以使用Provider。对于Foo(或@Baz Foo)的任何给定绑定,Provider<Foo>(或@Baz Provider<Foo>)为bound automatically,无需任何额外代码。

public class Bar {
  private Provider<Foo> fooProvider;

  @Inject
  public Bar(@Named("foo") Provider<Foo> fooProvider) {
    this.fooProvider = fooProvider;
  }

  public doSomething() {
    Foo foo = fooProvider.get();
  }
}

当然,你使用bind(...).toInstance(...)的方式,它总是相同的实例,但如果你需要为每次运行方法都需要一个新的实例,这是你最好的选择。