netty 服务启动流程 

NioServerSocketChannel  初始化过程:

1.创建 Java NIO的 ServerSocketChannel;

2.为ServerSocketChannel 注册感兴趣的键以及设置为非阻塞模式;

3.创建默认的 pipeline 以及unsafe 对象;

 

(1)创建 ServerSocketChannel

 /**
     * Create a new instance
     */
    public NioServerSocketChannel() {
        this(newSocket(DEFAULT_SELECTOR_PROVIDER));
    }
newSocket(DEFAULT_SELECTOR_PROVIDER) :用来创建一个Java NIO的 ServerSocketChannel ;以下操作等于 ServerSocketChannel.open();为了解决性能问题(每次回进行加锁)
 private static final SelectorProvider DEFAULT_SELECTOR_PROVIDER = SelectorProvider.provider();

    private static final InternalLogger logger = InternalLoggerFactory.getInstance(NioServerSocketChannel.class);

    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>.
             */
            return provider.openServerSocketChannel();
        } catch (IOException e) {
            throw new ChannelException(
                    "Failed to open a server socket.", e);
        }
    }

(2)为ServerSocketChannel 注册感兴趣的键以及设置为非阻塞模式;

 protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
        super(parent);
        this.ch = ch;
        //感兴趣的key
        this.readInterestOp = readInterestOp;
        try {
        //设置为非阻塞模式
            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);
        }
    }    

(3).创建默认的 pipeline 以及unsafe 对象;

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

 

pipeline创建流程

无论在创建服务端还是处理客户端请求连接的时候,会对每一个客户端的连接创建一个NiosocketChannel 以及 pipeline组件;我们来看一看pipeline的创建流程;

首先需要知道的是pipeline 创建是跟随者NioServerSocketChannel 或者NioSocketChannel 一起创建的;

 

NioSocketChannel 与NioServerSocketChannel 都继承了AbstractNioChannel 这个抽象类,源码可知所以对于一些方法的实现以及pipeline 实现都是相同的

(1).进入AbstractNioChannel 的父类 AbstractChannel 构造函数,这里进行了pipeline 的创建

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

(2).在构造pipeline 会将当前的对象this(NioServerSocketChannel 或者NioSocketChannel 传进来),创建默认的channelpipeline;

protected DefaultChannelPipeline newChannelPipeline() {
        return new DefaultChannelPipeline(this);
    }

(3).接下来就是赋值操作

protected DefaultChannelPipeline(Channel channel) {
    //维护当前的channel 对象
        this.channel = ObjectUtil.checkNotNull(channel, "channel");
        succeededFuture = new SucceededChannelFuture(channel, null);
        voidPromise =  new VoidChannelPromise(channel, true);
        //创建尾巴哨兵
        tail = new TailContext(this);
        //创建头哨兵
        head = new HeadContext(this);
        //链表连起来,以后的addLat 操作就是基于这个链表的
        head.next = tail;
        tail.prev = head;
    }

 

pipeline 的addlast 方法会将我们的handler 转换为一个handlercontext 对象;

//新构造一个channelHandlerContext 对象            
newCtx = newContext(group, filterName(name, handler), handler);
//链表
 addLast0(newCtx);

 

 

用图表示的话就是:

  

 

 

netty新连接接入(即创建NioSocketChannel)

在上图中,在初始化channel 中,进行了新连接接入的方法,看一下吧;

void init(Channel channel) throws Exception {
    //获取用户配置的option 属性
        final Map<ChannelOption<?>, Object> options = options0();
        synchronized (options) {
            setChannelOptions(channel, options, logger);
        }
        //获取用户的attr属性
        final Map<AttributeKey<?>, Object> attrs = attrs0();
        synchronized (attrs) {
            for (Entry<AttributeKey<?>, Object> e: attrs.entrySet()) {
                @SuppressWarnings("unchecked")
                AttributeKey<Object> key = (AttributeKey<Object>) e.getKey();
                channel.attr(key).set(e.getValue());
            }
        }
        //得到NioServerSocketChannel pipeline
        ChannelPipeline p = channel.pipeline();

        final EventLoopGroup currentChildGroup = childGroup;
        final ChannelHandler currentChildHandler = childHandler;
        final Entry<ChannelOption<?>, Object>[] currentChildOptions;
        final Entry<AttributeKey<?>, Object>[] currentChildAttrs;
        synchronized (childOptions) {
            currentChildOptions = childOptions.entrySet().toArray(newOptionArray(childOptions.size()));
        }
        synchronized (childAttrs) {
            currentChildAttrs = childAttrs.entrySet().toArray(newAttrArray(childAttrs.size()));
        }
        //添加ServerBootstrapAcceptor 用来处理NioSocketChannel
        p.addLast(new ChannelInitializer<Channel>() {
            @Override
            public void initChannel(final Channel ch) throws Exception {
                final ChannelPipeline pipeline = ch.pipeline();
                ChannelHandler handler = config.handler();
                if (handler != null) {
                    pipeline.addLast(handler);
                }

                ch.eventLoop().execute(new Runnable() {
                    @Override
                    public void run() {
                        pipeline.addLast(new ServerBootstrapAcceptor(
                                ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));
                    }
                });
            }
        });
    }

 

经过这样之后,pipeline的结构就是这样的;可以说这个ServerBootStrapAcceptor 就是一个桥梁

我们看一下ServerBootStrapAcceptor 这个进站处理器一个核心方法,进行socketChannel 的注册以及监听

@Override
        @SuppressWarnings("unchecked")
        //这个传过来的msg 其实是NioSocketChannel 对象,这个我后面说
        public void channelRead(ChannelHandlerContext ctx, Object msg) {
            final Channel child = (Channel) msg;
        //为NioSocketChannel 的pipeline 进行添加我们定义的处理器
            child.pipeline().addLast(childHandler);

            setChannelOptions(child, childOptions, logger);

            for (Entry<AttributeKey<?>, Object> e: childAttrs) {
                child.attr((AttributeKey<Object>) e.getKey()).set(e.getValue());
            }

            try {
                //socketChannel 交给work 线程管理,注册监听其Read事件,并事件传播ad dhandler 等方法;
                childGroup.register(child).addListener(new ChannelFutureListener() {
                    @Override
                    public void operationComplete(ChannelFuture future) throws Exception {
                        if (!future.isSuccess()) {
                            forceClose(child, future.cause());
                        }
                    }
                });
            } catch (Throwable t) {
                forceClose(child, t);
            }
        }

 

到这里,估计疑惑的就是什么时候触发执行这个channelread方法呢?显而易见的,是我们的selector 轮询到有新链接接入的时候,即触发accept 方法

主要从绑定端口的操作开始的

private static void doBind0(
            final ChannelFuture regFuture, final Channel channel,
            final SocketAddress localAddress, final ChannelPromise promise) {

        // This method is invoked before channelRegistered() is triggered.  Give user handlers a chance to set up
        // the pipeline in its channelRegistered() implementation.
        //execute 方法,会进行selector 的轮询,可以点进去这个execute 内部,startThread 方法
        channel.eventLoop().execute(new Runnable() {
            @Override
            public void run() {
                if (regFuture.isSuccess()) {
                    channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
                } else {
                    promise.setFailure(regFuture.cause());
                }
            }
        });
    }

 

最终会运行到NioEventLoop 方法中的如下

private void processSelectedKey(SelectionKey k, AbstractNioChannel ch) {

 

我们主要看这个unsafe.read() 方法;NioServerSocketChannel 的unsafe 实现类是NioMessageUnsafe;

  if ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0) {
                unsafe.read();
            }

accept 一个SocketChannel,也就是Java nio 操作,并构造成一个NioSocketChannel ;

int localRead = doReadMessages(readBuf);
protected int doReadMessages(List<Object> buf) throws Exception {
        //jdk SocketChannel 
        SocketChannel ch = SocketUtils.accept(javaChannel());

        try {
            if (ch != null) {
            //构造成一个NioSocketChannel
                buf.add(new NioSocketChannel(this, ch));
                return 1;
            }
        } catch (Throwable t) {
            logger.warn("Failed to create a new channel from an accepted socket.", t);

            try {
                ch.close();
            } catch (Throwable t2) {
                logger.warn("Failed to close a socket.", t2);
            }
        }

        return 0;
    }

 

这样一个NioSocketChannel 就创建出来了;接下来就是连接的接入,监听read 事件;

 for (int i = 0; i < size; i ++) {
                    readPending = false;
//事件的传播,就会执行到ServerBootStrapAcceptor 的channelread 方法中,参数就是Niosocketchannel

                    pipeline.fireChannelRead(readBuf.get(i));
                }
                readBuf.clear();
                allocHandle.readComplete();
                pipeline.fireChannelReadComplete();

 流程图如下: 

 

 

线程轮询

(一)我们先看一看 EventLoopGroup 的初始化;

在此声明,Netty 是基于java NIO 的,建议知道java NIO 运行机制(Selector,Channel ,ByteBuffer ,zeroCopy) ,再阅读此篇文章,不然会一头雾水;

netty 是对javanio 的顶层封装扩展,所以对于一些底层的重要操作,还是基于Javanio的;

EventLoopGroup :事件循环组:

EventLoopGroup bossGroup =new NioEventLoopGroup();
EventLoopGroup workGroup =new NioEventLoopGroup();

主要是完成一些变量的赋值

主要发生了什么:Look,源码就是一层一层的调用构造函数,往里面赋值;

1.extends 多线程事件循环组, 被用于基于channel 的NIO selector 实现

/**
 * {@link MultithreadEventLoopGroup} implementations which is used for NIO {@link Selector} based {@link Channel}s.
 */
public class NioEventLoopGroup extends MultithreadEventLoopGroup {

2.我们一步一步点击下来,发现就是在它的构造函数里面调来调去,我们发现他创建了一个空的 Executor 对象 (java 1. 5 并发库重要内容,执行器,进行线程执行),以及 nThreads 线程数量为 0(这里的0并不是说我们给我们创建 0个线程,后面会有判断);

  */
    public NioEventLoopGroup() {
        this(0);
    }

    /**
     * Create a new instance using the specified number of threads, {@link ThreadFactory} and the
     * {@link SelectorProvider} which is returned by {@link SelectorProvider#provider()}.
     */
    public NioEventLoopGroup(int nThreads) {
        this(nThreads, (Executor) null);
    }

3.我们可以看到在这个构造方法里调用了  SelectorProvider.provider(),这个不陌生吧,在java nio 中创建selector 的Selector.open() 方法中其实调用的就是这个

/**
  * Create a new instance using the specified number of threads, the given {@link ThreadFactory} and the
  * {@link SelectorProvider} which is returned by {@link SelectorProvider#provider()}.
  */  

public NioEventLoopGroup(int nThreads, Executor executor) {
this(nThreads, executor, SelectorProvider.provider());
}

4.继续点,可以看到它又添加了一些新的内容 DefaultSelectStrategyFactory 工厂 Factory which uses the default select strategy.  默认的选择策略

public NioEventLoopGroup(
int nThreads, Executor executor, final SelectorProvider selectorProvider) {
this(nThreads, executor, selectorProvider, DefaultSelectStrategyFactory.INSTANCE);
}

//在这个构造方法里用添加了一个参数  DefaultSelectStrategyFactory.INSTANCE ,提供一个默认选择策略,工厂模式
/**
* Factory which uses the default select strategy.
*/
public final class DefaultSelectStrategyFactory implements SelectStrategyFactory {
public static final SelectStrategyFactory INSTANCE = new DefaultSelectStrategyFactory();

private DefaultSelectStrategyFactory() { }

@Override
public SelectStrategy newSelectStrategy() {
return DefaultSelectStrategy.INSTANCE;
}
}

5. 继续走,这里就开始调用父类super(MultithreadEventLoopGroup)方法了,在这里我们就可以知道默认给我们创建多少线程了;

public NioEventLoopGroup(int nThreads, Executor executor, final SelectorProvider selectorProvider,
final SelectStrategyFactory selectStrategyFactory) {
super(nThreads, executor, selectorProvider, selectStrategyFactory, RejectedExecutionHandlers.reject());
}



protected MultithreadEventLoopGroup(int nThreads, Executor executor, Object... args) { 
super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, executor, args); }


//分析线程数量 //线程数量判断,如果是0的话,就是 DEFAULT_EVENT_LOOP_THREADS ,是多少呢?我们点进去看一看,我们会看到一个静态代码块 static { DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt( "io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2)); if (logger.isDebugEnabled()) { logger.debug("-Dio.netty.eventLoopThreads: {}", DEFAULT_EVENT_LOOP_THREADS); } } //调用Runtime.availableProcessors将会获取 可用的处理器 @SuppressForbidden(reason = "to obtain default number of available processors") synchronized int availableProcessors() { if (this.availableProcessors == 0) { final int availableProcessors = SystemPropertyUtil.getInt( "io.netty.availableProcessors", Runtime.getRuntime().availableProcessors()); setAvailableProcessors(availableProcessors); } return this.availableProcessors; } 由此可以看到 默认创建的线程数不是0 而是根据不同电脑的处理器个数*2

6,接下来就是Excutor 的赋值了,因为从第二部可以看到,初始的Excutor 的null;

protected MultithreadEventExecutorGroup(int nThreads, Executor executor, Object... args) {
this(nThreads, executor, DefaultEventExecutorChooserFactory.INSTANCE, args);
}

protected MultithreadEventExecutorGroup(int nThreads, Executor executor,
EventExecutorChooserFactory chooserFactory, Object... args) {
if (nThreads <= 0) {
throw new IllegalArgumentException(String.format("nThreads: %d (expected: > 0)", nThreads));
}


//**********源码解释***********//
//我们看红色部分,就是对 executor 进行初始化操作,这里我们需要了解的是Excutor 接口 以及ThreadFactory 接口的作用
//在netty 里实现了ThreadFactory关于自己的DefaultThreadFactory
if (executor == null) {
executor = new ThreadPerTaskExecutor(newDefaultThreadFactory());
}

children = new EventExecutor[nThreads];

for (int i = 0; i < nThreads; i ++) {
boolean success = false;
try {
children[i] = newChild(executor, args);
success = true;
} catch (Exception e) {
// TODO: Think about if this is a good exception type
throw new IllegalStateException("failed to create a child event loop", e);
} finally {
if (!success) {
for (int j = 0; j < i; j ++) {
children[j].shutdownGracefully();
}

for (int j = 0; j < i; j ++) {
EventExecutor e = children[j];
try {
while (!e.isTerminated()) {
e.awaitTermination(Integer.MAX_VALUE, TimeUnit.SECONDS);
}
} catch (InterruptedException interrupted) {
// Let the caller handle the interruption.
Thread.currentThread().interrupt();
break;
}
}
}
}
}

chooser = chooserFactory.newChooser(children);

final FutureListener<Object> terminationListener = new FutureListener<Object>() {
@Override
public void operationComplete(Future<Object> future) throws Exception {
if (terminatedChildren.incrementAndGet() == children.length) {
terminationFuture.setSuccess(null);
}
}
};

for (EventExecutor e: children) {
e.terminationFuture().addListener(terminationListener);
}

Set<EventExecutor> childrenSet = new LinkedHashSet<EventExecutor>(children.length);
Collections.addAll(childrenSet, children);
readonlyChildren = Collections.unmodifiableSet(childrenSet);
                                               

 

 

 

posted on 2018-09-23 21:19  iscys  阅读(292)  评论(0编辑  收藏  举报