rpc系列4-處理超時場景.及提供hook

問題:客戶端發(fā)起遠程調(diào)用,如果服務端長時間不返回怎么辦鞠苟?

這就涉及到一個調(diào)用超時的問題乞榨,平時我們應用中很多場景都會規(guī)定超時時間,比如:sql查詢超時当娱,http請求超時等吃既。那么如果服務端方法執(zhí)行的時間超過規(guī)定的timeout時間,那么客戶端就需要調(diào)出當前調(diào)用跨细,拋出TimeoutException鹦倚。

好了,下面開始對RpcBuidler進行改造了冀惭,讓其支持超時情況的處理震叙。同樣掀鹅,先給出預期的測試方案和結果:

// 業(yè)務類UserService在之前的基礎上增加超時調(diào)用的方法:
public interface UserService {
    
    // other method
    
    /**
     * 超時測試
     */
    public boolean timeoutTest();
    
}
//實現(xiàn)類
public class UserServiceImpl implements UserService {
    
     // other method
    
    @Override
    public boolean timeoutTest() {
        try {
            //模擬長時間執(zhí)行
            Thread.sleep(10 * 1000);
        } catch (InterruptedException e) {}
        return true;
    }
}

ClientTest中測試代碼:

    @Test
    public void timeoutTest(){
        long beginTime = System.currentTimeMillis();
        try {
            boolean result = userService.timeoutTest(); 
        } catch (Exception e) {
            long period = System.currentTimeMillis() - beginTime;
            System.out.println("period:" + period);
            Assert.assertTrue(period < 3100);
        }
    }

有了異步方法的實現(xiàn)經(jīng)驗,其實這個超時處理過程和異步非常類似捐友,都是利用Future機制來實現(xiàn)的淫半,下面對doInvoke方法進行重構,返回一個異步任務:

    private Future<RpcResponse> doInvoke(final RpcRequest request) throws IOException, ClassNotFoundException{

        //構造并提交FutureTask異步任務
        Future<RpcResponse> retVal = (Future<RpcResponse>) handlerPool.submit(new Callable<RpcResponse>(){
            @Override
            public RpcResponse call() throws Exception {
                Object res = null;
                try{
                    //創(chuàng)建連接,獲取輸入輸出流
                    Socket socket = new Socket(host,port);
                    try{
                        ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
                        ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
                        try{
                            //發(fā)送
                            out.writeObject(request);
                            //接受server端的返回信息---阻塞
                            res = in.readObject();
                        }finally{
                            out.close();
                            in.close();
                        }
                    }finally{
                        socket.close();
                    }
                }catch(Exception e){
                    throw e;
                }
                return (RpcResponse)res;
            }
        });
        return retVal;
    }

回調(diào)方法invoke修改如下:

    @Override
    public Object invoke(Object proxy, Method method,
            Object[] args) throws Throwable {
        //如果是異步方法,立即返回null
        if(asyncMethods.get().contains(method.getName())) return null;
        Object retVal = null;

        RpcRequest request = new RpcRequest(method.getName(), method.getParameterTypes(),args,RpcContext.getAttributes());
        RpcResponse rpcResp  = null;
        try{
            Future<RpcResponse> response = doInvoke(request);
            //獲取異步結果
            rpcResp  = (RpcResponse)response.get(TIMEOUT,TimeUnit.MILLISECONDS);
        }catch(TimeoutException e){
            throw e;
        }catch(Exception e){}
        
        if(!rpcResp.isError()){
            retVal = rpcResp.getResponseBody();
        }else{
            throw new RpcException(rpcResp.getErrorMsg());
        }
        return retVal;
    }

可見匣砖,經(jīng)過這樣改造后科吭,所有的方法調(diào)用都是通過Future獲取結果。

提供Hook猴鲫,讓開發(fā)人員進行RPC層面的AOP对人。

首先看下題目提供的Hook接口:

public interface ConsumerHook {
    public void before(RpcRequest request);
    public void after(RpcRequest request);
}
//實現(xiàn)類
public class UserConsumerHook implements ConsumerHook{
    @Override
    public void before(RpcRequest request) {
        RpcContext.addAttribute("hook key","this is pass by hook");
    }

    @Override
    public void after(RpcRequest request) {
        System.out.println("I have finished Rpc calling.");
    }
}

hook實現(xiàn)的功能很簡單,即在客戶端進行遠程調(diào)用的前后執(zhí)行before和after方法拂共。

public final class RpcConsumer implements InvocationHandler{

    //牺弄。。宜狐。
    
    //鉤子
    private ConsumerHook hook;

    public RpcConsumer hook(ConsumerHook hook){
        this.hook = hook;
        return this;
    }

static{
        userService = (UserService)consumer.targetHostPort(host, port)
                            .interfaceClass(UserService.class)
                            .timeout(TIMEOUT)
                            .hook(new UserConsumerHook())//新增鉤子
                            .newProxy();
    }
//势告。。抚恒。
}

//UserServiceImpl中的測試方法
public Map<String, Object> getMap() {
        Map<String,Object> newMap = new HashMap<String,Object>();
        newMap.put("name","getMap");
        newMap.putAll(RpcContext.getAttributes());
        return newMap;
}

我們只需要在doInvoke方法開始出添加鉤子函數(shù)的執(zhí)行邏輯即可咱台。如下:

    private Future<RpcResponse> doInvoke(final RpcRequest request) throws IOException, ClassNotFoundException{
        //插入鉤子
        hook.before(request);
        //。俭驮。回溺。
}

同時在asyncCall和invoke方法的結束添加after的執(zhí)行邏輯。具體實現(xiàn)可以看源碼混萝。

github附上源碼

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末遗遵,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子逸嘀,更是在濱河造成了極大的恐慌车要,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,042評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件崭倘,死亡現(xiàn)場離奇詭異屯蹦,居然都是意外死亡,警方通過查閱死者的電腦和手機绳姨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評論 2 384
  • 文/潘曉璐 我一進店門登澜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人飘庄,你說我怎么就攤上這事脑蠕。” “怎么了?”我有些...
    開封第一講書人閱讀 156,674評論 0 345
  • 文/不壞的土叔 我叫張陵谴仙,是天一觀的道長迂求。 經(jīng)常有香客問我,道長晃跺,這世上最難降的妖魔是什么揩局? 我笑而不...
    開封第一講書人閱讀 56,340評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮掀虎,結果婚禮上凌盯,老公的妹妹穿的比我還像新娘。我一直安慰自己烹玉,他們只是感情好驰怎,可當我...
    茶點故事閱讀 65,404評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著二打,像睡著了一般县忌。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上继效,一...
    開封第一講書人閱讀 49,749評論 1 289
  • 那天症杏,我揣著相機與錄音,去河邊找鬼瑞信。 笑死鸳慈,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的喧伞。 我是一名探鬼主播,決...
    沈念sama閱讀 38,902評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼绩郎,長吁一口氣:“原來是場噩夢啊……” “哼潘鲫!你這毒婦竟也來了?” 一聲冷哼從身側響起肋杖,我...
    開封第一講書人閱讀 37,662評論 0 266
  • 序言:老撾萬榮一對情侶失蹤溉仑,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后状植,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體浊竟,經(jīng)...
    沈念sama閱讀 44,110評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年津畸,在試婚紗的時候發(fā)現(xiàn)自己被綠了振定。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,577評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡肉拓,死狀恐怖后频,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤卑惜,帶...
    沈念sama閱讀 34,258評論 4 328
  • 正文 年R本政府宣布膏执,位于F島的核電站,受9級特大地震影響露久,放射性物質(zhì)發(fā)生泄漏更米。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,848評論 3 312
  • 文/蒙蒙 一毫痕、第九天 我趴在偏房一處隱蔽的房頂上張望征峦。 院中可真熱鬧,春花似錦镇草、人聲如沸眶痰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽竖伯。三九已至,卻和暖如春因宇,著一層夾襖步出監(jiān)牢的瞬間七婴,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評論 1 264
  • 我被黑心中介騙來泰國打工察滑, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留打厘,地道東北人。 一個月前我還...
    沈念sama閱讀 46,271評論 2 360
  • 正文 我出身青樓贺辰,卻偏偏與公主長得像户盯,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子饲化,可洞房花燭夜當晚...
    茶點故事閱讀 43,452評論 2 348

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

  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理莽鸭,服務發(fā)現(xiàn),斷路器吃靠,智...
    卡卡羅2017閱讀 134,628評論 18 139
  • 靜(嫻靜)女其姝硫眨,俟我于城隅(城角)。 愛(隱藏)而不見巢块,搔首踟躕礁阁。 靜女其孌,貽我彤管(紅管草)族奢。 彤管有煒(紅...
    ananli閱讀 588評論 0 0
  • 花開的季節(jié)姥闭,很是喜歡去看花,特別是成片成片的花海越走。置身于花叢中泣栈,近距離接觸花兒們,或嬌艷或素雅,或熱烈或清...
    溫暖的簡閱讀 419評論 2 4