设置 gRPC ServerInterceptors 的执行顺序

Ras*_*tko 3 java spring grpc grpc-java

在 io.grpc.internal.AbstractServerImplBuilder 中,您可以将 ServerInterceptor 的实现添加到最终列表中

final List<ServerInterceptor> interceptors = new ArrayList<>();
Run Code Online (Sandbox Code Playgroud)

然后在构建器的默认服务器实现中 - io.grpc.internal.ServerImpl 它在 foreach 循环中调用它们

/** Never returns {@code null}. */
private <ReqT, RespT> ServerStreamListener startCall(ServerStream stream, String fullMethodName,
    ServerMethodDefinition<ReqT, RespT> methodDef, Metadata headers,
    Context.CancellableContext context, StatsTraceContext statsTraceCtx, Tag tag) {
  // TODO(ejona86): should we update fullMethodName to have the canonical path of the method?
  statsTraceCtx.serverCallStarted(
      new ServerCallInfoImpl<>(
          methodDef.getMethodDescriptor(), // notify with original method descriptor
          stream.getAttributes(),
          stream.getAuthority()));
  ServerCallHandler<ReqT, RespT> handler = methodDef.getServerCallHandler();
  for (ServerInterceptor interceptor : interceptors) {
    handler = InternalServerInterceptors.interceptCallHandler(interceptor, handler);
  }
  ServerMethodDefinition<ReqT, RespT> interceptedDef = methodDef.withServerCallHandler(handler);
  ServerMethodDefinition<?, ?> wMethodDef = binlog == null
      ? interceptedDef : binlog.wrapMethodDefinition(interceptedDef);
  return startWrappedCall(fullMethodName, wMethodDef, stream, headers, context, tag);
}
Run Code Online (Sandbox Code Playgroud)

因此它会在收到请求时执行从最后一个注册到前一个注册的拦截器链。从处理程序执行响应时遵循相同的顺序。

我想知道和期望的是它将遵循洋葱中间件模式,并且您可以显式设置执行顺序(类似于 servlet 过滤器)。我错过了什么吗?

Eri*_*son 5

没有办法设置顺序。ServerBuilder.intercept()是 , 的便捷版本ServerInterceptors.intercept(),并且遵循相同的语义。有一种ServerInterceptors.interceptForward()方法可以以相反的方向运行它们,但是您无法拥有单独添加拦截器并同时支持两种形式的 API。

拦截 API 有点令人困惑,因为它确实遵循洋葱原则,但洋葱是围绕服务的。拦截器包装了一个服务,因此最后应用的拦截器首先执行。

serviceDef = ServerInterceptors.intercept(serviceDef,
    interceptor1,
    interceptor2,
    interceptor3);

// is equivalent to

serviceDef = ServerInterceptors.intercept(serviceDef, interceptor1);
serviceDef = ServerInterceptors.intercept(serviceDef, interceptor2);
serviceDef = ServerInterceptors.intercept(serviceDef, interceptor3);
// the gRPC server sees the last 'serviceDef', so interceptor3 is
// called first
Run Code Online (Sandbox Code Playgroud)