Передать параметр конструктору с 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 создать один для вас.