在JAX-RS网络应用程序中,我们使用子资源:
@Path("/some/things")
public class ThingsListResource {
@Inject
SomeStorage store;
@GET
public List<Thing> getAllThings() {
return store.getAllThings();
}
@Path("{id}")
public ThingResource getThingResource(@PathParam("id") String id) {
return new ThingResource(id); // PROBLEMATIC
}
}
public class ThingResource {
@Inject
SomeOtherDependecy dep;
@Inject
SomeStorage store;
private final String id;
public ThingResource(String id) {
this.id = id;
}
@GET
public Thing getThisThing() {
return store.getThing(id);
}
@DELETE
public void removeThisThing() {
store.removeThing(id);
}
// following is a list of methods useful enough
// to make ThingResource a useable subresource
}
正如您所注意到的那样,使用Guice及其GuiceResteasyBootstrapServletContextListener
进行了注射。注入根资源的依赖关系没有问题。上面有问题的行标有PROBLEM
:子资源是手工创建的,省略了所有Guice注入。
将Guice中的依赖项注入子资源的主要方法是什么?我可以在这里想到几个选项:
将注入器注入根资源并使用它创建子资源,可能在子资源中有一些@Assisted
魔法:
@Inject
Injector injector
// ...
return injector.getInstance(ThingResource.class); // via some provider accepting id?
但是我无法将我的头部注入“提取物”的id
或@Assisted
注射。此外,这里看起来需要很多Guice样板。
忘记子资源的Guice管理,并从root资源手动将每个依赖项传递给它的构造函数。简单但非常“手工依赖注射” - 似乎。
创建ThingsListResource
的子资源和内部类,从而让它可以访问外部类(注入)字段。不是很可扩展(例如,如果想要有不同的子资源实现公共接口),但是简单......
忘记子资源并将它们“升级”为根资源。这有点打破DRY规则,因为您将指定每个资源的完整URL路径。
还有其他方法可以采用或更简单的方式来实现上述想法吗?
答案 0 :(得分:8)
这是assisted inject的理想用例。您需要定义工厂界面:
public interface ThingResourceFactory {
public ThingResource create(String id);
}
然后在一个模块中绑定它:
install(new FactoryModuleBuilder().build(ThingResourceFactory.class));
然后修改ThingResource
构造函数:
private final String id;
@Inject
public ThingResource(@Assisted String id) {
this.id = id;
}
(顺便说一下,如果我是你,我会使用构造函数注入而不是场注入,但这只是一个附注)
然后您将ThingResourceFactory
注入ThingsListResource
并在资源方法中使用它:
@Path("/some/things")
public class ThingsListResource {
@Inject
SomeStorage store;
@Inject
ThingResourceFactory thingResourceFactory;
@GET
public List<Thing> getAllThings() {
return store.getAllThings();
}
@Path("{id}")
public ThingResource getThingResource(@PathParam("id") String id) {
return thingResourceFactory.create(id);
}
}
看,几乎没有样板,非常容易使用! Guice将自动为您创建ThingResourceFactory
实例,它将create()
个参数直接传递给类构造函数中的@Assisted
参数,并使用常规方法注入其他参数/字段/方法/等。