Netty源码分析(二)—客户端初始化

本文详细分析了Netty客户端初始化的过程,包括Bootstrap的配置、EventLoopGroup线程池、Channel通道、Handler处理器的添加以及客户端的连接步骤。Netty通过封装Java NIO,简化了开发工作。客户端初始化涉及创建Bootstrap、设置EventLoopGroup、选择Channel类型、定制Handler处理链以及发起连接操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Netty源码分析(二)—客户端初始化

传统Java NIO在客户端启动时会涉及到SocketChannel,Selector,selectorKey等类;Netty对Java NIO基础类进行了封装,减少用户开发工作量,降低开发难度;

个人主页:tuzhenyu’s page
原文地址:Netty源码分析(二)—客户端初始化

(0)客户端初始化

  • 客户端初始化的步骤

    • 创建Bootstrap启动辅助类,通过Builder模式进行参数配置;

    • 创建并绑定Reactor线程池EventLoopGroup;

    • 设置并绑定服务端Channel通道类型;

    • 绑定服务端通道数据处理器责任链Handler;

    • 连接特定IP和端口;

  • 客户端初始化实例


private void connect(String host,int port){
    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
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        socketChannel.pipeline().addLast(new TimeClientHandler());
                    }
                });

        ChannelFuture f = b.connect(host,port).sync();
        f.channel().closeFuture().sync();
    }catch (Exception e){
        e.printStackTrace();
    }finally {
        group.shutdownGracefully();
    }
}

(1) Bootstrap初始化

  • ServerBootstrap继承AbstracBootstrap类,需要对EventLoopGroup,Channel和ChannelHandler等参数进行配置;

这里写图片描述

(2) EventLoopGroup线程池初始化

  • EventLoopGroup初始化是创建创建一个NioEventLoopGroup类型的Reactor线程池group分别用来通道IO事件;

EventLoopGroup group = new NioEventLoopGroup();

BootStrap b = new Bootstrap();

b.group(group);
  • 将group赋值给AbstractBootstrap的group属性,用作后续调用;

public B group(EventLoopGroup group) {
    if(group == null) {
        throw new NullPointerException("group");
    } else if(this.group != null) {
        throw new IllegalStateException("group set already");
    } else {
        this.group = group;
        return this;
    }
}

(3) Channel通道初始化

  • Channel初始化主要是指对通道类型进行设置,常见的通道类型主要有NioServerSocktChannel异步非阻塞服务端TCP通道,NioSocketChannel异步非阻塞客户端通道,OioServerSocketChannel同步阻塞服务端通道,OioSocketChannel同步阻塞客户端通道,NioDatagramChannel异步非阻塞UDP通道,OioDatagramChannel同步阻塞UDP通道等;

  • 在serverBootstrap初始化过程中通过调用channel()方法进行通道类型设置


public B channel(Class<? extends C> channelClass) {
    if(channelClass == null) {
        throw new NullPointerException("channelClass");
    } else {
        return this.channelFactory((io.netty.channel.ChannelFactory)(new ReflectiveChannelFactory(channelClass)));
    }
}
  • 根据传入的Channe类型初始化一个ChannelFactory类型的工厂类,工厂类中通过newChannel()方法创建Channel实例

private final Class<? extends T> clazz;

public ReflectiveChannelFactory(Class<? extends T> clazz) {
    if(clazz == null) {
        throw new NullPointerException("clazz");
    } else {
        this.clazz = clazz;
    }
}

public T newChannel() {
    try {
        return (Channel)this.clazz.newInstance();
    } catch (Throwable var2) {
        throw new ChannelException("Unable to create Channel from class " + this.clazz, var2);
    }
}
  • 通过channelFactory()方法将创建工厂类实例指向AbstractoryBootstrap的channelFactory属性

public B channelFactory(ChannelFactory<? extends C> channelFactory) {
    if(channelFactory == null) {
        throw new NullPointerException("channelFactory");
    } else if(this.channelFactory != null) {
        throw new IllegalStateException("channelFactory set already");
    } else {
        this.channelFactory = channelFactory;
        return this;
    }
}

(4)handler处理器的添加过程

  • 我们可以自定义Handler处理器并将其加入到pipeline管道中,进而像插件一样自由组合各种handler完成具体的业务逻辑;添加handler的过程是获取与channel通道绑定的管道pipeline然后将自定义的handler添加进pipeline内部维护的一个双向链表;

bootstrap.handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        socketChannel.pipeline().addLast(new TimeClientHandler());
                    }
});
  • Bootstrap.handler方法接收一个 ChannelHandler, 而我们传递的是一个 派生于ChannelInitializer的匿名类, 它正好也实现了 ChannelHandler接口;在channelInitializer抽象类中存在抽象方法initChannel()需要实现,同时在ChannelInitializer类中channelRegistered方法调用initChannle()方法实现handler处理器添加到pipeline管道中;

public abstract class ChannelInitializer<C extends Channel> extends ChannelInboundHandlerAdapter {

    private static final InternalLogger logger = InternalLoggerFactory.getInstance(ChannelInitializer.class);
    protected abstract void initChannel(C ch) throws Exception;

    @Override
    @SuppressWarnings("unchecked")
    public final void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        initChannel((C) ctx.channel());
        ctx.pipeline().remove(this);
        ctx.fireChannelRegistered();
    }
    ...
}
  • 在 channelRegistered 方法中, 会调用initChannel 方法, 将自定义的 handler 添加到 ChannelPipeline 中, 然后调用 ctx.pipeline().remove(this) 将自己从 ChannelPipeline 中删除.

(5)客户端的连接过程

  • 完成启动辅助类Bootstrap的参数配置后调用connect()方法连接服务端

public ChannelFuture connect(SocketAddress remoteAddress) {
    if(remoteAddress == null) {
        throw new NullPointerException("remoteAddress");
    } else {
        this.validate();
        return this.doResolveAndConnect(remoteAddress, this.config.localAddress());
    }
}
  • connect()方法调用validate()方法看各个Part是否准备就绪,然后调用doResolveAndConnect()方法:

private ChannelFuture doResolveAndConnect(final SocketAddress remoteAddress, final SocketAddress localAddress) {
    ChannelFuture regFuture = this.initAndRegister();
    final Channel channel = regFuture.channel();
    if(regFuture.isDone()) {
        return !regFuture.isSuccess()?regFuture:this.doResolveAndConnect0(channel, remoteAddress, localAddress, channel.newPromise());
    } else {
        final PendingRegistrationPromise promise = new PendingRegistrationPromise(channel);
        regFuture.addListener(new ChannelFutureListener() {
            public void operationComplete(ChannelFuture future) throws Exception {
                Throwable cause = future.cause();
                if(cause != null) {
                    promise.setFailure(cause);
                } else {
                    promise.registered();
                    Bootstrap.this.doResolveAndConnect0(channel, remoteAddress, localAddress, promise);
                }

            }
        });
        return promise;
    }
}
  • 通过调用initAndRegister()方法用ChannelFactory创建了一个Channel的实例,然后调用init()方法初始化Channel,最后将Channel注册到EventLoopGroup上:

总结

  • 客户端初始化和服务端初始化基本相同,区别在于Channel的类型设置和Handler处理链的添加等
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值