netty與其應(yīng)用moco-runner的學(xué)習(xí)筆記

前言:
moco-runner是github上一個(gè)基于netty的mock開源項(xiàng)目
這里以Http服務(wù)啟動(dòng)時(shí)的moco-runner為例介紹
以Socket服務(wù)啟動(dòng)時(shí)基本處理邏輯是一致的

啟動(dòng)流程

Netty服務(wù)端創(chuàng)建時(shí)序圖

Netty服務(wù)端創(chuàng)建時(shí)序圖.png

結(jié)合Netty的Demo代碼

moco-runner封裝程度比較高涩赢,用Demo代碼結(jié)合上面的時(shí)序圖自己捋一下基礎(chǔ)實(shí)現(xiàn)

public class NettyDemo {    
    public static void main(String[] args) {
        NioEventLoopGroup boosGroup = new NioEventLoopGroup();
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();
        
        final ServerBootstrap serverBootstrap = new ServerBootstrap(); 
                // 1. 創(chuàng)建ServerBootStrap實(shí)例
                // 在moco-runner中 : MocoServer類 : start(final int port, final ChannelInitializer<? extends Channel> pipelineFactory)
        serverBootstrap
            .group(boosGroup, workerGroup)                                            
                // 2. 設(shè)置并綁定Reactor線程池:EventLoopGroup, EventLoop就是處理所有注冊(cè)到本線程的Selector上面的Channel
                // 在moco-runner中 : MocoServer類 : group = new NioEventLoopGroup(0, MocoExecutors.executor());
            .channel(NioServerSocketChannel.class)
                // 3. 設(shè)置并綁定服務(wù)端的channel
            .option(ChannelOption.SO_BACKLOG, 1024)
            .childOption(ChannelOption.SO_KEEPALIVE, true)
            .childOption(ChannelOption.TCP_NODELAY, true)
            .childHandler(new ChannelInitializer<SocketChannel>() {
                // 4和5. 創(chuàng)建處理網(wǎng)絡(luò)事件的ChannelPipeline和handler滑绒,網(wǎng)絡(luò)時(shí)間以流的形式在其中流轉(zhuǎn)蛤育,handler完成多數(shù)的功能定制:比如編解碼 SSl安全認(rèn)證
                // 在moco-runner中 : ServerRunner類 : ((MocoHttpServer)configuration).channelInitializer()
                // 在moco-runner中 : MocoHttpServer的channelInitializer實(shí)現(xiàn)如下(省略部分非關(guān)鍵代碼)
                private ActualHttpServer serverSetting;
                
                @Override
                protected void initChannel(SocketChannel ch) throws Exception {
                    ChannelPipeline pipeline = ch.pipeline();
                    pipeline.addFirst("ssl", serverSetting.sslHandler().get());
                    ServerConfig serverConfig = serverSetting.getServerConfig();
                    pipeline.addLast("codec", new HttpServerCodec(4096,
                            serverConfig.getHeaderSize(),
                            8192, false));
                    pipeline.addLast("aggregator", new HttpObjectAggregator(serverConfig.getContentLength()));
                    pipeline.addLast("handler", new MocoHandler(serverSetting));
                }
            });
        serverBootstrap.bind(8001);
                // 6. 綁定監(jiān)聽端口并啟動(dòng)服務(wù)端
    }
}

業(yè)務(wù)處理流程

moco-runner主Handler : MocoHandler

SimpleChannelInboundHandler

SimpleChannelInboundHandler<T>是用來接收解碼消息当船,并處理該數(shù)據(jù)業(yè)務(wù)邏輯的一個(gè)抽象類實(shí)現(xiàn)。
MocoHandler繼承自SimpleChannelInboundHandler<T>處理Mock流程
對(duì)于SimpleChannelInboundHandler<T>中的T為待處理的消息的Java類型

對(duì)于MocoHandler贤牛,所有Mock的業(yè)務(wù)邏輯都在channelRead0()中實(shí)現(xiàn)

MocoHandler的構(gòu)造器參數(shù)(ActualHttpServer)serverSetting從哪來碎乃?是什么?

回到MocoHandler的實(shí)例化過程:

  1. MocoHandler在MocoHttpServer類的channelInitializer方法中實(shí)例化鳖枕,構(gòu)造參數(shù)(ActualHttpServer)serverSetting又來自于MocoHttpServer的構(gòu)造器參數(shù)
  2. MocoHttpServer在Runner類的類方法runner(final HttpServer server)中被實(shí)例化魄梯,構(gòu)造參數(shù)(HttpServer)server又來自于runner方法的參數(shù)
  3. runner在StandaloneRunner類中的newRunner方法被調(diào)用
  4. newRunner方法在StandaloneRunner類中的run方法被調(diào)用
  5. run方法在JsonRunner類中的run方法被調(diào)用,參數(shù)(Server)server在JsonRunner的構(gòu)造方法中
    private JsonRunner(final Iterable<? extends RunnerSetting> settings, final StartArgs startArgs) {
        this.server = newServer(settings, startArgs);
    }

通過以下方法組裝

    private Server newServer(final Iterable<? extends RunnerSetting> settings, final StartArgs startArgs) {
        // 省略對(duì)Socket服務(wù)器的判斷與處理
        return createHttpServer(settings, startArgs);
    }
    private HttpServer createHttpServer(final Iterable<? extends RunnerSetting> settings, final StartArgs startArgs) {
        HttpServer targetServer = createBaseHttpServer(settings, startArgs);
        return targetServer;
    }
    private HttpServer createBaseHttpServer(final Iterable<? extends RunnerSetting> settings,
                                            final StartArgs startArgs) {
        HttpServer targetServer = createHttpServer(startArgs);
        // 遍歷settings
        for (RunnerSetting setting : settings) {
            // httpParser.parseServer()最終是在BaseActualServer類中處理配置文件json列表中的request/response匹配響應(yīng)配置(接口擋板配置)宾符,獲取對(duì)應(yīng)擋板配置的HttpServer實(shí)例
            HttpServer parsedServer = httpParser.parseServer(setting.getStreams(),
                    startArgs.getPort(), toConfigs(setting));
            // 合并parsedServer與原targetServer
            targetServer = mergeServer(targetServer, parsedServer);
        }
        return targetServer;
    }

其中

    private HttpServer createHttpServer(final StartArgs startArgs) {
        // 省略Https的情況
        return ActualHttpServer.createLogServer(startArgs.getPort().or(0));
    }

這里來看下最終返回的HttpServer對(duì)象targetServer酿秸,也就是MocoHandler類的構(gòu)造器參數(shù)(ActualHttpServer)serverSetting


HttpServer

它是mocorunner定義的一個(gè)接口,定義了post/get/put/delete/proxy等接口方法
而我們實(shí)際最終使用的ActualHttpServer類實(shí)例是它的一個(gè)子類魏烫,ActualHttpServer直接繼承自HttpConfiguration辣苏,
而HttpConfiguration實(shí)現(xiàn)了HttpServer接口的同時(shí)又繼承自BaseActualServer

單從以上服務(wù)器的啟動(dòng)邏輯來看肝箱,BaseActualServer是我們目前更需要關(guān)注的類,
它的實(shí)例實(shí)際持有了擋板的配置項(xiàng)(List<Setting<T>>)settings稀蟋,
并可以通過BaseActualServer的mergeServer(final U thatServer)方法煌张,
將thatServer實(shí)例的settings合并到當(dāng)前BaseActualServer的實(shí)例中

MocoHandler類實(shí)例持有的屬性ImmutableList<Setting<HttpResponseSetting>> settings

看清楚以上邏輯后,這里就知道了MocoHandler持有的屬性settings退客,就是來自于前期經(jīng)過多次merge的BaseActualServer實(shí)例的settings骏融,保存的是擋板的配置項(xiàng)

這個(gè)settings在MocoHandler的業(yè)務(wù)處理方法
channelRead0(final ChannelHandlerContext ctx, final FullHttpRequest message)
的子調(diào)用
doGetHttpResponse(final HttpRequest request)
中被遍歷>匹配>命中則調(diào)用writeToResponse處理實(shí)際業(yè)務(wù)并作返回

        for (Setting setting : settings) {
            if (setting.match(request)) {
                logger.info(String.format("Response by setting : %s", setting.toString()));
                setting.writeToResponse(context);
                return httpResponse;
            }
        }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市萌狂,隨后出現(xiàn)的幾起案子档玻,更是在濱河造成了極大的恐慌,老刑警劉巖茫藏,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件误趴,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡务傲,警方通過查閱死者的電腦和手機(jī)凉当,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來树灶,“玉大人纤怒,你說我怎么就攤上這事糯而√焱ǎ” “怎么了?”我有些...
    開封第一講書人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵熄驼,是天一觀的道長(zhǎng)像寒。 經(jīng)常有香客問我,道長(zhǎng)瓜贾,這世上最難降的妖魔是什么诺祸? 我笑而不...
    開封第一講書人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮祭芦,結(jié)果婚禮上筷笨,老公的妹妹穿的比我還像新娘。我一直安慰自己龟劲,他們只是感情好胃夏,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著昌跌,像睡著了一般仰禀。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蚕愤,一...
    開封第一講書人閱讀 51,688評(píng)論 1 305
  • 那天答恶,我揣著相機(jī)與錄音饺蚊,去河邊找鬼。 笑死悬嗓,一個(gè)胖子當(dāng)著我的面吹牛污呼,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播包竹,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼曙求,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了映企?” 一聲冷哼從身側(cè)響起悟狱,我...
    開封第一講書人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎堰氓,沒想到半個(gè)月后挤渐,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡双絮,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年浴麻,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片囤攀。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡软免,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出焚挠,到底是詐尸還是另有隱情膏萧,我是刑警寧澤,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布蝌衔,位于F島的核電站榛泛,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏噩斟。R本人自食惡果不足惜曹锨,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望剃允。 院中可真熱鬧沛简,春花似錦、人聲如沸斥废。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽营袜。三九已至撒顿,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間荚板,已是汗流浹背凤壁。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來泰國(guó)打工吩屹, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人拧抖。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓煤搜,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親唧席。 傳聞我的和親對(duì)象是個(gè)殘疾皇子擦盾,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355