泽西2每请求@Context注入

时间:2016-06-27 16:38:56

标签: dependency-injection jax-rs jersey-2.0

概述

在Jersey 2中,我可以在我的资源中注入自定义的特定于请求的值吗?具体来说,我想注入一个MyThing,它可以从我的自定义安全上下文MySecurityContext派生。我想直接注入MyThing以使代码清洁。

有没有办法做到这一点?根据{{​​3}},使用ContextResolver无法完成,this questionthis article表示可能。

什么有用

使用身份验证过滤器,我可以使用以下代码设置自定义安全上下文:

@Provider
public class HttpTokenAuthFilter implements IComposableJaxRsAuthFilter {

   @Override
   public boolean doAuth(ContainerRequestContext requestContext) throws WebApplicationException {
       // error handling omitted
       requestContext.setSecurityContext(MySecurityContext.fromHeaders(requestContext));
   }
}

...然后在我的资源中我可以从中提取一个值:

@Path("/foo")
public class MyResource {
    @Context 
    private SecurityContext securityContext;

    @Get
    public String doGetFoo() {
       MyThing myThing = ((MySecurityContext)securityContext).getThing();
       // use myThing to produce a result
    }

我被困的地方

...但是,由于这将重复很多,我宁愿写一下:

    @Context
    private MyThing myThing;

我尝试定义ContextResolver。我看到它正在构建,但我从未看到它被调用,所以我还没有尝试过任何上面链接的技术。这甚至是正确使用的类吗?

@Provider
public class MyThingResolver implements ContextResolver<MyThing> {

    public MyThingResolver() {
        System.out.println("ctor");
    }

    @Override
    public MyThing getContext(Class type) {
        System.out.println("getContext");

        if (type.equals(MyThing.class)) {
           return new MyThing(); // TODO: SHOULD ACTUALLY USE CURRENT MySession
        }
        return null;
    }
}

1 个答案:

答案 0 :(得分:1)

几乎是解决方案

根据this answer以及this followup指定的优化,几乎可以使用Factory完成注入。唯一需要注意的是,您必须通过MyThing注入Provider,否则它将在过滤器运行和交换之前创建(使用默认 SecurityContext)在MySecurityContext

工厂代码如下所示:

public class MyThingFactory implements Factory<MyThing> {

    @Context
    private SecurityContext securityContext;

    @Override
    public MyThing provide() {
        return ((MySecurityContext)securityContext).getThing();
    }

    @Override
        public void dispose(MyThing session) {
    }
}

然后资源可以像这样注入:

@Context
private Provider<MyThing> myThingProvider;

......并按照这样消费:

MyThing myThing = myThingProvider.get();
// use myThing

AbstractBinder中的工厂注册如下所示:

this.bindFactory(MyThingFactory.class) //
    .to(MyThing.class) //
    .in(RequestScoped.class);

(编辑)救援代理人!

根据@peeskillet的评论,可以通过代理Provider来摆脱MyThing。 (Per @ jwells131313,MyThing因此必须是一个接口或一个可代理的类。)

然后绑定看起来像这样:

this.bindFactory(MyThingFactory.class) //
    .to(MyThing.class) //
    .proxy(true) //
    .in(RequestScoped.class);

注射最终按预期工作:

@Context
private MyThing myThing;