Jersey Async ContainerRequestFilter

Ald*_*den 10 java rest asynchronous jersey jersey-2.0

我有一个Jersey REST API并使用a ContainerRequestFilter来处理授权.我也在@ManagedAsync所有端点上使用,以便我的API可以服务数千个并发请求.

我的授权过滤器命中远程服务,但是当运行过滤器时,Jersey还没有将当前线程添加到它的内部ExecutorService,所以我完全失去了异步的好处.

我可以告诉泽西岛我希望这ContainerRequestFilter是异步的吗?

@Priority(Priorities.AUTHORIZATION)
public class AuthorizationFilter implements ContainerRequestFilter
{
    @Inject
    private AuthorizationService authSvc;

    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException
    {
        String authToken = requestContext.getHeaderString(HttpHeaders.AUTHORIZATION);

        // HITS A REMOTE SERVER
        AuthorizationResponse authResponse = authSvc.authorize(authToken);

        if (!authResponse.isAuthorized())
        {
            requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED)
                    .entity("unauthorized!")
                    .build());
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是一个示例资源:

@Path("/stuff")
@Produces(MediaType.APPLICATION_JSON)
public class StuffResource
{
    @GET
    @Path("/{id}")
    @ManagedAsync
    public void getById(@PathParam("id") long id, @Suspended final AsyncResponse ar)
    {
        Stuff s;

        // HIT THE DATABASE FOR STUFF

        ar.resume(s);
    }
}
Run Code Online (Sandbox Code Playgroud)

更新刚刚从泽西岛球员那里听到,从2.7开始这是不可能的.仅异步调用资源方法本身,而不是过滤器.任何进行的建议仍然欢迎.

Ald*_*den 4

从 2.7 开始,Jersey 尚未内置此功能。

@ManagedAsync如果您有任何过滤器或拦截器执行任何严肃的工作(例如点击远程授权服务),则毫无用处。他们将来可能会添加异步运行过滤器的功能,但现在您只能靠自己了。

更新- 还有其他方法......

经过漫长而危险的旅程后,我找到了一个非常棘手的解决方案,并在短期内使用。以下是我尝试过的内容以及失败/有效的原因。

Guice AOP - 失败

我使用 Guice 进行 DI(让 Guice 注入与 Jersey 一起使用本身就是一项壮举!),所以我想我可以使用 Guice AOP 来解决这个问题。尽管 Guice 注入可以工作,但不可能让 Guice 使用 Jersey 2 创建资源类,因此 Guice AOP 无法使用资源类方法。如果您拼命地尝试让 Guice 使用 Jersey 2 创建资源类,请不要浪费时间,因为它不会起作用。这是一个众所周知的问题

HK2 AOP -推荐解决方案

HK2 最近刚刚发布了 AOP 功能,请参阅此问题以了解如何使其工作的详细信息。

监控- 也有效

这不适合胆小的人,并且在Jersey 文档中完全不鼓励这样做。您可以注册 和ApplicationEventListener并覆盖onRequest以返回RequestEventListener侦听RESOURCE_METHOD_START和调用身份验证/授权服务的 。该事件是从@ManagedAsync线程触发的,这就是这里的全部目标。需要注意的是,该abortWith方法是无操作的,因此它不会像正常的ContainerRequestFilter. 相反,如果身份验证失败,您可以抛出异常,并注册一个ExceptionMapper来处理您的异常。如果有人有足够的勇气尝试一下,请告诉我,我将发布代码。