如何将自定义上下文绑定到Jersey请求

时间:2014-02-19 19:24:03

标签: java jersey

我有一个带有基于令牌的用户身份验证的Jersey REST应用程序。当请求进入时,会创建自定义RestContext对象并将其作为属性添加到ContainerRequestContext(通过在收到请求后立即运行的过滤器)。此上下文管理用户授权(通过角色)和对其他业务逻辑的访问。它可用于执行业务逻辑的资源。处理请求时,RestContext将在管道最末端执行的第二个过滤器中清除。

虽然需要两个过滤器,但效果很好。我一直在阅读关于HK2和InjectionResolver的使用,我想知道是否可以使用注入在我的资源和其他过滤器中注入此RestContext(例如,我有一个创建{的过滤器来自SecurityContext的{​​1}},但我找不到答案。通常,如何根据请求上下文为每个请求注入一个对象?这甚至可能吗?有没有更简单的方法,例如,使用RestContext

编辑:正如我所指出的,我基本上试图在我的资源中注入the documentation行的自定义类。但是,我似乎无法正确注册我的@Context以绑定我的类的注入。我得到以下内容:

AbstractBinder

编辑 2:我设法取得了一些进展。我按以下方式创建配置:

org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at Injectee(requiredType=RestContext,parent=RestContextFilter,qualifiers={}),position=0,optional=false,self=false,unqualified=null,1435496015)

因为文件明确指出粘合剂的注入是not supported via class but via instance

但是我现在得到了这个:

new ResourceConfig(allResources())
  .packages(packagesToScan())
  .registerInstances(new RestContextBinder());

RestContext是A MultiException has 3 exceptions. They are: 1. java.lang.IllegalStateException: Not inside a request scope. 2. java.lang.IllegalArgumentException: While attempting to resolve the dependencies of my.package.RestContextFilter errors were found 3. java.lang.IllegalStateException: Unable to perform operation: resolve on my.package.RestContextFilter - 在请求/响应过滤器中编辑。然后,它用于创建@Inject并将其设置在SecurityContext中,并在响应过滤器中清除它。是不是响应过滤器请求作用域?为什么我收到错误?

1 个答案:

答案 0 :(得分:6)

UPDATE 现在Jersey 2.7已经淘汰,解决方案更简单。

听起来你想要一个RequestScoped绑定。以下是使用Jersey 2.7进行设置的方法:

您需要一个请求过滤器,因为RestContext将是RequestScoped,您可以将过滤器注入过滤器,在其上设置一些属性,并知道它们可用于剩余的请求。

@Priority(Priorities.AUTHORIZATION) // filter deals with roles, comes after AUTHENTICATION
public class RestContextFilter implements ContainerRequestFilter
{
    // you need to inject a provider, rather than the class directly
    // because this filter is instantiated before the request scope is ready
    private Provider<RestContext> rcProvider;

    @Inject
    public RestContextFilter(Provider<RestContext> rcProvider)
    {
        this.rcProvider = rcProvider;
    }

    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException
    {
        // now you're in a request scope and can get your context
        RestContext rc = rcProvider.get();

        // set some properties on rc here (current user or roles or whatever)
    }
}

您需要注册过滤器并使用HK2绑定绑定RestContext中的ResourceConfig

public class MyResourceConfig extends ResourceConfig
{
    public MyResourceConfig()
    {
        register(RestContextFilter.class);

        register(new AbstractBinder()
        {
            @Override
            protected void configure()
            {
                bindFactory(new Factory<RestContext>()
                {
                    @Override
                    public RestContext provide()
                    {
                        return new RestContext();
                    }

                    // this will get called at the end of the request
                    // allowing you to close your request scoped object
                    @Override
                    public void dispose(RestContext instance)
                    {
                        instance.close();
                    }
                }, RequestScoped.class).to(RestContext.class).in(RequestScoped.class);
            }
        });
    }
}

然后,您可以在资源中注入RestContext,并且过滤器会设置所有信息。例如:

@Path("/my/path")
public class MyResource
{
    private RestContext rc;

    @Inject
    public MyResource(RestContext rc)
    {
        this.rc = rc;
    }

    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    public void upload(MyPostObj data)
    {
        // do stuff here, and rc is all set up
    }
}

我倾向于选择构造函数注入而不是字段注入,因为我认为它使得您的依赖项对于阅读代码的其他开发人员来说更加明显。也很抱歉,如果我的支撑方式让你烦恼,我来自.NET的精彩世界:)。