日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

gRPC学习记录(五)--拦截器分析

發布時間:2025/3/15 编程问答 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 gRPC学习记录(五)--拦截器分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

對于此類調用攔截器是必不可少的,本篇就分析下攔截器的實現.(博主本來想分析源碼的,但是水平不足,并發知識欠缺,看的不是很懂,哎,仍需努力),另外貌似不同版本有些差異,這里使用的是1.0.3版本.

1.一個攔截器的小例子

在分析之前先看一種設計.

有一個接口如下:

/*** 主調用接口*/ public abstract class Client {public abstract void start(String say); } /*** 上述接口實現類*/ public class ClientImp extends Client {@Overridepublic void start(String say) {System.out.println(say);} }

對此接口相關的轉換器:

/*** 用于包裝Client到另一個Client*/ public abstract class ForwardingClient extends Client{//要包裝的對象protected abstract Client delegate();@Overridepublic void start(String say) {delegate().start(say);} } /*** 一個簡單的包裝實現類,必須要傳入要包裝的對象*/ public class ForwardingClientImpl extends ForwardingClient{//被委托對象private final Client client;public ForwardingClientImpl(Client client) {this.client = client;}@Overrideprotected Client delegate() {return client;} }

然后在下列方法中調用:

public class InterceptTest {public static void main(String[] args) {Client client = new ClientImp();//主要想執行的方法//構造第一個攔截器Client intercept1 = new ForwardingClientImpl(client){@Overridepublic void start(String say) {System.out.println("攔截器1");super.start(say);}};//構造第二個攔截器Client intercept2 = new ForwardingClientImpl(intercept1){@Overridepublic void start(String say) {System.out.println("攔截器2");super.start(say);}};//執行主方法intercept2.start("這是要執行的方法");} }

毫無疑問會輸出

攔截器2 攔截器1 這是要執行的方法

分析一下針對Client接口,通過ForwardingClient可以實現自身的嵌套調用,從而達到了類似攔截器的效果.在gRPC中有很多類似的嵌套類,其本質和上面差不多,上面例子有助于對gRPC攔截器的掌握.

2.gRPC的ClientCall

該抽象類就是用來調用遠程方法的,實現了發送消息和接收消息的功能,該接口由兩個泛型ReqT和ReqT,分別對應著請求發送的信息,和請求收到的回復.
ClientCall抽象類主要有兩個部分組成,一是public abstract static class Listener<T>用于監聽服務端回復的消息,另一部分是針對客戶端請求調用的一系列過程,如下代碼流程所示:
該類中方法都是抽象方法,規定了整個調用順序,如下:

call = channel.newCall(unaryMethod, callOptions); call.start(listener, headers); call.sendMessage(message); call.halfClose(); call.request(1); // wait for listener.onMessage()

在ClientCall的子類中有ForwardingClientCall<ReqT, RespT>,該類的作用和之前的Demo一樣,用于包裝ClientCall,然后實現委托嵌套調用,里面方法都如下代碼所示:

@Overridepublic void start(Listener<RespT> responseListener, Metadata headers) {delegate().start(responseListener, headers);}@Overridepublic void request(int numMessages) {delegate().request(numMessages);}

那和之前的Demo一對比,攔截器怎么使用就變得很容易了.
創建一個客戶端攔截器,其中為header添加了token參數.之所以要實現ClientInterceptor接口,因為Channel本身也是可以嵌套的類,所以創建ClientCall也是被一層一層的調用.

/*** 客戶端攔截器* @author Niu Li* @date 2017/2/4*/ //ClientInterceptor接口是針對ClientCall的創建進行攔截 public class ClientInterruptImpl implements ClientInterceptor {@Overridepublic <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(MethodDescriptor<ReqT, RespT> method,CallOptions callOptions, Channel next) {//創建clientSystem.out.println("創建client1");ClientCall<ReqT,RespT> clientCall = next.newCall(method,callOptions);return new ForwardingClientCall<ReqT, RespT>() {@Overrideprotected ClientCall<ReqT, RespT> delegate() {return clientCall;}@Overridepublic void start(Listener<RespT> responseListener, Metadata headers) {System.out.println("攔截器1,在此可以對header參數進行修改");Metadata.Key<String> token = Metadata.Key.of("token",Metadata.ASCII_STRING_MARSHALLER);headers.put(token,"123456");super.start(responseListener, headers);}};} }

調用輸出如下:

創建client1 攔截器1,在此可以對header參數進行修改

這是針對客戶端調用前的攔截,對于客戶端收到的回復攔截則通過ClientCall的靜態內部類Listener來實現,該Listener也是可以嵌套的,其內有如下方法:

public void onHeaders(Metadata headers) {} public void onMessage(T message) {} public void onClose(Status status, Metadata trailers) {} public void onReady() {}

對之前start方法改造下,讓其判斷返回的header中有沒有傳送過去的token,沒有則該請求視為失敗.

@Overridepublic void start(Listener<RespT> responseListener, Metadata headers) {System.out.println("攔截器1,在此可以對header參數進行修改");Metadata.Key<String> token = Metadata.Key.of("token",Metadata.ASCII_STRING_MARSHALLER);headers.put(token,"123456");Listener<RespT> forwardListener = new ForwardingClientCallListener.SimpleForwardingClientCallListener<RespT>(responseListener) {@Overridepublic void onHeaders(Metadata headers) {Metadata.Key<String> token = Metadata.Key.of("token",Metadata.ASCII_STRING_MARSHALLER);if (!"123456".equals(headers.get(token))){System.out.println("返回參數無token,關閉該鏈接");super.onClose(Status.DATA_LOSS,headers);}super.onHeaders(headers);}};super.start(forwardListener, headers);}

最后再Channel創建的時候使用intercept(new ClientInterruptImpl())加入攔截器這樣就簡單實現了客戶端的攔截了.


3.gRPC的ServerCall

有一點要搞明白,ClientCall是針對客戶端要調用的方法的,而ServerCall是針對ClientCall的.看如下例子:

public class ServerInterruptImpl implements ServerInterceptor{@Overridepublic <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call,Metadata headers, ServerCallHandler<ReqT, RespT> next) {System.out.println("執行server攔截器1,獲取token");//獲取客戶端參數Metadata.Key<String> token = Metadata.Key.of("token", Metadata.ASCII_STRING_MARSHALLER);String tokenStr = headers.get(token);if (StringUtil.isNullOrEmpty(tokenStr)){System.out.println("未收到客戶端token,關閉此連接");call.close(Status.DATA_LOSS,headers);}//服務端寫回參數ServerCall<ReqT, RespT> serverCall = new ForwardingServerCall.SimpleForwardingServerCall<ReqT, RespT>(call) {@Overridepublic void sendHeaders(Metadata headers) {System.out.println("執行server攔截器2,寫入token");headers.put(token,tokenStr);super.sendHeaders(headers);}};return next.startCall(serverCall,headers);} }

當服務端接收到請求的時候就會打印出來如下的日志.這樣就實現了服務端接手前的攔截和寫回時的攔截.

執行server攔截器1,獲取token 收到的信息:world:0 執行server攔截器2,寫入token

關于更多使用還在琢磨中,目前欠缺并發知識,所以下一步打算看看并發相關的資料.

附錄:

相關代碼: https://github.com/nl101531/JavaWEB



作者:此博廢棄_更新在個人博客
鏈接:https://www.jianshu.com/p/6a2f6db0a967
來源:簡書

著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。


總結

以上是生活随笔為你收集整理的gRPC学习记录(五)--拦截器分析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。