Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/383.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Jersey@ManagedAsync并在HTTP线程和工作线程之间复制数据_Java_Multithreading_Rest_Jersey_Servlet 3.0 - Fatal编程技术网

Java Jersey@ManagedAsync并在HTTP线程和工作线程之间复制数据

Java Jersey@ManagedAsync并在HTTP线程和工作线程之间复制数据,java,multithreading,rest,jersey,servlet-3.0,Java,Multithreading,Rest,Jersey,Servlet 3.0,我正在做一个项目,它有两种风格,有多租户和没有多租户 该项目公开了一个REST服务,我希望它是异步的。 所以我的基本服务看起来像 @Component @Path("/resouce") @Consumes(MediaType.APPLICATION_JSON) public class ResouceEndpoint { @POST @ManagedAsync public void add(final Event event, @Suspended

我正在做一个项目,它有两种风格,有多租户和没有多租户

该项目公开了一个REST服务,我希望它是异步的。 所以我的基本服务看起来像

@Component
@Path("/resouce")
@Consumes(MediaType.APPLICATION_JSON)
public class ResouceEndpoint {
    @POST
    @ManagedAsync
    public void add(final Event event, @Suspended final AsyncResponse asyncResponse) {
        resouce.insert (event);
        asyncResponse.resume( Response.status(Response.Status.NO_CONTENT).build());     
    }
}
没有多租户的情况下效果很好,我可以免费获得泽西岛内部执行人服务的好处。看

当我切换到多租户时,我会在请求上添加一个过滤器,解析租户id并将其放在本地线程(在我们的例子中是HTTP线程)上

当处理链点击“add()”方法时,当前线程是由Jersey executor服务提供的,因此它不包括我的租户id。 我只能考虑以下几个选项来解决这个问题

将ResourceEndpoint扩展到MutLiterationResourceEndpoint并删除@ManagedAsync 使用我自己的线程执行器

public class MutliTenantResouceEndpoint extends ResouceEndpoint {
    @POST
    public void add(final Event event, @Suspended final AsyncResponse asyncResponse) {
        final String tenantId = getTeantIdFromThreadLocal();
        taskExecutor.submit(new Callable<Void>() {
            @Override
            public Void call() throws Exception {
                setTeantIdToThreadLocal(tenantId);
                browserEventsAnalyzer.insertEvent(event);
                Response response = Response.status(Response.Status.NO_CONTENT).build();
                asyncResponse.resume(response);
                return null;
            }
        });
    }
}
公共类MutLiterationResourceEndpoint扩展了ResourceEndpoint{
@职位
public void add(最终事件,@Suspended最终异步响应){
最后一个字符串tenantId=getTeantIdFromThreadLocal();
taskExecutor.submit(新的可调用(){
@凌驾
public Void call()引发异常{
设置本地(租户ID);
browserEventsAnalyzer.insertEvent(事件);
Response=Response.status(Response.status.NO_CONTENT.build();
asyncResponse.resume(响应);
返回null;
}
});
}
}
但这样我需要管理我自己的线程执行器,感觉好像我遗漏了什么。
有没有关于不同方法的建议?

以下是一些建议

作为背景,我已经使用泽西运动衫2年了,18个月前就遇到了这个问题

1.停止使用
@ManagedAsync
如果您可以控制运行Jersey的http服务器,我建议您停止使用
@ManagedAsync

不要将Jersey设置为立即返回其http处理线程,并将实际请求工作卸载到托管执行器服务线程,而是将类似的内容用于http服务器,并将其配置为具有更大的工作线程池。这完成了同样的事情,但将异步责任推到了Jersey下面的一层

如果您对任何中大型项目使用
@ManagedAsync
,您将在一年中遇到许多痛点。下面是我脑海中的一些想法:

  • 如果任何ContainerRequestFilter命中外部服务(例如,身份验证筛选器命中您的安全模块,该模块命中数据库),您将失去您认为获得的好处
    • 如果DB阻塞,并且auth filter调用需要5秒钟,Jersey尚未将工作卸载到异步线程,因此需要接收新conn的主线程被阻塞
  • 如果在筛选器中设置了logback的MDC,并且希望在整个请求中都使用该上下文,则需要在托管异步线程上再次设置MDC
  • 资源方法对于新手来说是神秘的,而且读起来很难看,因为:
    • 它们需要一个额外的参数
    • 它们返回void,隐藏其真正的响应类型
    • 他们可以在任何地方“返回”,而不需要任何实际的
      return
      语句
  • Swagger或其他API文档工具无法自动记录异步资源终结点
  • Guice或其他DI框架在处理异步资源端点中的某些范围绑定和/或提供程序时可能会遇到问题
2.使用
@Context
ContainerRequest
属性 这涉及到在过滤器中调用
requestContext.setProperty(“tenant\u id”,tenantId)
,然后使用
@Context
注入请求在资源中调用
requestContext.getProperty(“tenant\u id”)

3.使用HK2 AOP而不是Jersey过滤器 这将涉及设置一个
InterceptionService
的HK2绑定,该绑定具有一个
MethodInterceptor
,用于检查托管异步资源方法,并手动执行所有
RequestScoped
绑定的
ContainerRequestFilter
。您的过滤器不是在Jersey注册的,而是在HK2注册的,由方法拦截器运行


如果您愿意,我可以在选项2/3中添加更多细节和代码示例,或者提供更多建议,但首先查看更多的筛选代码会有所帮助,如果可能,我再次建议选项1。

+1对于详细答案,我最终使用了选项1建议。当我有时间时,我会尝试选项3并让你知道。选项2是不相关的,因为我必须按原样使用过滤器。我知道这有点旧,但仍然有效。关于如何解决你提到的MDC陷阱,你有什么建议吗?将自定义执行器+异步执行器设置为简单复制上下文就足够了吗?