netty 并发 随笔 2-netty.channel实例化

0. java还要写到什么时候嘛…

// io.netty.bootstrap.AbstractBootstrap#doBind
private ChannelFuture doBind(final SocketAddress localAddress) {
    final ChannelFuture regFuture = initAndRegister();
    final Channel channel = regFuture.channel();
    if (regFuture.cause() != null) {
        return regFuture;
    }

    if (regFuture.isDone()) {
        // At this point we know that the registration was complete and successful.
        ChannelPromise promise = channel.newPromise();
        doBind0(regFuture, channel, localAddress, promise);
        return promise;
    } else {
        // Registration future is almost always fulfilled already, but just in case it's not.
        final PendingRegistrationPromise promise = new PendingRegistrationPromise(channel);
        regFuture.addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture future) throws Exception {
                Throwable cause = future.cause();
                if (cause != null) {
                    // Registration on the EventLoop failed so fail the ChannelPromise directly to not cause an
                    // IllegalStateException once we try to access the EventLoop of the Channel.
                    promise.setFailure(cause);
                } else {
                    // Registration was successful, so set the correct executor to use.
                    // See https://github.com/netty/netty/issues/2586
                    promise.registered();

                    doBind0(regFuture, channel, localAddress, promise);
                }
            }
        });
        return promise;
    }
}

1. 直接进入主题

// io.netty.bootstrap.AbstractBootstrap#initAndRegister
final ChannelFuture initAndRegister() {
    Channel channel = null;
    try {
    	// step into ...
    	// 从语义可知: Channel工厂会创建一个通道实例
		// 工厂反射创建出channel(构造中维护了jdk的socketChannel)
		// 本章节专注于这个方法
        channel = channelFactory.newChannel();
		// 初始化
        init(channel);
    } catch (Throwable t) {
        if (channel != null) {
            // channel can be null if newChannel crashed (eg SocketException("too many open files"))
            channel.unsafe().closeForcibly();
            // as the Channel is not registered yet we need to force the usage of the GlobalEventExecutor
            return new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE).setFailure(t);
        }
        // as the Channel is not registered yet we need to force the usage of the GlobalEventExecutor
        return new DefaultChannelPromise(new FailedChannel(), GlobalEventExecutor.INSTANCE).setFailure(t);
    }

	// group 指的是 bossGroup:EventLoopGroup(因此将进入MultithreadEventLoopGroup)
	// 这里用脚可以想到:registry发生了:channel(IO)开始关联了线程模型
	// 这里的unsafe被封装到了netty.Channel,作为内部接口
    ChannelFuture regFuture = config().group().register(channel);
    if (regFuture.cause() != null) {
        if (channel.isRegistered()) {
            channel.close();
        } else {
            channel.unsafe().closeForcibly();
        }
    }

    // If we are here and the promise is not failed, it's one of the following cases:
    // 1) If we attempted registration from the event loop, the registration has been completed at this point.
    //    i.e. It's safe to attempt bind() or connect() now because the channel has been registered.
    // 2) If we attempted registration from the other thread, the registration request has been successfully
    //    added to the event loop's task queue for later execution.
    //    i.e. It's safe to attempt bind() or connect() now:
    //         because bind() or connect() will be executed *after* the scheduled registration task is executed
    //         because register(), bind(), and connect() are all bound to the same thread.

    return regFuture;
}

1.1 回溯到channelFactory实例化的时候

发生再前面ServerBootstrap的构建过程中

EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
    ServerBootstrap b = new ServerBootstrap();
    b.group(bossGroup, workerGroup)
    		// step into ...
            .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();
                    p.addLast(new LoggingHandler(LogLevel.INFO));
                    p.addLast(new EchoServerHandler());
                }
            });

    ChannelFuture f = b.bind(EchoConstants.PORT_SERVER).sync();

    f.channel().closeFuture().sync();
} finally {
    bossGroup.shutdownGracefully();
    workerGroup.shutdownGracefully();
}

// io.netty.bootstrap.AbstractBootstrap#channel
public B channel(Class<? extends C> channelClass) {
	// 这里保存了传入的channel的Class,用于后续使用反射调用其构造器
	// 在这里创建了通道的工厂(从命名可知:通过反射创建实例)实例,并赋值到了全局
    return channelFactory(new ReflectiveChannelFactory<C>(
            ObjectUtil.checkNotNull(channelClass, "channelClass")
    ));
}

1.2 ChannelFactory创建 Channel

1.2.1 调用Channel的构造器实例来创建Channel实例

public class ReflectiveChannelFactory<T extends Channel> implements ChannelFactory<T> {

    private final Constructor<? extends T> constructor;

	public ReflectiveChannelFactory(Class<? extends T> clazz) {
	    ObjectUtil.checkNotNull(clazz, "clazz");
	    try {
	    	// 通道工厂实例化时,保存的是通道类的构造器的实例
	        this.constructor = clazz.getConstructor();
	    } catch (NoSuchMethodException e) {
	        throw new IllegalArgumentException("Class " + StringUtil.simpleClassName(clazz) +
	                " does not have a public non-arg constructor", e);
	    }
	}
	
	@Override
	public T newChannel() {
	    try {
	    	// step into ...
	    	// 调用其无参构造创建通道实例
	        return constructor.newInstance();
	    } catch (Throwable t) {
	        throw new ChannelException("Unable to create Channel from class " + constructor.getDeclaringClass(), t);
	    }
	}
}

1.2.2 Channel、pipeline构造

值得注意的设计:

  • jdk.channel 被封闭到 netty.channel 内部维护,并非继承关系
  • pipeline 会在netty.channel构造过程中实例化,呈双向链表,此时并没有往里添加我们自定义的handler
	// io.netty.channel.socket.nio.NioServerSocketChannel
    public NioServerSocketChannel() {
    	// private static final SelectorProvider DEFAULT_SELECTOR_PROVIDER = SelectorProvider.provider();
    	// 1. 获取selector作为socket的构造参数
    	// 2. 构造socket实例作为该channel(NioServerSocketChannel)的构造参数
    	// 注意:执行完 2 时,jdk.channel实例已经创建完成,维护在netty.channel内部
    	// 3. 执行channel的构造函数
        this(newSocket(DEFAULT_SELECTOR_PROVIDER));
    }

	// java.nio.channels.spi.SelectorProvider#provider
	// 1. 获取selector作为socket的构造参数
    public static SelectorProvider provider() {
        synchronized (lock) {
            if (provider != null)
                return provider;
            return AccessController.doPrivileged(
                new PrivilegedAction<SelectorProvider>() {
                    public SelectorProvider run() {
                            if (loadProviderFromProperty())
                                return provider;
                            if (loadProviderAsService())
                                return provider;
                           	// 因为我们之前构造NioEventLoopGroup时,没有指定selectorProvider,所以会默认返回jdk默认的selector
                            provider = sun.nio.ch.DefaultSelectorProvider.create();
                            return provider;
                        }
                    });
        }
    }


	// io.netty.channel.socket.nio.NioServerSocketChannel
	// 2. 构造socket实例作为该channel(NioServerSocketChannel)的构造参数
    private static ServerSocketChannel newSocket(SelectorProvider provider) {
        try {
            /**
             *  Use the {@link SelectorProvider} to open {@link SocketChannel} and so remove condition in
             *  {@link SelectorProvider#provider()} which is called by each ServerSocketChannel.open() otherwise.
             *
             *  See <a href="https://github.com/netty/netty/issues/2308">#2308</a>.
             */
             // 这里使用jdk默认的selector打开一个服务端的通道
            return provider.openServerSocketChannel();
        } catch (IOException e) {
            throw new ChannelException(
                    "Failed to open a server socket.", e);
        }
    }

	// io.netty.channel.socket.nio.NioServerSocketChannel	
	// 3. 执行channel的构造函数
    public NioServerSocketChannel(ServerSocketChannel channel) {
    	// 4. 执行父类构造
    	// 看看这里的入参:
    	// null:netty.channel的父级通道 
    	// channel:jdk.channel
    	// SelectionKey.OP_ACCEPT:selector轮询时的偏好事件
        super(null, channel, SelectionKey.OP_ACCEPT);
        // 这里掠过,无伤大雅,主要就是传递引用而已
        config = new NioServerSocketChannelConfig(this, javaChannel().socket());
    }

	// io.netty.channel.nio.AbstractNioMessageChannel#AbstractNioMessageChannel
	// 4. 执行父类构造
	protected AbstractNioMessageChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
		// step into ...
        super(parent, ch, readInterestOp);
    }

	// io.netty.channel.nio.AbstractNioChannel#AbstractNioChannel
	// 4. 执行父类构造
    protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
        super(parent);
        this.ch = ch;
        this.readInterestOp = readInterestOp;
        try {
        	// 设置jdk.channel非阻塞
            ch.configureBlocking(false);
        } catch (IOException e) {
            try {
                ch.close();
            } catch (IOException e2) {
                logger.warn(
                            "Failed to close a partially initialized socket.", e2);
            }

            throw new ChannelException("Failed to enter non-blocking mode.", e);
        }
    }
	
	// io.netty.channel.AbstractChannel#AbstractChannel(io.netty.channel.Channel)
	// 4. 执行父类构造
    protected AbstractChannel(Channel parent) {
        this.parent = parent;
        id = newId();
        // 这里unsafe的概念类似sun的,但是不是一个类,netty自己搞的
        // 实例化的是 DefaultServerUnsafe extends AbstractUnsafe
        // 后面事件触发后,底层都会借助这个内部类
        unsafe = newUnsafe();
        // 6. 实例化1个pipeline,作为channel内部变量维护
        // pipeline其实就是内部执行逻辑的1条双向执行链
        // 链上主要netty默认初始化的head/tailContext 以及 我们自定义的handler
        pipeline = newChannelPipeline();
    }

	// io.netty.channel.DefaultChannelPipeline#DefaultChannelPipeline
	// 6. 实例化1个pipeline,作为channel内部变量维护
    protected DefaultChannelPipeline(Channel channel) {
    	// pipeline持有了netty.channel的引用
        this.channel = ObjectUtil.checkNotNull(channel, "channel");
        succeededFuture = new SucceededChannelFuture(channel, null);
        voidPromise =  new VoidChannelPromise(channel, true);

		// head/tailContext都持有了pipeline的引用
        tail = new TailContext(this);
        head = new HeadContext(this);

		// 老司机都懂的双向链表结构
        head.next = tail;
        tail.prev = head;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
2023-07-14 15:19:01.215 WARN 7308 --- [sson-netty-2-15] io.netty.util.concurrent.DefaultPromise : An exception was thrown by org.redisson.misc.RedissonPromise$$Lambda$888/0x00000008008f7440.operationComplete() java.lang.NullPointerException: null 2023-07-14 15:19:01.216 ERROR 7308 --- [sson-netty-2-15] o.r.c.SentinelConnectionManager : Can't execute SENTINEL commands on /172.24.107.11:26379 org.redisson.client.RedisException: ERR No such master with that name. channel: [id: 0x2d66827d, L:/172.23.9.103:46812 - R:/172.24.107.11:26379] command: (SENTINEL SLAVES), params: [mymaster] at org.redisson.client.handler.CommandDecoder.decode(CommandDecoder.java:365) ~[redisson-3.13.3.jar:3.13.3] at org.redisson.client.handler.CommandDecoder.decodeCommand(CommandDecoder.java:196) ~[redisson-3.13.3.jar:3.13.3] at org.redisson.client.handler.CommandDecoder.decode(CommandDecoder.java:134) ~[redisson-3.13.3.jar:3.13.3] at org.redisson.client.handler.CommandDecoder.decode(CommandDecoder.java:104) ~[redisson-3.13.3.jar:3.13.3] at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:501) ~[netty-codec-4.1.51.Final.jar:4.1.51.Final] at io.netty.handler.codec.ReplayingDecoder.callDecode(ReplayingDecoder.java:366) ~[netty-codec-4.1.51.Final.jar:4.1.51.Final] at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:276) ~[netty-codec-4.1.51.Final.jar:4.1.51.Final] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) ~[netty-transport-4.1.51.Final.jar:4.1.51.Final] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) ~[netty-transport-4.1.51.Final.jar:4.1.51.Final] at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) ~[netty-transport-4.1.51.Final.jar:4.1.51.Final] at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410) ~[netty-transport-4.1.51.Final.jar:4.1.51.Final] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379) ~[netty-transport-4.1.51.Final.jar:4.1.51.Final] at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365) ~[netty-transport-4.1.51.Final.jar:4.1.51.Final] at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919) ~[netty-transport-4.1.51.Final.jar:4.1.51.Final] at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163) ~[netty-transport-4.1.51.Final.jar:4.1.51.Final] at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:714) ~[netty-transport-4.1.51.Final.jar:4.1.51.Final] at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:650) ~[netty-transport-4.1.51.Final.jar:4.1.51.Final] at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:576) ~[netty-transport-4.1.51.Final.jar:4.1.51.Final] at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493) ~[netty-transport-4.1.51.Final.jar:4.1.51.Final] at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989) ~[netty-common-4.1.51.Final.jar:4.1.51.Final] at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) ~[netty-common-4.1.51.Final.jar:4.1.51.Final] at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-common-4.1.51.Final.jar:4.1.51.Final] at java.base/java.lang.Thread.run(Thread.java:834) ~[na:na] 解决方法
最新发布
07-15
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

肯尼思布赖恩埃德蒙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值