上一篇粗略的介绍了一下netty,本篇将详细介绍Netty的服务器的启动过程。
ServerBootstrap
看过上篇事例的人,可以知道ServerBootstrap是Netty服务端启动中扮演着一个重要的角色。 它是Netty提供的一个服务端引导类,继承自AbstractBootstrap。
ServerBootstrap主要包括两部分:bossGroup和workerGroup。其中bossGroup主要用于绑定端口,接收来自客户端的请求,接收到请求之后,就会把这些请求交给workGroup去处理。就像现实中的老板和员工一样,自己开个公司(绑定端口),到外面接活(接收请求),使唤员工干活(让worker去处理)。
端口绑定
端口绑定之前,会先check引导类(ServerBootstrap)的bossGroup和workerGroup有没有设置,之后再调用doBind。
1 private ChannelFuture doBind(final SocketAddress localAddress) { 2 // 初始化并注册一个channel,并将chanelFuture返回 3 final ChannelFuture regFuture = initAndRegister(); 4 // 得到实际的channel(初始化和注册的动作可能尚未完成) 5 final Channel channel = regFuture.channel(); 6 // 发生异常时,直接返回 7 if (regFuture.cause() != null) { 8 return regFuture; 9 } 10 // 当到这chanel相关处理已经完成时 11 if (regFuture.isDone()) { 12 // 到这可以确定channel已经注册成功 13 ChannelPromise promise = channel.newPromise(); 14 // 进行相关的绑定操作 15 doBind0(regFuture, channel, localAddress, promise); 16 return promise; 17 } else { 18 // 注册一般到这就已经完成,到以防万一 19 final PendingRegistrationPromise promise = new PendingRegistrationPromise(channel); 20 // 添加一个监听器 21 regFuture.addListener(new ChannelFutureListener() { 22 @Override 23 public void operationComplete(ChannelFuture future) throws Exception { 24 Throwable cause = future.cause(); 25 if (cause != null) { 26 promise.setFailure(cause); 27 } else { 28 // 修改注册状态为成功(当注册成功时不在使用全局的executor,使用channel自己的,详见 https://github.com/netty/netty/issues/2586) 29 promise.registered(); 30 // 进行相关的绑定操作 31 doBind0(regFuture, channel, localAddress, promise); 32 } 33 } 34 }); 35 return promise; 36 } 37 }
上面的代码主要有两部分:初始化并注册一个channel和绑定端口。
初始化并注册一个channel
1 final ChannelFuture initAndRegister() { 2 Channel channel = null; 3 try { 4 // 生产各新channel 5 channel = channelFactory.newChannel(); 6 // 初始化channel 7 init(channel); 8 } catch (Throwable t) { 9 if (channel != null) { 10 // 注册失败时强制关闭 11 channel.unsafe().closeForcibly(); 12 // 由于channel尚未注册好,强制使用GlobalEventExecutor 13 return new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE).setFailure(t); 14 } 15 return new DefaultChannelPromise(new FailedChannel(), GlobalEventExecutor.INSTANCE).setFailure(t); 16 } 17 // 注册channel 18 ChannelFuture regFuture = config().group().register(channel); 19 if (regFuture.cause() != null) { 20 if (channel.isRegistered()) { 21 channel.close(); 22 } else { 23 channel.unsafe().closeForcibly(); 24 } 25 } 26 return regFuture; 27 }
channel的初始化方法:
1 void init(Channel channel) throws Exception { 2 // 获取bossChannel的可选项Map 3 final Map<ChannelOption<?>, Object> options = options0(); 4 synchronized (options) { 5 setChannelOptions(channel, options, logger); 6 } 7 // 获取bossChannel的属性Map 8 final Map<AttributeKey<?>, Object> attrs = attrs0(); 9 synchronized (attrs) { 10 for (Entry<AttributeKey<?>, Object> e : attrs.entrySet()) { 11 @SuppressWarnings("unchecked") 12 AttributeKey<Object> key = (AttributeKey<Object>) e.getKey(); 13 channel.attr(key).set(e.getValue()); 14 } 15 } 16 ChannelPipeline p = channel.pipeline(); 17 // 设置worker的相关属性 18 final EventLoopGroup currentChildGroup = childGroup; 19 final ChannelHandler currentChildHandler = childHandler; 20 final Entry<ChannelOption<?>, Object>[] currentChildOptions; 21 final Entry<AttributeKey<?>, Object>[] currentChildAttrs; 22 synchronized (childOptions) { 23 currentChildOptions = childOptions.entrySet().toArray(newOptionArray(childOptions.size())); 24 } 25 synchronized (childAttrs) { 26 currentChildAttrs = childAttrs.entrySet().toArray(newAttrArray(childAttrs.size())); 27 } 28 p.addLast(new ChannelInitializer<Channel>() { 29 @Override 30 public void initChannel(final Channel ch) throws Exception { 31 final ChannelPipeline pipeline = ch.pipeline(); 32 // 添加handler到pipeline 33 ChannelHandler handler = config.handler(); 34 if (handler != null) { 35 pipeline.addLast(handler); 36 } 37 // 通过EventLoop将ServerBootstrapAcceptor到pipeline中,保证它是最后一个handler 38 ch.eventLoop().execute(new Runnable() { 39 @Override 40 public void run() { 41 pipeline.addLast(new ServerBootstrapAcceptor( 42 ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs)); 43 } 44 }); 45 } 46 }); 47 }
channel的注册方法,最终是调用doRegister,不同的channel有所不同,下面以Nio为例:
1 protected void doRegister() throws Exception { 2 boolean selected = false; 3 for (; ; ) { 4 try { 5 // 直接调用java的提供的Channel的注册方法 6 selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this); 7 return; 8 } catch (CancelledKeyException e) { 9 if (!selected) { 10 eventLoop().selectNow(); 11 selected = true; 12 } else { 13 throw e; 14 } 15 } 16 } 17 }
绑定端口
最终调用的是NioServerSocketChannel的doBind方法。
1 protected void doBind(SocketAddress localAddress) throws Exception { 2 if (PlatformDependent.javaVersion() >= 7) { 3 javaChannel().bind(localAddress, config.getBacklog()); 4 } else { 5 javaChannel().socket().bind(localAddress, config.getBacklog()); 6 } 7 }
到这就完成了netty服务端的整个启动过程。
文中帖的代码注释全在:https://github.com/KAMIJYOUDOUMA/nettyForAnalysis.git , 有兴趣的童鞋可以关注一下。
本篇到此结束,如果读完觉得有收获的话,欢迎点赞、关注、加公众号【贰级天災】,查阅更多精彩历史!!!
