JAX-RS子资源和Guice注入

时间:2014-07-28 13:03:03

标签: java dependency-injection jax-rs guice

在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中的依赖项注入子资源的主要方法是什么?我可以在这里想到几个选项:

  1. 将注入器注入根资源并使用它创建子资源,可能在子资源中有一些@Assisted魔法:

    @Inject
    Injector injector
    
    // ...
    
    return injector.getInstance(ThingResource.class); // via some provider accepting id?
    

    但是我无法将我的头部注入“提取物”的id@Assisted注射。此外,这里看起来需要很多Guice样板。

  2. 忘记子资源的Guice管理,并从root资源手动将每个依赖项传递给它的构造函数。简单但非常“手工依赖注射” - 似乎。

  3. 创建ThingsListResource的子资源和内部类,从而让它可以访问外部类(注入)字段。不是很可扩展(例如,如果想要有不同的子资源实现公共接口),但是简单......

  4. 忘记子资源并将它们“升级”为根资源。这有点打破DRY规则,因为您将指定每个资源的完整URL路径。

  5. 还有其他方法可以采用或更简单的方式来实现上述想法吗?

1 个答案:

答案 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参数,并使用常规方法注入其他参数/​​字段/方法/等。