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项目的更多相关文章

  1. Java全栈程序员之07:IDEA中使用MAVEN构架生产级的Web项目

    在上一篇我们介绍了如何在IDEA中使用MAVEN,以及如何创建依赖等.那么在这一篇中,我们就试图搭建一个生产级的解决方案,大家可以使用这个解决方案作为骨架代码来搭建自己的开发环境. 在这里,我们要完成 ...

  2. 【分布式事务】基于RocketMQ搭建生产级消息集群?

    导读 目前很多互联网公司的系统都在朝着微服务化.分布式化系统的方向在演进,这带来了很多好处,也带来了一些棘手的问题,其中最棘手的莫过于数据一致性问题了.早期我们的软件功能都在一个进程中,数据的一致性可 ...

  3. 前端MVC Vue2学习总结(七)——ES6与Module模块化、Vue-cli脚手架搭建、开发、发布项目与综合示例

    使用vue-cli可以规范项目,提高开发效率,但是使用vue-cli时需要一些ECMAScript6的知识,特别是ES6中的模块管理内容,本章先介绍ES6中的基础与模块化的内容再使用vue-cli开发 ...

  4. Maven 搭建spring boot多模块项目(附源码),亲测可以,感谢原创

    原创地址:https://segmentfault.com/a/1190000005020589 我的DEMO码云地址,持续添加新功能: https://gitee.com/itbase/Spring ...

  5. 使用maven搭建ssm框架的javaweb项目

    目前主流的javaweb项目,常会用到ssm(Spring+Spring MVC+Mybatis)框架来搭建项目的主体框架,本篇介绍搭建SSM框架的maven项目的实施流程.记之共享! 一.SSM框架 ...

  6. Maven 搭建spring boot多模块项目

    Maven 搭建spring boot多模块项目 备注:所有项目都在idea中创建 1.idea创建maven项目 1-1: 删除src,target目录,只保留pom.xml 1-2: 根目录pom ...

  7. 使用 Sealos 在 3 分钟内快速部署一个生产级别的 Kubernetes 高可用集群

    本文首发于:微信公众号「运维之美」,公众号 ID:Hi-Linux. 「运维之美」是一个有情怀.有态度,专注于 Linux 运维相关技术文章分享的公众号.公众号致力于为广大运维工作者分享各类技术文章和 ...

  8. 微信自研生产级paxos类库PhxPaxos实现原理介绍

    转载自:   http://mp.weixin.qq.com/s?__biz=MzI4NDMyNTU2Mw==&mid=2247483695&idx=1&sn=91ea4229 ...

  9. react全家桶从0搭建一个完整的react项目(react-router4、redux、redux-saga)

    react全家桶从0到1(最新) 本文从零开始,逐步讲解如何用react全家桶搭建一个完整的react项目.文中针对react.webpack.babel.react-route.redux.redu ...

随机推荐

  1. Google Hacking --你真的会用Google吗?

    你真的会用Google吗?Google Hacking提升工作效率 阅读本文需要6.66分钟 Google hacking,也叫作google dorking.如果在 Google 上搜索 Googl ...

  2. textarea 实现高度自动增长

    有时候希望textarea 能够自动调整高度来适应输入的内容 网上看到了很多解决方案,比如动态创建一个隐藏的div,当用户输入的时候将textarea的内容绑定到div,由于div的高度会自动撑开,因 ...

  3. Jprofile解析dump文件使用详解

    1 Jprofile简介 官网 下载对应的系统版本即可 性能查看工具JProfiler,可用于查看java执行效率,查看线程状态,查看内存占用与内存对象,还可以分析dump日志. 2 功能简介 选择a ...

  4. Flutter调研(2)-Flutter从安装到运行成功的一些坑

    工作需要,因客户端有部分页面要使用flutter编写,需要QA了解一下flutter相关知识,因此,做了flutter调研,包含安装,基础知识与demo编写,第二部分是安装与环境配置. —— 在mac ...

  5. Ajax&Json案例

    案例: * 校验用户名是否存在 1. 服务器响应的数据,在客户端使用时,要想当做json数据格式使用.有两种解决方案: 1. $.get(type):将最后一个参数type指定为"json& ...

  6. 深度解析互联网大厂面试难题自定义@EnableXX系列

    深度解析互联网大厂面试难题自定义@EnableXX系列   其实是一个@Import的设计技巧 创建注解@EnableXX(任何名称注解都行,只是这个名字好一些) XXConfiguration类不能 ...

  7. Eureka 注册中心看这一篇就够了

    服务注册中心是服务实现服务化管理的核心组件,类似于目录服务的作用,主要用来存储服务信息,譬如提供者 url 串.路由信息等.服务注册中心是微服务架构中最基础的设施之一. 在微服务架构流行之前,注册中心 ...

  8. node--CommonJS

    1.CommonJS 1)弥补js没有标准的缺陷 2.Node模块 1)分为核心模块和用户自定义模块 2)我们可以把公共的功能抽离为一个单独的js文件作为一个模块 其中的成员和属性外界无法访问,若要设 ...

  9. 30分钟学会Objective-C

    注: 本文首发于我的个人博客:https://evilpan.com/2019/04/05/objc-basics/ 请原谅我的标题党.但是如果你有其他语言的学习经验,要学习Objective-C的语 ...

  10. 在eclipse的Java类文件中,右上角出现大写字母A代表什么

    代表这个文件(类)是一个抽象类abstract的第一个字母: