搭建生产级的Netty项目
Netty是Trustin Lee在2004年开发的一款高性能的网络应用程序框架。相比于JDK自带的NIO,Netty做了相当多的增强,且隔离了jdk nio的实现细节,API也比较友好,还支持流量整形等高级特性。在我们常见的一些开源项目中已经普遍的应用到了Netty,比如Dubbo、Elasticsearch、Zookeeper等。
Netty的具体开发
提示:因代码相对较多,这里只展示其主要部分,至于项目中用到的编解码器、工具类,请直接拉到最后下载源码!也欢迎顺手给个Star~
需要的依赖
<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>
<dependency>
    <groupId>io.dropwizard.metrics</groupId>
    <artifactId>metrics-core</artifactId>
    <version>4.1.1</version>
</dependency>
<dependency>
    <groupId>io.dropwizard.metrics</groupId>
    <artifactId>metrics-jmx</artifactId>
    <version>4.1.1</version>
</dependency>
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-all</artifactId>
    <version>4.1.29.Final</version>
</dependency>
Client端代码
package com.example.nettydemo.client;
import com.example.nettydemo.client.codec.*;
import com.example.nettydemo.client.codec.dispatcher.OperationResultFuture;
import com.example.nettydemo.client.codec.dispatcher.RequestPendingCenter;
import com.example.nettydemo.client.codec.dispatcher.ResponseDispatcherHandler;
import com.example.nettydemo.common.RequestMessage;
import com.example.nettydemo.common.string.StringOperation;
import com.example.nettydemo.util.IdUtil;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioChannelOption;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import javax.net.ssl.SSLException;
import java.util.concurrent.ExecutionException;
public class Client {
    public static void main(String[] args) throws InterruptedException, ExecutionException, SSLException {
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.channel(NioSocketChannel.class);
        //客户端连接服务器最大允许时间,默认为30s
        bootstrap.option(NioChannelOption.CONNECT_TIMEOUT_MILLIS, 30 * 1000); //10s
        NioEventLoopGroup group = new NioEventLoopGroup();
        try {
            bootstrap.group(group);
            RequestPendingCenter requestPendingCenter = new RequestPendingCenter();
            LoggingHandler loggingHandler = new LoggingHandler(LogLevel.INFO);
            bootstrap.handler(new ChannelInitializer<NioSocketChannel>() {
                @Override
                protected void initChannel(NioSocketChannel ch) throws Exception {
                    ChannelPipeline pipeline = ch.pipeline();
                    pipeline.addLast(new FrameDecoder());
                    pipeline.addLast(new FrameEncoder());
                    pipeline.addLast(new ProtocolEncoder());
                    pipeline.addLast(new ProtocolDecoder());
                    pipeline.addLast(new ResponseDispatcherHandler(requestPendingCenter));
                    pipeline.addLast(new OperationToRequestMessageEncoder());
//                    pipeline.addLast(loggingHandler);
                }
            });
            //连接服务
            ChannelFuture channelFuture = bootstrap.connect("127.0.0.1", 8888);
            //因为future是异步执行,所以需要先连接上后,再进行下一步操作
            channelFuture.sync();
            long streamId = IdUtil.nextId();
            /**
             * 发送数据测试,按照定义的规则组装数据
             */
//            OrderOperation orderOperation =  new OrderOperation(1001, "你好啊,hi");
            RequestMessage requestMessage = new RequestMessage(streamId, new StringOperation(1234, "你好啊,hi"));
            //将future放入center
            OperationResultFuture operationResultFuture = new OperationResultFuture();
            requestPendingCenter.add(streamId, operationResultFuture);
            //发送消息
            for (int i = 0; i < 10; i++) {
                channelFuture.channel().writeAndFlush(requestMessage);
            }
            //阻塞等待结果,结果来了之后会调用ResponseDispatcherHandler去set结果
//            OperationResult operationResult = operationResultFuture.get();
//            //将结果打印
//            System.out.println("返回:"+operationResult);
            channelFuture.channel().closeFuture().get();
        } finally {
            group.shutdownGracefully();
        }
    }
}
Server端代码
package com.example.nettydemo.server;
import com.example.nettydemo.server.codec.FrameDecoder;
import com.example.nettydemo.server.codec.FrameEncoder;
import com.example.nettydemo.server.codec.ProtocolDecoder;
import com.example.nettydemo.server.codec.ProtocolEncoder;
import com.example.nettydemo.server.handler.MetricsHandler;
import com.example.nettydemo.server.handler.ServerIdleCheckHandler;
import com.example.nettydemo.server.handler.ServerProcessHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioChannelOption;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.flush.FlushConsolidationHandler;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.traffic.GlobalTrafficShapingHandler;
import io.netty.util.concurrent.DefaultThreadFactory;
import io.netty.util.concurrent.UnorderedThreadPoolEventExecutor;
import lombok.extern.slf4j.Slf4j;
import javax.net.ssl.SSLException;
import java.security.cert.CertificateException;
import java.util.concurrent.ExecutionException;
/**
 * netty server 入口
 */
@Slf4j
public class Server {
    public static void main(String... args) throws InterruptedException, ExecutionException, CertificateException, SSLException {
        ServerBootstrap serverBootstrap = new ServerBootstrap();
        //设置channel模式,因为是server所以使用NioServerSocketChannel
        serverBootstrap.channel(NioServerSocketChannel.class);
        //最大的等待连接数量
        serverBootstrap.option(NioChannelOption.SO_BACKLOG, 1024);
        //设置是否启用 Nagle 算法:用将小的碎片数据连接成更大的报文 来提高发送效率。
        //如果需要发送一些较小的报文,则需要禁用该算法
        serverBootstrap.childOption(NioChannelOption.TCP_NODELAY, true);
        //设置netty自带的log,并设置级别
        serverBootstrap.handler(new LoggingHandler(LogLevel.INFO));
        //thread
        //用户指定线程名
        NioEventLoopGroup bossGroup = new NioEventLoopGroup(0, new DefaultThreadFactory("boss"));
        NioEventLoopGroup workGroup = new NioEventLoopGroup(0, new DefaultThreadFactory("worker"));
        UnorderedThreadPoolEventExecutor businessGroup = new UnorderedThreadPoolEventExecutor(10, new DefaultThreadFactory("business"));
        //只能使用一个线程,因GlobalTrafficShapingHandler比较轻量级
        NioEventLoopGroup eventLoopGroupForTrafficShaping = new NioEventLoopGroup(0, new DefaultThreadFactory("TS"));
        try {
            //设置react方式
            serverBootstrap.group(bossGroup, workGroup);
            //metrics
            MetricsHandler metricsHandler = new MetricsHandler();
            //trafficShaping流量整形
            //long writeLimit 写入时控制, long readLimit 读取时控制 具体设置看业务修改
            GlobalTrafficShapingHandler globalTrafficShapingHandler = new GlobalTrafficShapingHandler(eventLoopGroupForTrafficShaping, 10 * 1024 * 1024, 10 * 1024 * 1024);
            //log
            LoggingHandler debugLogHandler = new LoggingHandler(LogLevel.DEBUG);
            LoggingHandler infoLogHandler = new LoggingHandler(LogLevel.INFO);
            //设置childHandler,按执行顺序放
            serverBootstrap.childHandler(new ChannelInitializer<NioSocketChannel>() {
                @Override
                protected void initChannel(NioSocketChannel ch) throws Exception {
                    ChannelPipeline pipeline = ch.pipeline();
                    pipeline.addLast("debugLog", debugLogHandler);
                    pipeline.addLast("tsHandler", globalTrafficShapingHandler);
                    pipeline.addLast("metricHandler", metricsHandler);
                    pipeline.addLast("idleHandler", new ServerIdleCheckHandler());
                    pipeline.addLast("frameDecoder", new FrameDecoder());
                    pipeline.addLast("frameEncoder", new FrameEncoder());
                    pipeline.addLast("protocolDecoder", new ProtocolDecoder());
                    pipeline.addLast("protocolEncoder", new ProtocolEncoder());
                    pipeline.addLast("infoLog", infoLogHandler);
                    //对flush增强,减少flush次数牺牲延迟增强吞吐量
                    pipeline.addLast("flushEnhance", new FlushConsolidationHandler(10, true));
                    //为业务处理指定单独的线程池
                    pipeline.addLast(businessGroup, new ServerProcessHandler());//businessGroup,
                }
            });
            //绑定端口并阻塞启动
            ChannelFuture channelFuture = serverBootstrap.bind(8888).sync();
            channelFuture.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workGroup.shutdownGracefully();
            businessGroup.shutdownGracefully();
            eventLoopGroupForTrafficShaping.shutdownGracefully();
        }
    }
}
最后
以上介绍了Netty的基本用法,在代码中也做了一部分的关键注释,但可能还会有许多不足,也不可能满足所有人的要求,大家可根据自己的实际需求去改造此项目。附上源码地址netty源码
持续学习,记录点滴。更多文章请访问 文章首发
搭建生产级的Netty项目的更多相关文章
- Java全栈程序员之07:IDEA中使用MAVEN构架生产级的Web项目
		在上一篇我们介绍了如何在IDEA中使用MAVEN,以及如何创建依赖等.那么在这一篇中,我们就试图搭建一个生产级的解决方案,大家可以使用这个解决方案作为骨架代码来搭建自己的开发环境. 在这里,我们要完成 ... 
- 【分布式事务】基于RocketMQ搭建生产级消息集群?
		导读 目前很多互联网公司的系统都在朝着微服务化.分布式化系统的方向在演进,这带来了很多好处,也带来了一些棘手的问题,其中最棘手的莫过于数据一致性问题了.早期我们的软件功能都在一个进程中,数据的一致性可 ... 
- 前端MVC Vue2学习总结(七)——ES6与Module模块化、Vue-cli脚手架搭建、开发、发布项目与综合示例
		使用vue-cli可以规范项目,提高开发效率,但是使用vue-cli时需要一些ECMAScript6的知识,特别是ES6中的模块管理内容,本章先介绍ES6中的基础与模块化的内容再使用vue-cli开发 ... 
- Maven 搭建spring boot多模块项目(附源码),亲测可以,感谢原创
		原创地址:https://segmentfault.com/a/1190000005020589 我的DEMO码云地址,持续添加新功能: https://gitee.com/itbase/Spring ... 
- 使用maven搭建ssm框架的javaweb项目
		目前主流的javaweb项目,常会用到ssm(Spring+Spring MVC+Mybatis)框架来搭建项目的主体框架,本篇介绍搭建SSM框架的maven项目的实施流程.记之共享! 一.SSM框架 ... 
- Maven 搭建spring boot多模块项目
		Maven 搭建spring boot多模块项目 备注:所有项目都在idea中创建 1.idea创建maven项目 1-1: 删除src,target目录,只保留pom.xml 1-2: 根目录pom ... 
- 使用 Sealos 在 3 分钟内快速部署一个生产级别的 Kubernetes 高可用集群
		本文首发于:微信公众号「运维之美」,公众号 ID:Hi-Linux. 「运维之美」是一个有情怀.有态度,专注于 Linux 运维相关技术文章分享的公众号.公众号致力于为广大运维工作者分享各类技术文章和 ... 
- 微信自研生产级paxos类库PhxPaxos实现原理介绍
		转载自: http://mp.weixin.qq.com/s?__biz=MzI4NDMyNTU2Mw==&mid=2247483695&idx=1&sn=91ea4229 ... 
- react全家桶从0搭建一个完整的react项目(react-router4、redux、redux-saga)
		react全家桶从0到1(最新) 本文从零开始,逐步讲解如何用react全家桶搭建一个完整的react项目.文中针对react.webpack.babel.react-route.redux.redu ... 
随机推荐
- android逆向---charles抓包
			手机与电脑处于同一网络环境,且正确设置代理后,charles显示CONNECT失败,提示信息SSL handshake with client failed: An unknown issue occ ... 
- python爬虫之数据加密解密
			一.什么叫数据加密 数据加密是指利用加密算法和秘钥将明文转变为密文的过程. 二.数据加密的方式 1.单向加密 指只能加密数据而不能解密数据,这种加密方式主要是为了保证数据的完整性,常见的加密算法有MD ... 
- 不要写很酷但同事看不懂的Java代码
			你好呀,我是沉默王二,一个和黄家驹一样身高,和刘德华一样颜值的程序员.为了提高 Java 编程的技艺,我最近在 GitHub 上学习一些高手编写的代码.下面这一行代码(出自大牛之手)据说可以征服你的朋 ... 
- 8421BCD转余3码Verilog HDL的设计(1)
			近期阅读Verilog HDL高级数字设计(第二版)中,遇到了串行比特流BCD码转余3码转换器的设计,比较独特的是: (1)该转换器的输入为1位串行比特流,输出也为1位串行比特流. BCD码与余三码的 ... 
- webstorm 提示 "scanning files to index..." 一直不能编译的问题
			先说一下我的操作过程吧: 下载公司的vue项目后,要用到webpack打包工具,需要按照package.json安装一些依赖,我使用了镜像后,npm install模块时候生成了一个 node_mod ... 
- HTML与CSS 开发常用语义化命名
			一.布局❤️ header 头部/页眉:index 首页/索引:logo 标志:nav/sub_nav 导航/子导航:banner 横幅广告:main/content 主体/内容:container/ ... 
- PYTHON程序设计实验
			Python程序设计实验报告一: 熟悉IDLE和在线编程平台 安徽工程大学 Python程序设计实验报告 班级 物流191 姓名 邹缕学号 3190505117成绩 ▁▁▁ 日期 2020.3.5 指 ... 
- iview中遇到table的坑(已经修改了table的数据,但是界面没有更新)
			https://blog.csdn.net/bigdargon/article/details/89381466 https://blog.csdn.net/qiuyan_f/article/deta ... 
- 基于VR三维全景的虚拟展馆展览实现
			VR三维全景虚拟现实技术的应用,能够通过全方位互动式来还原真实场景,令人产生一种身临其境的感觉,由于三维全景虚拟现实技术具有一定应用优势,其在企业与院校展示.建筑规划展示.酒店宾馆展示等方面都逐步得到 ... 
- 通过mockjs来制作假数据
			需用用到的模块为express和mockjs //导入模块开启服务器模块 const express=require('express') //导入假数据模块 const mockjs=require ... 
