天天看点

Netty源码分析——服务端channle的创建(一)

首先我们看一下正常netty服务端启动的代码

public void server(int port) throws Exception {
        final ByteBuf buf = Unpooled.copiedBuffer("hello", Charset.forName("UTF-8"));
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
                    .localAddress(new InetSocketAddress(port)).childHandler(new ChannelInitializer<SocketChannel>(){

                protected void initChannel(SocketChannel ch) throws Exception {
                    ch.pipeline().addLast(new ChannelInboundHandlerAdapter(){
                        @Override
                        public void channelActive(ChannelHandlerContext ctx) throws Exception {
                            // 消息写完关闭连接
                            ctx.writeAndFlush(buf.duplicate()).addListener(ChannelFutureListener.CLOSE);
                        }
                    });
                }
            });
            ChannelFuture f = serverBootstrap.bind().sync();
            f.channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully().sync();
            workerGroup.shutdownGracefully().sync();
        }
    }
           

然后我们从bind()方法跟进去,发现有个doBind()方法,里面有个initAndRegister()方法就是创建服务端Channel的地方,有个

public T newChannel() {
        try {
            return clazz.newInstance();
        } catch (Throwable t) {
            throw new ChannelException("Unable to create Channel from class " + clazz, t);
        }
    }
           

可以看出是通过反射的方式创建,那么这个clazz怎么来的呢,就是通过serverBootstrap的

channel(NioServerSocketChannel.class)传递进来的,我们再看看这个channel()方法

public B channel(Class<? extends C> channelClass) {
        if (channelClass == null) {
            throw new NullPointerException("channelClass");
        }
        return channelFactory(new ReflectiveChannelFactory<C>(channelClass));
    }
           

就是这里把NioServerSocketChannel.class封装到ReflectiveChannelFactory传递给了channelFactory。

接着我们分析NioServerSocketChannel这个类的构造函数做了哪些事情

public NioServerSocketChannel() {
        this(newSocket(DEFAULT_SELECTOR_PROVIDER));
	}
	
private static ServerSocketChannel newSocket(SelectorProvider provider) {
        try {
            return provider.openServerSocketChannel();
        } catch (IOException e) {
            throw new ChannelException(
                    "Failed to open a server socket.", e);
        }
	}
           

首先是通过newSocket()创建了一个jdk底层的ServerSocketChannel,这里其实就把一个服务端的channel创建完毕了,我们接着看

public NioServerSocketChannel(ServerSocketChannel channel) {
        super(null, channel, SelectionKey.OP_ACCEPT);
        config = new NioServerSocketChannelConfig(this, javaChannel().socket());
    }
           

这里调用了父类的构造函数、NioServerSocketChannelConfig进行tcp参数配置,我们跟着这个父类构造函数

protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
        super(parent);
        this.ch = ch;
        this.readInterestOp = readInterestOp;
        try {
        	// 设置服务端channle为非阻塞模式
            ch.configureBlocking(false);
        } catch (IOException e) {
            try {
                ch.close();
            } catch (IOException e2) {
                if (logger.isWarnEnabled()) {
                    logger.warn(
                            "Failed to close a partially initialized socket.", e2);
                }
            }

            throw new ChannelException("Failed to enter non-blocking mode.", e);
        }
    }
           

通过 ch.configureBlocking(false);设置服务端channle为非阻塞模式,我们接着父类构造函数往下跟

protected AbstractChannel(Channel parent) {
        this.parent = parent;
        id = newId();
        unsafe = newUnsafe();
        pipeline = newChannelPipeline();
    }
           

通过AbstractChannel,创建id(channel 的id),unsafe(channel底层tcp读写操作的一个类),pipeline(channel事件处理的一条链)。

到这里,服务端channle的创建源码解析就已经结束。