首先看一个netty服务端启动的demo
public class Server { public static void main(String[] args) throws Exception { // 配置服务端的 NIO线程组 // boss线程组用于网络事件的监听 EventLoopGroup bossGroup = new NioEventLoopGroup(1); // worker线程组用于SocketChannel的网络读写 EventLoopGroup workerGroup = new NioEventLoopGroup(); try { // NIO服务端的辅助启动类,目的是降低服务端开发的复杂度 ServerBootstrap b = new ServerBootstrap(); // 配置两大线程组 b.group(bossGroup, workerGroup) // 配置服务端channel .channel(NioServerSocketChannel.class) // 配置TCP基本属性 .childOption(ChannelOption.TCP_NODELAY, true) // 客户端创建连接时绑定基本属性 .childAttr(AttributeKey.newInstance("childAttr"), "childAttrValue") // 配置服务端启动过程逻辑处理器 .handler(new ServerHandler()) // 配置业务处理链 handler pipeline .childHandler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) { // 配置业务处理handler,对数据流进行读写等处理 // ch.pipeline().addLast() } }); // 前面都是一些属性配置的逻辑,真正的服务端启动在此处开始 // 绑定端口,正式启动server端服务 ChannelFuture f = b.bind(8888).sync(); // 同步等待,直至服务端监听端口关闭 f.channel().closeFuture().sync(); } finally { // 优雅退出,释放线程池资源 bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } }
ServerHandler
ublic class ServerHandler extends ChannelInboundHandlerAdapter { @Override public void channelActive(ChannelHandlerContext ctx) { System.out.println("channelActive"); } @Override public void channelRegistered(ChannelHandlerContext ctx) { System.out.println("channelRegistered"); } @Override public void handlerAdded(ChannelHandlerContext ctx) { System.out.println("handlerAdded"); } @Override public void channelRead(final ChannelHandlerContext ctx, Object msg) throws Exception { super.channelRead(ctx, msg); new Thread(new Runnable() { @Override public void run() { // 耗时的操作 String result = loadFromDB(); ctx.channel().writeAndFlush(result); ctx.executor().schedule(new Runnable() { @Override public void run() { // ... } }, 1, TimeUnit.SECONDS); } }).start(); } private String loadFromDB() { return "hello world!"; } }
Netty创建服务端Channel时,从服务端 ServerBootstrap 类的 bind 方法进入,下图是创建服务端Channel的函数调用链。在后续代码中通过反射的方式创建服务端Channel,反射操作在创建服务端 Channel 对象的工厂的 newChannel 方法,创建服务端 Channel 对象的工厂在ServerBootstrap 类的 channel 方法中确定。
在服务端创建Channel的过程中,上述代码中传入的Class类为 NioServerSocketChannel.class,这个类是在配置ServerBootstrap时通过其channel()方法确定的,所以创建的服务端Channel对象也就是 NioServerSocketChannel 类的对象,实例化 NioServerSocketChannel 类时会调用该类及其父类的一系列 构造方法,这一过程中将会创建 jdk 底层的 jdk channel 以及做一些基础的初始化工作,比如设置服务端Channel的阻塞模式,创建服务端Channel的id、unsafe、pipeline成员等。
每一个Channel在创建的时候都会为其分配一个新的ChannelPipeline,这项关联是永久性的,Channel既不能附加另外一个ChannelPipeline,也不能分离其当前的。ChannelPipeline中以链式结构存储ChannelHandlerContext,在刚开始创建ChannelPipeline的时候会先创建两个节点:head、tail节点,后续再往ChannelPipeline中添加ChannelHandler时可调用ChannelPipeline的addLast方法进行添加,处理过程中会将ChannelHandler封装为ChannelHandlerContext,然后添加进去。
服务端Channel创建完成后会对其进行初始化,初始化工作大概就是保存用户自定义的属性,然后配置服务端的pipeline,再通过保存的用户属性创建一个连接接入器,并将其添加到服务端的pipeline,连接接入器每次accept新的连接之后都会使用这些属性对新连接做一些配置。
原文:https://www.cnblogs.com/liekkas01/p/12650564.html