《 Netty权威指南(第2版)》 学习感悟
1:Netty是什么?
Netty是由JBOSS提供的一个java开源框架。Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序dsf。
也就是说,Netty 是一个基于NIO的客户,服务器端编程框架,使用Netty 可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户,
服务端应用。Netty相当简化和流线化了网络应用的编程开发过程,例如,TCP和UDP的socket服务开发。
“快速”和“简单”并不意味着会让你的最终应用产生维护性或性能上的问题。Netty 是一个吸收了多种协议的实现经验,这些协议包括FTP,SMTP,HTTP,各种二进制,文本协议,并经过相当精心设计的项目,最终,Netty 成功的找到了一种方式,在保证易于开发的同时还保证了其应用的性能,稳定性和伸缩性。
Netty具有如下优势:
- 处理大容量数据流更简单
- 处理协议编码和单元测试更简单
- I/O超时和idle状态检测
- 应用程序的关闭更简单,更安全
- 更可靠的OutOfMemoryError预防
传输方式为:
- 基于BIO和NIO的UDP传输
- 本地传输(又名 in-VM传输)
- HTTP通道,可绕过防火墙
2:Netty可以做什么?
netty是一套在java NIO的基础上封装的便于用户开发网络应用程序的api. 应用场景很多,诸如阿里的消息队列(RocketMQ),分布式rpc(Dubbo)通信层都使用到了netty(dubbo可以用服务发现自由选择通信层). 主要优点个人总结如下:
1. netty是非阻塞事件驱动框架, 并结合线程组(group)的概念,可以很好的支持高并发,慢连接的场景。
2. 编程接口非常容易,并且也较好的解决了TCP粘包/拆包的问题.netty提供了自己的ByteBuf和channel,相比于jdk的ByteBuffer和channel来说更简便灵活操作, 并提供了pipeline的概念,并针对每个contextHandler都可以由用户定义, 方便直接.
3. 有一些web框架已经开始直接使用netty做为底层通信服务,诸如play. 这样play就不用依赖于容器去进行部署,在没有nginx做反向代理的情况下也能支持高并发.编解码器可以随意扩展,今天是个web,明天就可以是一个ftp或email服务器,个人觉得比较灵活。
《 Netty权威指南(第2版)》试读章节是服务端创建,其对原生NIO类库的使用复杂性进行了讲解,对Netty服务端穿件的时序图和步骤进行了详细说明,对Netty源码对服务端创建进行剖析,最后对新的客户端接入进行了源码层面的分析和讲解。通过本章节的学习,读者可以掌握Netty服务端创建并且可以在实际中使用,编写出高效的代码。
Netty服务端创建时序图:

Netty服务端创建程序:
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpContentDecompressor;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
import org.apache.log4j.PropertyConfigurator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
import com.innoplay.httpserver.config.ConfigInfo;
import com.innoplay.httpserver.config.ConfigProperties;
import com.innoplay.service.context.ApplicationContextUtil;
/**
* server main entrance, netty tcp server listen on configInfo.listenPort
*
*/
public class HttpServer {
/**
* init load config information
*/
private static ConfigInfo configInfo;
private static final Logger logger = LoggerFactory
.getLogger(HttpServer.class);
private static ServerBootstrap bootstrap;
/**
* start server method
*
* @param args
* @throws IOException
*/
private void start() throws Exception {
EventLoopGroup group = new NioEventLoopGroup(configInfo.getThreadNum());
try {
bootstrap = new ServerBootstrap();
bootstrap
.group(group)
.channel(NioServerSocketChannel.class)
.localAddress(
new InetSocketAddress(configInfo.getListenPort()))
.childHandler(new ChannelInitializer<SocketChannel>() {
/*
* (non-Javadoc)
*
* @see
* io.netty.channel.ChannelInitializer#initChannel(io
* .netty.channel.Channel)
*/
@Override
protected void initChannel(SocketChannel ch)
throws Exception {
ch.pipeline().addLast(new HttpServerCodec());
ch.pipeline().addLast(new HttpContentDecompressor());
ch.pipeline().addLast(new HttpObjectAggregator(Integer.MAX_VALUE));//定义
ch.pipeline().addLast(new HttpServerHandler());
}
});
ChannelFuture f = bootstrap.bind().sync();
logger.info(HttpServer.class.getName()
+ " started and listen on " + f.channel().localAddress());
f.channel().closeFuture().sync();
} finally {
group.shutdownGracefully().sync();
}
}
/**
* main entrance
*
* @param args
*/
public static void main(String[] args) {
try {
//program argument setting/windows/linux
//conf.path=E:\Workspace\server\trunk\innoplay-httpserver\target\conf
if(args != null) {
for(String s : args) {
if(s.startsWith("--conf.path")) {
System.setProperty(ConfigProperties.CONFIGPATH, s.replace("--conf.path=", ""));
PropertyConfigurator.configure(System.getProperty(ConfigProperties.CONFIGPATH) + File.separator + "log4j.properties");
logger.info("System has received conf.path: {}", s);
}
}
} else {
logger.error("please setting the --conf.path=XXXX, system exited!");
System.exit(-1);
}
configInfo = ConfigProperties.loadProperties();
// ApplicationContext context = new FileSystemXmlApplicationContext(System.getProperty(ConfigProperties.CONFIGPATH) + File.separator +"applicationContext.xml");
ApplicationContext context = new GenericXmlApplicationContext("applicationContext.xml");
ApplicationContextUtil.setContext(context);
HttpServer server = new HttpServer();
server.start();
} catch (Exception e) {
logger.error("Server occur an error!", e.getCause());
e.printStackTrace();
}
}
public static void close() {
if (bootstrap != null) {
try {
bootstrap.group().shutdownGracefully().sync();
} catch (InterruptedException e) {
logger.error("Server close occur an error!", e.getCause());
e.printStackTrace();
}
}
}
}
相信这本书对学习Netty的爱好者有很好的帮助,对编写出高效的代码有很好的帮助。