gRPC學(xué)習(xí)記錄(五)--攔截器分析

gRPC學(xué)習(xí)記錄(五)--攔截器分析

標(biāo)簽(空格分隔): javaWEB


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

1.一個(gè)攔截器的小例子

在分析之前先看一種設(shè)計(jì).

有一個(gè)接口如下:

/**
 * 主調(diào)用接口
 */
public abstract class Client {
    public abstract void start(String say);
}
/**
 * 上述接口實(shí)現(xiàn)類
 */
public class ClientImp extends Client {
    @Override
    public void start(String say) {
        System.out.println(say);
    }
}

對(duì)此接口相關(guān)的轉(zhuǎn)換器:

/**
 * 用于包裝Client到另一個(gè)Client
 */
public abstract class ForwardingClient extends Client{
    //要包裝的對(duì)象
    protected abstract Client delegate();

    @Override
    public void start(String say) {
        delegate().start(say);
    }
}
/**
 * 一個(gè)簡(jiǎn)單的包裝實(shí)現(xiàn)類,必須要傳入要包裝的對(duì)象
 */
public class ForwardingClientImpl extends ForwardingClient{

    //被委托對(duì)象
    private final Client client;

    public ForwardingClientImpl(Client client) {
        this.client = client;
    }

    @Override
    protected Client delegate() {
        return client;
    }
}

然后在下列方法中調(diào)用:

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

毫無(wú)疑問會(huì)輸出

攔截器2
攔截器1
這是要執(zhí)行的方法

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

2.gRPC的ClientCall

該抽象類就是用來調(diào)用遠(yuǎn)程方法的,實(shí)現(xiàn)了發(fā)送消息和接收消息的功能,該接口由兩個(gè)泛型ReqT和ReqT,分別對(duì)應(yīng)著請(qǐng)求發(fā)送的信息,和請(qǐng)求收到的回復(fù).
ClientCall抽象類主要有兩個(gè)部分組成,一是public abstract static class Listener<T>用于監(jiān)聽服務(wù)端回復(fù)的消息,另一部分是針對(duì)客戶端請(qǐng)求調(diào)用的一系列過程,如下代碼流程所示:
該類中方法都是抽象方法,規(guī)定了整個(gè)調(diào)用順序,如下:

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,然后實(shí)現(xiàn)委托嵌套調(diào)用,里面方法都如下代碼所示:

@Override
  public void start(Listener<RespT> responseListener, Metadata headers) {
    delegate().start(responseListener, headers);
  }

  @Override
  public void request(int numMessages) {
    delegate().request(numMessages);
  }

那和之前的Demo一對(duì)比,攔截器怎么使用就變得很容易了.
創(chuàng)建一個(gè)客戶端攔截器,其中為header添加了token參數(shù).之所以要實(shí)現(xiàn)ClientInterceptor接口,因?yàn)镃hannel本身也是可以嵌套的類,所以創(chuàng)建ClientCall也是被一層一層的調(diào)用.

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

調(diào)用輸出如下:

創(chuàng)建client1
攔截器1,在此可以對(duì)header參數(shù)進(jìn)行修改

這是針對(duì)客戶端調(diào)用前的攔截,對(duì)于客戶端收到的回復(fù)攔截則通過ClientCall的靜態(tài)內(nèi)部類Listener來實(shí)現(xiàn),該Listener也是可以嵌套的,其內(nèi)有如下方法:

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

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

            @Override
            public void start(Listener<RespT> responseListener, Metadata headers) {
                System.out.println("攔截器1,在此可以對(duì)header參數(shù)進(jìn)行修改");
                Metadata.Key<String> token = Metadata.Key.of("token",Metadata.ASCII_STRING_MARSHALLER);
                headers.put(token,"123456");
                Listener<RespT> forwardListener = new ForwardingClientCallListener.
                        SimpleForwardingClientCallListener<RespT>(responseListener) {
                    @Override
                    public 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("返回參數(shù)無(wú)token,關(guān)閉該鏈接");
                            super.onClose(Status.DATA_LOSS,headers);
                        }
                        super.onHeaders(headers);
                    }
                };
                super.start(forwardListener, headers);
            }

最后再Channel創(chuàng)建的時(shí)候使用intercept(new ClientInterruptImpl())加入攔截器這樣就簡(jiǎn)單實(shí)現(xiàn)了客戶端的攔截了.


3.gRPC的ServerCall

有一點(diǎn)要搞明白,ClientCall是針對(duì)客戶端要調(diào)用的方法的,而ServerCall是針對(duì)ClientCall的.看如下例子:

public class ServerInterruptImpl  implements ServerInterceptor{
    @Override
    public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call,
                                                                 Metadata headers, ServerCallHandler<ReqT, RespT> next) {
        System.out.println("執(zhí)行server攔截器1,獲取token");
        //獲取客戶端參數(shù)
        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,關(guān)閉此連接");
            call.close(Status.DATA_LOSS,headers);
        }
        //服務(wù)端寫回參數(shù)
        ServerCall<ReqT, RespT> serverCall = new ForwardingServerCall.SimpleForwardingServerCall<ReqT, RespT>(call) {
            @Override
            public void sendHeaders(Metadata headers) {
                System.out.println("執(zhí)行server攔截器2,寫入token");
                headers.put(token,tokenStr);
                super.sendHeaders(headers);
            }
        };
        return next.startCall(serverCall,headers);
    }
}

當(dāng)服務(wù)端接收到請(qǐng)求的時(shí)候就會(huì)打印出來如下的日志.這樣就實(shí)現(xiàn)了服務(wù)端接手前的攔截和寫回時(shí)的攔截.

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

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

附錄:

相關(guān)代碼: https://github.com/nl101531/JavaWEB

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末涩禀,一起剝皮案震驚了整個(gè)濱河市料滥,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌艾船,老刑警劉巖葵腹,帶你破解...
    沈念sama閱讀 222,729評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件需曾,死亡現(xiàn)場(chǎng)離奇詭異读宙,居然都是意外死亡私股,警方通過查閱死者的電腦和手機(jī)价匠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,226評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門庄吼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來麦牺,“玉大人寒亥,你說我怎么就攤上這事洒忧≡耸冢” “怎么了烤惊?”我有些...
    開封第一講書人閱讀 169,461評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)吁朦。 經(jīng)常有香客問我柒室,道長(zhǎng),這世上最難降的妖魔是什么逗宜? 我笑而不...
    開封第一講書人閱讀 60,135評(píng)論 1 300
  • 正文 為了忘掉前任雄右,我火速辦了婚禮,結(jié)果婚禮上纺讲,老公的妹妹穿的比我還像新娘擂仍。我一直安慰自己,他們只是感情好刻诊,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,130評(píng)論 6 398
  • 文/花漫 我一把揭開白布防楷。 她就那樣靜靜地躺著,像睡著了一般则涯。 火紅的嫁衣襯著肌膚如雪复局。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,736評(píng)論 1 312
  • 那天粟判,我揣著相機(jī)與錄音亿昏,去河邊找鬼。 笑死档礁,一個(gè)胖子當(dāng)著我的面吹牛角钩,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 41,179評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼递礼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼惨险!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起脊髓,我...
    開封第一講書人閱讀 40,124評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤辫愉,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后将硝,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體恭朗,經(jīng)...
    沈念sama閱讀 46,657評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,723評(píng)論 3 342
  • 正文 我和宋清朗相戀三年依疼,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了痰腮。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,872評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡律罢,死狀恐怖膀值,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情弟翘,我是刑警寧澤虫腋,帶...
    沈念sama閱讀 36,533評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站稀余,受9級(jí)特大地震影響悦冀,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜睛琳,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,213評(píng)論 3 336
  • 文/蒙蒙 一盒蟆、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧师骗,春花似錦历等、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,700評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至黍少,卻和暖如春寡夹,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背厂置。 一陣腳步聲響...
    開封第一講書人閱讀 33,819評(píng)論 1 274
  • 我被黑心中介騙來泰國(guó)打工菩掏, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人昵济。 一個(gè)月前我還...
    沈念sama閱讀 49,304評(píng)論 3 379
  • 正文 我出身青樓智绸,卻偏偏與公主長(zhǎng)得像野揪,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子瞧栗,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,876評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理斯稳,服務(wù)發(fā)現(xiàn),斷路器沼溜,智...
    卡卡羅2017閱讀 134,716評(píng)論 18 139
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,331評(píng)論 25 707
  • 從三月份找實(shí)習(xí)到現(xiàn)在平挑,面了一些公司,掛了不少系草,但最終還是拿到小米、百度唆涝、阿里找都、京東、新浪廊酣、CVTE能耻、樂視家的研發(fā)崗...
    時(shí)芥藍(lán)閱讀 42,280評(píng)論 11 349
  • 又是一年清明節(jié),對(duì)于在帝都打拼的大部分人來說亡驰,也許清明節(jié)只是多了一個(gè)小長(zhǎng)假晓猛,可以出去游玩,與朋友聚會(huì)凡辱,或者在家休息...
    Michellesept閱讀 566評(píng)論 1 4
  • 想了很久透乾,如題洪燥。 在這里,我絕對(duì)不想說太多乳乌,我簡(jiǎn)單說一個(gè)小故事捧韵。 知了媽業(yè)余教小朋友畫畫,高大上一些就是“創(chuàng)意兒童...
    知了媽閱讀 280評(píng)論 0 0