netty源码解析-前言(2)为什么用netty

导读

原创文章,转载请注明出处。

本文源码地址: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);
                                //打印客户端发来的数据
                                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中的线程,这里我们把线程数量设置为1。
  • serverBootstrap.bind(8000).sync():绑定到8000端口,相当于上一篇中com.zhongdaima.netty.analysis.part0.jdk.nio.HelloNioServer绑定到8000端口。

  • serverBootstrap.childHandler():这里我们添加了一个ChannelInitializer,并在initChannel中添加了一个匿名handler,这个匿名handler就是我们的主要业务逻辑,接收到客户端发来的请求,并添加上“hello, ”发送回去。相当于上一篇中的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);
                            //打印服务端返回数据
                            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++) {
                //循环向服务端发送“zhongdaima" + 客户端编号
                clients[i].writeAndFlush(Unpooled.wrappedBuffer(("zhongdaima" + i).getBytes()));
            }
            Thread.sleep(1000);
        }
    }
}

该客户端创建了两条连接,然后循环向服务端发送“zhongdaima” + 客户端编号,接收到服务端数据后打印。比较简单,不再赘述。

2 netty vs jdk

与上一节用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

  • 代码复杂:大家已经看到了,代码太多。

  • 学习成本高:使用jdk原生api需要熟练掌握Selector、ByteBuffer等,需要具备非常高超的能力才能写出健壮代码。

  • api复杂不友好:jdk ByteBuffer类的api不够友好,必须非常小心才不会出错。

  • 没有配套设施:我们知道TCP是基于流的协议,而我们的应用发送数据是基于帧的,也就说我们需要手动从TCP流中拆出我们的“Reqeust”、“Response”等,非常复杂。

2.2 为什么选择netty

  • 代码简洁:大家已经看到了,与jdk原生api相比,代码量如何一看便知。

  • 学习成本低:netty对jdk api封装后,屏蔽了某些概念,如Selector。demo丰富,按照netty文档学习2小时轻松上手。

  • api更简单友好:netty的ByteBuf类比jdk的ByteBuffer好用太多,用了就知道。无需和Selector打交道,由netty自动完成。

  • 周边配套完善:netty并不是简单地封装了jdk的io api,还提供了丰富的周边配套,例如丰富的内置编解码器(http、redis等等)开箱即用。而且还有Abstract类型的编解码器接口,轻松构建私有协议编解码器。使用内置的IdleStateHandler轻松完成长连接心跳功能。

  • 知名项目/知名大厂都在用:群众的眼睛是雪亮的,历经众多项目的考验,稳定性高。

3 我用netty

我在两年前入职转转,负责公司RPC框架开发,当时公司的RPC框架客户端真的是用jdk原生nio写的。我很佩服前辈能用jdk原生api写代码,这么多年了代码依然有bug,不优雅。终于在入两个月后我忍不住用netty重构了,我删除了差不多20个类,新增了个6个类完成了这次重构工作,约摸估计减少上千行代码。看着清爽的代码,心情很美丽。

4 总结

上面都说了这么多,还用说啥,一起开始学习吧,关注我,及时获取最新文章。


关于作者

王建新,转转架构部资深Java工程师,主要负责服务治理、RPC框架、分布式调用跟踪、监控系统等。爱技术、爱学习,欢迎联系交流。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,258评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,335评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,225评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,126评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,140评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,098评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,018评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,857评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,298评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,518评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,400评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,993评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,638评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,661评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352

推荐阅读更多精彩内容