【问题标题】:Pass parameter to constructor with Guice使用 Guice 将参数传递给构造函数
【发布时间】:2012-02-11 05:12:18
【问题描述】:

我有一个工厂如下,

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 构造函数?

有什么想法吗?

【问题讨论】:

    标签: java dependency-injection guice


    【解决方案1】:

    所有“Guice 构造函数参数”的答案在某种程度上似乎都不完整。 这是一个完整的解决方案,包括用法和视觉效果:

    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 Magic)

    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?
    • 请修复“create”方法(FooFactory接口)缺少的返回类型。必须是:Foo create(String bar);
    【解决方案2】:

    您可能正在寻找的是使用 Guice 工厂。使用AssistedInject 功能特别容易,但它们有manual example at the top of the page。手动示例的简短之处在于,您在非静态 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));
    

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

    【讨论】:

    • 是的,糟透了,太复杂了,structuremap 比 guice 灵活得多。
    • 在哪里可以下载用于 Java 的 StructureMap?
    【解决方案3】:

    我知道这是旧线程,但我今天自己遇到了这个问题。 我只需要两个或最多三个不同的 'Foo' 实例,我真的不想编写 Factory 的所有样板代码。 通过谷歌搜索,我发现了这个Stubbisms – Tony’s Weblog,如果你确切地知道你需要什么实例,我会建议这个解决方案。

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

    希望对某人有所帮助。

    【讨论】:

      【解决方案4】:

      如果这个类是一个工厂,它应该是一个 Guice 管理的对象,有一个非静态的 getFoo 方法,而 getFoo 方法只会使用

      new Foo(bar)
      

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

      另见AssistedInject,避免自己创建这个工厂,让Guice为你创建一个。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-04-04
        相关资源
        最近更新 更多