Передать параметр конструктору с 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;              
    }

}

это определение Foo:

class Foo
{
   Foo(String bar)
   {

   }

}

OK. Я не уверен, как я могу передать этот параметр конструктору Foo с Guice?

какие идеи?

4 ответов


все ответы "Guice Constructor Parameter" кажутся неполными в некотором роде. Вот полное решение, включая использование:

interface FooInterface{
  String getFooName();
}

// аннотировать конструктор и вспомогательные параметры в классе реализации

class Foo implements FooInterface {
   String bar;

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

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

}

/ / создайте заводской интерфейс с методом create (), который принимает только вспомогательные параметры. // Интерфейс FooFactory не имеет явного класса реализации (Guice Magic)

interface FooFactory{
   Foo create(String bar);
}

/ / свяжите эту фабрику поставщику, созданному AssistedInject

binderModule implements Module{

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

// теперь использовать это:

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!"
   }
}

много помогает здесь: https://google.github.io/guice/api-docs/latest/javadoc/index.html?com/google/inject/assistedinject/FactoryModuleBuilder.html


то, что вы, вероятно, ищете, это использовать Guice factory. Особенно легко с 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));

вы можете проверить javadoc для FactoryModuleBuilder примеры более сложных заводов.


Я знаю, что это старая нить, но я просто попал в проблему сам сегодня. Мне нужно только два или максимум три разных экземпляра "Foo", и я действительно не хотел писать весь код bolierplate фабрики. С небольшим googling я нашел это Стаббизмы-Веблог Тони Я бы предложил такое решение, которое идеально подходит, если вы точно знаете, каких случаях нужно.

в модуле 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;
    }
}

надеюсь, это кому-то поможет.


если этот класс является фабрикой, это должен быть объект, управляемый Guice, имеющий нестатический метод getFoo, и метод getFoo будет просто использовать

new Foo(bar)

Не каждый класс должен быть создан экземпляром Guice.

см. Также AssistedInject, чтобы избежать создания этой фабрики самостоятельно и позволить Guice создать один для вас.