Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/307.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
grpc java异步调用服务器侦听器_Java_Asynchronous_Authorization_Interceptor_Grpc - Fatal编程技术网

grpc java异步调用服务器侦听器

grpc java异步调用服务器侦听器,java,asynchronous,authorization,interceptor,grpc,Java,Asynchronous,Authorization,Interceptor,Grpc,我有一个GRPCJava服务器,需要在处理请求之前对身份验证服务进行异步调用。我认为这应该在拦截器中完成,但它需要从interceptCall()同步返回侦听器 类AuthInterceptor实现ServerInterceptor{ @凌驾 publicservercall.listenerinterceptcall( 服务器呼叫, 元数据头, ServerCallHandler下一步 ) { String token=”“;//从标头获取标记 authService.authorize(令牌

我有一个GRPCJava服务器,需要在处理请求之前对身份验证服务进行异步调用。我认为这应该在拦截器中完成,但它需要从interceptCall()同步返回侦听器

类AuthInterceptor实现ServerInterceptor{ @凌驾 publicservercall.listenerinterceptcall( 服务器呼叫, 元数据头, ServerCallHandler下一步 ) { String token=”“;//从标头获取标记 authService.authorize(令牌).subscribe( 确定->//处理请求 错误->调用.关闭(Status.UNAUTHENTICATED,标题) ); //这里我们需要返回一个侦听器,但我们还没有开始调用 } }
因此,问题是:如何从ServerInterceptor进行异步调用,如果无法完成,那么什么是对请求进行异步身份验证的正确方法?我知道这可以通过StreamObservators直接在grpc服务中完成,但请求授权是一个交叉问题,拦截器似乎是一个完美的地方。

您确实需要返回一个
ServerCall.Listener
。但是,由于您不知道要委托给的
侦听器
,因此可以重写
侦听器
中的每个方法以将回调添加到队列中。身份验证完成后,排空队列

class DelayedListener<ReqT> extends Listener<ReqT> {
  private Listener<ReqT> delegate;
  private List<Runnable> events = new ArrayList<Runnable>();

  @Override public synchronized void onMessage(ReqT message) {
    if (delegate == null) {
      events.add(() -> delegate.onMessage(message));
    } else {
      delegate.onMessage(message);
    }
  }
  ...
  public synchronized void setDelegate(Listener<ReqT> delegate) {
    this.delegate = delegate;
    for (Runnable runnable : events) {
      runnable.run();
    }
    events = null;
  }
}
类DelayedListener扩展了Listener{ 私人听众代表; 私有列表事件=新的ArrayList(); @覆盖公共同步void onMessage(请求消息){ if(委托==null){ 添加(()->delegate.onMessage(message)); }否则{ onMessage(消息); } } ... 公共同步的void setDelegate(侦听器委托){ this.delegate=委托; for(可运行:事件){ runnable.run(); } 事件=空; } }
很好的解决方案。它是否适用于ConcurrentLinkedQueue而不是回调和setDelegate()上的同步?您的解决方案非常有效,解决了一般问题。我找到了另一个可能的解决方案:一个像往常一样转发所有回调并且只延迟
onHalfClosed()
回调的
SimpleForwardingServerCallListener
似乎也适用于我。或者此解决方案存在线程问题?在直接转发新事件之前,您需要确保“耗尽”所有排队事件。如果您只是使用ConcurrentLinkedQueue+volatile delegate,那么您有两个竞争:1)此.delegate=delegate位于
setDelegate()
的开头,让新事件在旧事件之前“竞争”,或2)此.delegate=delegate位于
setDelegate()
的末尾,事件可能会“卡住”在队列中。排队时你真的需要一把锁。如果
委托!=null
和调用
runnable.run()
时,但它更复杂。请参阅GRPC中的DelayedStream一元流和服务器流的存根调用延迟调用应用程序,直到
onHalfClosed()
。但是,1)其他拦截器仍将运行,2)客户端流和bidi流不是这样,3)生态系统中有一些备用服务器存根浮动,它们的行为可能不同。@AbhijitSarkar,是的。它在等待授权完成时排队,然后您使用setDelegate()排空队列。您是否可以更新您的问题,显示您使用
DelayedListener
的结果?我不清楚如何把这些点连接起来。
class DelayedListener<ReqT> extends Listener<ReqT> {
  private Listener<ReqT> delegate;
  private List<Runnable> events = new ArrayList<Runnable>();

  @Override public synchronized void onMessage(ReqT message) {
    if (delegate == null) {
      events.add(() -> delegate.onMessage(message));
    } else {
      delegate.onMessage(message);
    }
  }
  ...
  public synchronized void setDelegate(Listener<ReqT> delegate) {
    this.delegate = delegate;
    for (Runnable runnable : events) {
      runnable.run();
    }
    events = null;
  }
}