Multithreading springbootgrpc:ServerIntereceptor读取请求中的数据,并在响应中设置它
在GRPC服务的每个请求协议中都有一个名为“元数据”的字段(不要与GRPC元数据混淆):Multithreading springbootgrpc:ServerIntereceptor读取请求中的数据,并在响应中设置它,multithreading,grpc,interceptor,thread-local,grpc-java,Multithreading,Grpc,Interceptor,Thread Local,Grpc Java,在GRPC服务的每个请求协议中都有一个名为“元数据”的字段(不要与GRPC元数据混淆): message MyRequest { RequestResponseMetadata metadata = 1; ... } 所有响应中也存在相同的字段: message MyResponse { RequestResponseMetadata metadata = 1; ... } 我正在尝试编写一个ServerInterceptor(或者其他东西,如果可以的话),从请求中读取“me
message MyRequest {
RequestResponseMetadata metadata = 1;
...
}
所有响应中也存在相同的字段:
message MyResponse {
RequestResponseMetadata metadata = 1;
...
}
我正在尝试编写一个ServerInterceptor
(或者其他东西,如果可以的话),从请求中读取“metadata”字段,将其保存在某个地方,然后在处理完请求后在响应中设置它
尝试1:ThreadLocal
public class ServerInterceptor implements io.grpc.ServerInterceptor {
private ThreadLocal<RequestResponseMetadata> metadataThreadLocal = new ThreadLocal<>();
@Override
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
ServerCall<ReqT, RespT> call,
final Metadata requestHeaders,
ServerCallHandler<ReqT, RespT> next) {
return new SimpleForwardingServerCallListener<ReqT>(
next.startCall(
new SimpleForwardingServerCall<ReqT, RespT>(call) {
@Override
public void sendMessage(RespT message) {
super.sendMessage(
(RespT)
MetadataUtils.setMetadata(
(GeneratedMessageV3) message, metadataThreadLocal.get()));
metadataThreadLocal.remove();
}
},
requestHeaders)) {
@Override
public void onMessage(ReqT request) {
// todo nava see if ReqT can extend GenericV3Message
var metadata = MetadataUtils.getMetadata((GeneratedMessageV3) request);
metadataThreadLocal.set(metadata);
super.onMessage(request);
}
};
}
}
我计划在一个onComplete()
中分离上下文,但在它自身到达之前,sendMessage中的METADATA\u KEY.get()
返回null
,而我希望它返回数据
甚至在点击sendMessage()
函数之前,我就在控制台中得到了这个消息,表明我做错了什么:
3289640 [grpc-default-executor-0] ERROR i.g.ThreadLocalContextStorage - Context was not attached when detaching
java.lang.Throwable: null
at io.grpc.ThreadLocalContextStorage.detach(ThreadLocalContextStorage.java:48)
at io.grpc.Context.detach(Context.java:421)
at io.grpc.Context$CancellableContext.detach(Context.java:761)
at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:39)
at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:123)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
如何在接收到请求时读取数据、将其存储在某处并在发送回响应时使用它?您可以使用将值从请求传递到响应:
公共类MetadataServerInterceptor实现ServerInterceptor{
public static final Metadata.Key Metadata\u Key=Metadata.Key.of(“Metadata bin”,Metadata.BINARY\u BYTE\u MARSHALLER);
@凌驾
public ServerCall.Listener interceptCall(ServerCall调用、元数据头、ServerCallHandler-next){
var serverCall=new ForwardingServerCall.SimpleForwardingServerCall(调用){
@凌驾
公共无效发送消息(响应消息){
字节[]metadata=headers.get(metadata\u键);
message=(RespT)MetadataUtils.setMetadata((GeneratedMessageV3)消息,元数据);
super.sendMessage(message);
}
};
ServerCall.Listener listenerWithContext=Contexts.interceptCall(Context.current(),ServerCall,headers,next);
返回新的ForwardingServerCallListener.SimpleForwardingServerCallListener(listenerWithContext){
@凌驾
公共消息无效(请求消息){
字节[]元数据=MetadataUtils.getMetadata((GeneratedMessageV3)消息);
headers.put(元数据\关键字,元数据);
super.onMessage(message);
}
};
}
}
注意:由于无法将RequestResponseMetadata
的实例放入元数据中(至少在不实现自定义封送拆收器的情况下),因此可以将其保存为字节数组。您可以在RequestResponseMetadata
对象上使用toByteArray()
来获取byte[]
和RequestResponseMetadata.#parseFrom(byte[])
从byte[]
获取对象这是否回答了您的问题@Eric Anderson很抱歉造成混淆,我对问题进行了编辑以进一步解释。请按照其他答案进行操作。使用Contexts.interceptCall()。上下文附加/分离遵循调用堆栈,因此如果没有在同一方法中进行分离,则无法附加它。在您的情况下,您可以在初始interceptCall()期间在上下文中放置一些可变的对象(例如,AtomicReference、SettableFuture、custom对象),然后在onMessage()中对该对象进行突变。
3289640 [grpc-default-executor-0] ERROR i.g.ThreadLocalContextStorage - Context was not attached when detaching
java.lang.Throwable: null
at io.grpc.ThreadLocalContextStorage.detach(ThreadLocalContextStorage.java:48)
at io.grpc.Context.detach(Context.java:421)
at io.grpc.Context$CancellableContext.detach(Context.java:761)
at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:39)
at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:123)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)