我怎样才能使非辅助依赖成为辅助依赖?
How can I make a non-assisted dependency assisted?
假设我有第三方class如下:
public class MyObject {
@Inject
public MyObject(Foo foo, Bar bar) { ... }
}
现在假设我有一个像这样的工厂接口:
public interface MyObjectFactory {
public MyObject build(Bar bar);
}
我的想法是,我希望有一个 MyObjectFactory
为固定的 Foo
构建一个 MyObject
- 也就是说,本质上是在 @Assisted
上添加注释来自外部的 Bar
构造函数参数。当然,手动实现MyObjectFactory
总是可以的:
public class MyObjectFactoryImpl implements MyObjectFactory {
@Inject private Provider<Foo> foo;
@Override
public MyObject build(Bar bar) { return new MyObject(foo.get(), bar); }
}
但是假设有一些条件要求我让 Guice 构建 MyObject
个实例 - 例如,方法拦截器。这似乎是 "injecting the injector":
的工作
public class MyObjectFactoryImpl implements MyObjectFactory {
@Inject private Injector injector;
@Override
public MyObject build(Bar bar) {
Injector child = injector.createChildInjector(new AbstractModule() {
@Override
protected void configure() {
bind(Bar.class).toInstance(bar);
// Set up method interceptors for MyObject here...
}
});
return child.getInstance(MyObject.class);
}
}
这听起来很邪恶,而且是样板式的,所以我想知道是否有任何替代实现 and/or 一种让 Guice 生成工厂实现的方法。
实际上是。看看Assisted Inject
包括
<dependency>
<groupId>com.google.inject.extensions</groupId>
<artifactId>guice-assistedinject</artifactId>
<version>${guice.version}</version>
</dependency>
使用辅助更新注入
public class MyInjectedObject extends MyObject implements MyIntf {
@Inject
public MyObject(Foo foo, @Assisted Bar bar) { super(foo,bar); }
}
您还需要添加一个接口:
public interface MyIntf {}
在你的模块中将通用工厂绑定到你的接口
install(new FactoryModuleBuilder()
.implement(MyIntf.class, MyInjectedObject.class)
.build(MyObjectFactory.class)
);
现在您可以在任何地方注入 MyObjectFactory
。
MyObject obj = myObjectFactory.build(bar);
首先,出于您所描述的原因,您很少希望在 class 中传递 MyObject
的实例。你无法控制它们,所以你不能添加 @Assisted
注释,你不能添加方法拦截器等等。另外,当你想为不同的实现换出第三方库时会发生什么?
因此,您应该将 MyObject
包装到另一个对象中。
// **Please** choose better names than this in your real code.
public class MyWrapperBackedByMyObject implements MyWrapperInterface {
private final MyObject delegate;
@Inject
MyWrapperObject(Foo foo, @Assisted Bar bar) {
delegate = new MyObject(foo, bar);
}
@NotOnWeekends // Example of how you might do method interception
public void orderPizza() {
delegate.orderPizza();
}
}
然后,删除整个代码中对 MyObject
的所有引用,使用我上面描述的命名约定,应该只引用 MyWrapperInterface
.
假设我有第三方class如下:
public class MyObject {
@Inject
public MyObject(Foo foo, Bar bar) { ... }
}
现在假设我有一个像这样的工厂接口:
public interface MyObjectFactory {
public MyObject build(Bar bar);
}
我的想法是,我希望有一个 MyObjectFactory
为固定的 Foo
构建一个 MyObject
- 也就是说,本质上是在 @Assisted
上添加注释来自外部的 Bar
构造函数参数。当然,手动实现MyObjectFactory
总是可以的:
public class MyObjectFactoryImpl implements MyObjectFactory {
@Inject private Provider<Foo> foo;
@Override
public MyObject build(Bar bar) { return new MyObject(foo.get(), bar); }
}
但是假设有一些条件要求我让 Guice 构建 MyObject
个实例 - 例如,方法拦截器。这似乎是 "injecting the injector":
public class MyObjectFactoryImpl implements MyObjectFactory {
@Inject private Injector injector;
@Override
public MyObject build(Bar bar) {
Injector child = injector.createChildInjector(new AbstractModule() {
@Override
protected void configure() {
bind(Bar.class).toInstance(bar);
// Set up method interceptors for MyObject here...
}
});
return child.getInstance(MyObject.class);
}
}
这听起来很邪恶,而且是样板式的,所以我想知道是否有任何替代实现 and/or 一种让 Guice 生成工厂实现的方法。
实际上是。看看Assisted Inject
包括
<dependency>
<groupId>com.google.inject.extensions</groupId>
<artifactId>guice-assistedinject</artifactId>
<version>${guice.version}</version>
</dependency>
使用辅助更新注入
public class MyInjectedObject extends MyObject implements MyIntf {
@Inject
public MyObject(Foo foo, @Assisted Bar bar) { super(foo,bar); }
}
您还需要添加一个接口:
public interface MyIntf {}
在你的模块中将通用工厂绑定到你的接口
install(new FactoryModuleBuilder()
.implement(MyIntf.class, MyInjectedObject.class)
.build(MyObjectFactory.class)
);
现在您可以在任何地方注入 MyObjectFactory
。
MyObject obj = myObjectFactory.build(bar);
首先,出于您所描述的原因,您很少希望在 class 中传递 MyObject
的实例。你无法控制它们,所以你不能添加 @Assisted
注释,你不能添加方法拦截器等等。另外,当你想为不同的实现换出第三方库时会发生什么?
因此,您应该将 MyObject
包装到另一个对象中。
// **Please** choose better names than this in your real code.
public class MyWrapperBackedByMyObject implements MyWrapperInterface {
private final MyObject delegate;
@Inject
MyWrapperObject(Foo foo, @Assisted Bar bar) {
delegate = new MyObject(foo, bar);
}
@NotOnWeekends // Example of how you might do method interception
public void orderPizza() {
delegate.orderPizza();
}
}
然后,删除整个代码中对 MyObject
的所有引用,使用我上面描述的命名约定,应该只引用 MyWrapperInterface
.