学不懂Netty?看不懂源码?不存在的,手把手带你阅读Netty源码

提前准备好如下代码, 从服务端构建着手,深入分析Netty服务端的启动过程。

public class NettyBasicServerExample {

    public void bind(int port){
        //netty的服务端编程要从EventLoopGroup开始,
        // 我们要创建两个EventLoopGroup,
        // 一个是boss专门用来接收连接,可以理解为处理accept事件,
        // 另一个是worker,可以关注除了accept之外的其它事件,处理子任务。
        //上面注意,boss线程一般设置一个线程,设置多个也只会用到一个,而且多个目前没有应用场景,
        // worker线程通常要根据服务器调优,如果不写默认就是cpu的两倍。
        EventLoopGroup bossGroup=new NioEventLoopGroup();

        EventLoopGroup workerGroup=new NioEventLoopGroup();
        try {
            //服务端要启动,需要创建ServerBootStrap,
            // 在这里面netty把nio的模板式的代码都给封装好了
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup, workerGroup)
                //配置Server的通道,相当于NIO中的ServerSocketChannel
                .channel(NioServerSocketChannel.class)
                .handler(new LoggingHandler(LogLevel.INFO)) //设置ServerSocketChannel对应的Handler
                //childHandler表示给worker那些线程配置了一个处理器,
                // 这个就是上面NIO中说的,把处理业务的具体逻辑抽象出来,放到Handler里面
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        socketChannel.pipeline()
                            .addLast(new NormalInBoundHandler("NormalInBoundA",false))
                            .addLast(new NormalInBoundHandler("NormalInBoundB",false))
                            .addLast(new NormalInBoundHandler("NormalInBoundC",true));
                        socketChannel.pipeline()
                            .addLast(new NormalOutBoundHandler("NormalOutBoundA"))
                            .addLast(new NormalOutBoundHandler("NormalOutBoundB"))
                            .addLast(new NormalOutBoundHandler("NormalOutBoundC"))
                            .addLast(new ExceptionHandler());
                    }
                });
            //绑定端口并同步等待客户端连接
            ChannelFuture channelFuture=bootstrap.bind(port).sync();
            System.out.println("Netty Server Started,Listening on :"+port);
            //等待服务端监听端口关闭
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            //释放线程资源
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) {
        new NettyBasicServerExample().bind(8080);
    }
}
public class NormalInBoundHandler extends ChannelInboundHandlerAdapter {
    private final String name;
    private final boolean flush;

    public NormalInBoundHandler(String name, boolean flush) {
        this.name = name;
        this.flush = flush;
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("InboundHandler:"+name);
        if(flush){
            ctx.channel().writeAndFlush(msg);
        }else {
            throw new RuntimeException("InBoundHandler:"+name);
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.out.println("InboundHandlerException:"+name);
        super.exceptionCaught(ctx, cause);
    }
}
public class NormalOutBoundHandler extends ChannelOutboundHandlerAdapter {
    private final String name;

    public NormalOutBoundHandler(String name) {
        this.name = name;
    }

    @Override
    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
        System.out.println("OutBoundHandler:"+name);
        super.write(ctx, msg, promise);
    }
}

在服务端启动之前,需要配置ServerBootstrap的相关参数,这一步大概分为以下几个步骤

  • 配置EventLoopGroup线程组
  • 配置Channel类型
  • 设置ServerSocketChannel对应的Handler
  • 设置网络监听的端口
  • 设置SocketChannel对应的Handler
  • 配置Channel参数

Netty会把我们配置的这些信息组装,发布服务监听。

ServerBootstrap参数配置过程#

下面这段代码是我们配置ServerBootStrap相关参数,这个过程比较简单,就是把配置的参数值保存到ServerBootstrap定义的成员变量中就可以了。

bootstrap.group(bossGroup, workerGroup)
    //配置Server的通道,相当于NIO中的ServerSocketChannel
    .channel(NioServerSocketChannel.class)
    .handler(new LoggingHandler(LogLevel.INFO)) //设置ServerSocketChannel对应的Handler
    //childHandler表示给worker那些线程配置了一个处理器,
    // 这个就是上面NIO中说的,把处理业务的具体逻辑抽象出来,放到Handler里面
    .childHandler(new ChannelInitializer<SocketChannel>() {
    });

我们来看一下ServerBootstrap的类关系图以及属性定义

ServerBootstrap类关系图#

如图8-1所示,表示ServerBootstrap的类关系图。

  • AbstractBootstrap,定义了一个抽象类,作为抽象类,一定是抽离了Bootstrap相关的抽象逻辑,所以很显然可以推断出Bootstrap应该也继承了AbstractBootstrap
  • ServerBootstrap,服务端的启动类,
  • ServerBootstrapAcceptor,继承了ChannelInboundHandlerAdapter,所以本身就是一个Handler,当服务端启动后,客户端连接上来时,会先进入到ServerBootstrapAccepter。

学不懂Netty?看不懂源码?不存在的,手把手带你阅读Netty源码

图8-1 ServerBootstrap类关系图

AbstractBootstrap属性定义#

public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable {
    @SuppressWarnings("unchecked")
    private static final Map.Entry<ChannelOption<?>, Object>[] EMPTY_OPTION_ARRAY = new Map.Entry[0];
    @SuppressWarnings("unchecked")
    private static final Map.Entry<AttributeKey<?>, Object>[] EMPTY_ATTRIBUTE_ARRAY = new Map.Entry[0];
    /**
     * 这里的EventLoopGroup 作为服务端 Acceptor 线程,负责处理客户端的请求接入
     * 作为客户端 Connector 线程,负责注册监听连接操作位,用于判断异步连接结果。
     */
    volatile EventLoopGroup group; //
    @SuppressWarnings("deprecation")
    private volatile ChannelFactory<? extends C> channelFactory;  //channel工厂,很明显应该是用来制造对应Channel的
    private volatile SocketAddress localAddress;  //SocketAddress用来绑定一个服务端地址

    // The order in which ChannelOptions are applied is important they may depend on each other for validation
    // purposes.
    /**
     * ChannelOption 可以添加Channer 添加一些配置信息
     */
    private final Map<ChannelOption<?>, Object> options = new LinkedHashMap<ChannelOption<?>, Object>();
    private final Map<AttributeKey<?>, Object> attrs = new ConcurrentHashMap<AttributeKey<?>, Object>();
    /**
     *  ChannelHandler 是具体怎么处理Channer 的IO事件。
     */
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值