netty源碼解析-前言(2)為什么用netty

導讀

原創(chuàng)文章哆键,轉(zhuǎn)載請注明出處模软。

本文源碼地址:netty-source-code-analysis

為什么用netty衰絮?因為dubbo吻育、sofa-rpc做个、rocketMQ、jetty等知名的的項目都在用,就是這么簡單拨与。平時我們在遇到技術難題的時候契邀,第1個想法是什么呢:看看別人怎么搞的。我們在和同事爭論技術方案的時候乃戈,最常說的一句話是什么:XXX(某知名框架/某知名公司)也是這么做的。思路沒問題,看看別人怎么做的策泣,尤其是知名權威的項目/公司是怎么做的,借鑒一下抬吟,這是最快速的解決問題的方式萨咕。

1 用netty 寫個NIO Hello World

1.1 netty版本的NIO服務端

/**
 * 歡迎關注公眾號“種代碼“,獲取博主微信深入交流
 *
 * @author wangjianxin
 */
public class HelloNettyServer {
    public static void main(String[] args) throws InterruptedException {
        //相當于com.zhongdaima.netty.analysis.part0.jdk.nio.NioServerConnector中的線程
        EventLoopGroup boss = new NioEventLoopGroup(1);
        //相當于com.zhongdaima.netty.analysis.part0.jdk.nio.NioServerHandler中的線程
        EventLoopGroup worker = new NioEventLoopGroup(1);
        ServerBootstrap serverBootstrap = new ServerBootstrap();
        serverBootstrap.group(boss, worker)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel ch) throws Exception {
                        ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {
                            @Override
                            public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                                byte[] bytes = new byte[((ByteBuf) msg).readableBytes()];
                                ((ByteBuf) msg).readBytes(bytes);
                                String name = new String(bytes);
                                //打印客戶端發(fā)來的數(shù)據(jù)
                                System.out.println(name);
                                ctx.writeAndFlush(Unpooled.wrappedBuffer(("hello, " + name).getBytes()));
                            }
                        });
                    }
                });
        //綁定到8000端口
        ChannelFuture future = serverBootstrap.bind(8000).sync();
        //等待channel關閉
        future.channel().closeFuture().syncUninterruptibly();
    }
}
  • NioEventLoopGroup:就是一組線程火本,boss就相當于上一篇中com.zhongdaima.netty.analysis.part0.jdk.nio.NioServerConnector中的線程危队,而worker就相當于上一篇com.zhongdaima.netty.analysis.part0.jdk.nio.NioServerHandler中的線程,這里我們把線程數(shù)量設置為1钙畔。
  • serverBootstrap.bind(8000).sync():綁定到8000端口茫陆,相當于上一篇中com.zhongdaima.netty.analysis.part0.jdk.nio.HelloNioServer綁定到8000端口。

  • serverBootstrap.childHandler():這里我們添加了一個ChannelInitializer擎析,并在initChannel中添加了一個匿名handler簿盅,這個匿名handler就是我們的主要業(yè)務邏輯,接收到客戶端發(fā)來的請求,并添加上“hello, ”發(fā)送回去桨醋。相當于上一篇中的com.zhongdaima.netty.analysis.part0.jdk.nio.NioServerHandler棚瘟。

1.2 netty版本的NIO客戶端

/**
 * 歡迎關注公眾號“種代碼“,獲取博主微信深入交流
 *
 * @author wangjianxin
 */
public class HelloNettyClient {
    private static final int CLIENTS = 2;
    private static final EventLoopGroup EVENT_LOOP_GROUP = new NioEventLoopGroup(1);

    public static void main(String[] args) throws InterruptedException {
        //用來保存兩個客戶端
        Channel[] clients = new Channel[CLIENTS];
        for (int i = 0; i < CLIENTS; i++) {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.channel(NioSocketChannel.class)
                    .group(EVENT_LOOP_GROUP)
                    .handler(new ChannelInboundHandlerAdapter() {
                        @Override
                        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                            byte[] bytes = new byte[((ByteBuf) msg).readableBytes()];
                            ((ByteBuf) msg).readBytes(bytes);
                            //打印服務端返回數(shù)據(jù)
                            System.out.println(new String(bytes));
                        }
                    });
            //連接8000端口
            clients[i] = bootstrap.connect(new InetSocketAddress(8000)).sync().channel();
        }
        while (true) {
            for (int i = 0; i < clients.length; i++) {
                //循環(huán)向服務端發(fā)送“zhongdaima" + 客戶端編號
                clients[i].writeAndFlush(Unpooled.wrappedBuffer(("zhongdaima" + i).getBytes()));
            }
            Thread.sleep(1000);
        }
    }
}

該客戶端創(chuàng)建了兩條連接喜最,然后循環(huán)向服務端發(fā)送“zhongdaima” + 客戶端編號偎蘸,接收到服務端數(shù)據(jù)后打印。比較簡單瞬内,不再贅述迷雪。

2 netty vs jdk

與上一節(jié)用jdk原生api寫的demo比,大家看了用netty寫的demo之后有什么感受虫蝶?哇章咧,很清爽,很簡潔秉扑,比用jdk原生api寫的那一坨代碼友好太多了慧邮。這里用“一坨”來形容jdk原生api demo一點都不為過。

而netty也不僅僅是NIO舟陆,netty對于BIO误澳、NIO、AIO(異步io秦躯,netty5)抽象出了一套共同的api忆谓,我們只需要稍微修改代碼就可以將我們程序切換為BIO、NIO踱承、AIO中的一種倡缠。

2.1 為什么不用jdk原生api

  • 代碼復雜:大家已經(jīng)看到了,代碼太多茎活。

  • 學習成本高:使用jdk原生api需要熟練掌握Selector昙沦、ByteBuffer等,需要具備非常高超的能力才能寫出健壯代碼载荔。

  • api復雜不友好:jdk ByteBuffer類的api不夠友好盾饮,必須非常小心才不會出錯。

  • 沒有配套設施:我們知道TCP是基于流的協(xié)議懒熙,而我們的應用發(fā)送數(shù)據(jù)是基于幀的丘损,也就說我們需要手動從TCP流中拆出我們的“Reqeust”、“Response”等工扎,非常復雜徘钥。

2.2 為什么選擇netty

  • 代碼簡潔:大家已經(jīng)看到了,與jdk原生api相比肢娘,代碼量如何一看便知呈础。

  • 學習成本低:netty對jdk api封裝后舆驶,屏蔽了某些概念,如Selector猪落。demo豐富贞远,按照netty文檔學習2小時輕松上手畴博。

  • api更簡單友好:netty的ByteBuf類比jdk的ByteBuffer好用太多笨忌,用了就知道。無需和Selector打交道俱病,由netty自動完成官疲。

  • 周邊配套完善:netty并不是簡單地封裝了jdk的io api,還提供了豐富的周邊配套亮隙,例如豐富的內(nèi)置編解碼器(http途凫、redis等等)開箱即用。而且還有Abstract類型的編解碼器接口溢吻,輕松構建私有協(xié)議編解碼器维费。使用內(nèi)置的IdleStateHandler輕松完成長連接心跳功能。

  • 知名項目/知名大廠都在用:群眾的眼睛是雪亮的促王,歷經(jīng)眾多項目的考驗犀盟,穩(wěn)定性高。

3 我用netty

我在兩年前入職轉(zhuǎn)轉(zhuǎn)蝇狼,負責公司RPC框架開發(fā)阅畴,當時公司的RPC框架客戶端真的是用jdk原生nio寫的。我很佩服前輩能用jdk原生api寫代碼迅耘,這么多年了代碼依然有bug贱枣,不優(yōu)雅。終于在入兩個月后我忍不住用netty重構了颤专,我刪除了差不多20個類纽哥,新增了個6個類完成了這次重構工作,約摸估計減少上千行代碼栖秕〈核看著清爽的代碼,心情很美麗累魔。

4 總結

上面都說了這么多摔笤,還用說啥,一起開始學習吧垦写,關注我吕世,及時獲取最新文章。


關于作者

王建新梯投,轉(zhuǎn)轉(zhuǎn)架構部資深Java工程師命辖,主要負責服務治理况毅、RPC框架、分布式調(diào)用跟蹤尔艇、監(jiān)控系統(tǒng)等尔许。愛技術、愛學習终娃,歡迎聯(lián)系交流味廊。

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市棠耕,隨后出現(xiàn)的幾起案子余佛,更是在濱河造成了極大的恐慌,老刑警劉巖窍荧,帶你破解...
    沈念sama閱讀 219,366評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件辉巡,死亡現(xiàn)場離奇詭異,居然都是意外死亡蕊退,警方通過查閱死者的電腦和手機郊楣,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來瓤荔,“玉大人净蚤,你說我怎么就攤上這事≤怨保” “怎么了塞栅?”我有些...
    開封第一講書人閱讀 165,689評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長腔丧。 經(jīng)常有香客問我放椰,道長,這世上最難降的妖魔是什么愉粤? 我笑而不...
    開封第一講書人閱讀 58,925評論 1 295
  • 正文 為了忘掉前任砾医,我火速辦了婚禮,結果婚禮上衣厘,老公的妹妹穿的比我還像新娘如蚜。我一直安慰自己,他們只是感情好影暴,可當我...
    茶點故事閱讀 67,942評論 6 392
  • 文/花漫 我一把揭開白布错邦。 她就那樣靜靜地躺著,像睡著了一般型宙。 火紅的嫁衣襯著肌膚如雪撬呢。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,727評論 1 305
  • 那天妆兑,我揣著相機與錄音魂拦,去河邊找鬼毛仪。 笑死,一個胖子當著我的面吹牛芯勘,可吹牛的內(nèi)容都是我干的箱靴。 我是一名探鬼主播,決...
    沈念sama閱讀 40,447評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼荷愕,長吁一口氣:“原來是場噩夢啊……” “哼衡怀!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起路翻,我...
    開封第一講書人閱讀 39,349評論 0 276
  • 序言:老撾萬榮一對情侶失蹤狈癞,失蹤者是張志新(化名)和其女友劉穎茄靠,沒想到半個月后茂契,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,820評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡慨绳,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,990評論 3 337
  • 正文 我和宋清朗相戀三年掉冶,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片脐雪。...
    茶點故事閱讀 40,127評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡厌小,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出战秋,到底是詐尸還是另有隱情璧亚,我是刑警寧澤,帶...
    沈念sama閱讀 35,812評論 5 346
  • 正文 年R本政府宣布脂信,位于F島的核電站癣蟋,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏狰闪。R本人自食惡果不足惜疯搅,卻給世界環(huán)境...
    茶點故事閱讀 41,471評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望埋泵。 院中可真熱鬧幔欧,春花似錦、人聲如沸丽声。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽雁社。三九已至浴井,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間歧胁,已是汗流浹背滋饲。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評論 1 272
  • 我被黑心中介騙來泰國打工厉碟, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人屠缭。 一個月前我還...
    沈念sama閱讀 48,388評論 3 373
  • 正文 我出身青樓箍鼓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親呵曹。 傳聞我的和親對象是個殘疾皇子款咖,可洞房花燭夜當晚...
    茶點故事閱讀 45,066評論 2 355

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