以官方例子开启我们的netty源码之旅
EchoClient类
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY, true)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
if (sslCtx != null) {
p.addLast(sslCtx.newHandler(ch.alloc(), HOST, PORT));
}
//p.addLast(new LoggingHandler(LogLevel.INFO));
p.addLast(new EchoClientHandler());
}
});
// Start the client.
ChannelFuture f = b.connect(HOST, PORT).sync();
// Wait until the connection is closed.
f.channel().closeFuture().sync();
} finally {
// Shut down the event loop to terminate all threads.
group.shutdownGracefully();
}
EchoServer类
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 100)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
if (sslCtx != null) {
p.addLast(sslCtx.newHandler(ch.alloc()));
}
p.addLast(new LoggingHandler(LogLevel.INFO));
//p.addLast(new EchoServerHandler());
}
});
// Start the server.
ChannelFuture f = b.bind(PORT).sync();
// Wait until the server socket is closed.
f.channel().closeFuture().sync();
} finally {
// Shut down all event loops to terminate all threads.
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
使用总结
1、ServerBootstrap类用于创建服务端实例,Bootstrap用于创建客户端实例。
2、在服务端,基于NioEventLoopGroup类创建了bossGroup、workerGroup这两个EventLoopGroup。客户端基于NioEventLoopGroup创建了一个group。它们可以理解为Netty中的线程池。
3、服务端的channel是NioServerSocketChannel(包装了nio原生的ServerSocketChannel),客户端的channel是NioSocketChannel(包装了nio原生的SocketChannel)
4、服务端ServerBootstrap有handler、childHandler;而客户端Bootstrap只有handler。
5、handler在初始化时执行,childHandler在客户端成功connect后才执行。如果需要在客户端连接前的请求进行 handler处理,则需要配置handler(),如果是处理客户端连接之后的handler,则需要配置在childHandler()。
6、pipeline:handler可以指定多个(需要上面的ChannelInitializer类辅助),它们会组成了一个 pipeline,它们其实就类似拦截器的概念,每个NioSocketChannel或NioServerSocketChannel内部都会有个pipeline实例。
7、ChannelFuture:涉及到Netty中的异步编程,和JDK中的Future接口类似。
8、handler可以指定多个(需要上面的ChannelInitializer类辅助)
展望
就这样,一个简单的netty应用程序就写完了。程序虽然简单,但世上的netty程序大体都是这几步:客户端和服务端各自开启EventLoopGroup和Bootstrap。使用很简单,所以我不会讲如何使用,但越简单的api往往意味着越复杂的底层代码。虽然使用起来就上面这几步,但是对应的底层代码非常复杂,你不应该想着短短几天就能搞明白。没有高手指路,甚至你很长时间都不一定能弄清楚,底层到底是如何运作的,相比于原生的NIO又有哪些异同。本系列文章就是这个目的,让你用最短的时间弄清楚netty的底层原理。如果你日常的工作只是CRUD,这个过程完成之后,你不只对netty,对NIO、多线程、异步、线程模型的理解也会更深一个层次。