Передача параметра конструктору с помощью 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)
{
}
}
ХОРОШО. Я не уверен, как я могу передать этот параметр конструктору Foo с помощью Guice?
Есть идеи?
Ответы
Ответ 1
Все ответы "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.
Ответ 2
То, что вы, вероятно, ищете, - это использовать Guice factory. Особенно удобно использовать AssistedInject
, но они имеют ручной пример в верхней части страницы. Короче говоря, для примера с ручным является то, что вы получаете factory под нестатический метод 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);
}
Затем в вашем графическом модуле:
install(new FactoryModuleBuilder()
.implement(Foo.class, FooImpl.class)
.build(FooFactory.class));
Вы можете проверить javadoc для FactoryModuleBuilder
для примеров с более сложными фабриками.
Ответ 3
Я знаю, что это старая ветка, но сегодня я сам решил эту проблему. Мне нужно всего два или максимум три разных экземпляра 'Foo', и я действительно не хотел писать весь болгарный код Factory. Немного погуглив, я нашел этот веб-блог Stubbisms - Tonys. Я бы предложил это решение, которое идеально, если вы точно знаете, какие экземпляры вам нужны.
В модуле 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) {
}
И Фу в моем случае:
public class FooImpl implements Foo {
private String name;
public FooImpl(String name) {
this.name = name;
}
@Override
public String getName() {
return name;
}
}
Надеюсь, это поможет кому-то.
Ответ 4
Если этот класс является factory, он должен быть объектом, управляемым Guice, с не статическим методом getFoo, и метод getFoo будет использовать
new Foo(bar)
Не каждый класс должен быть создан Guice.
Также см. AssistedInject, чтобы избежать создания этого factory самостоятельно и позволить Guice создать его для вас.