Netty源码分析(一)—服务端初始化
2017-11-22 15:31
696 查看
Netty源码分析(一)—服务端初始化
传统Java NIO在服务端启动时会涉及到ServerSocketChannel,Selector,selectorKey等类;Netty对Java NIO基础类进行了封装,减少用户开发工作量,降低开发难度;个人主页:tuzhenyu’s page
原文地址:Netty源码分析(一)—服务端初始化
(0) 服务端初始化
服务端初始化的步骤创建ServerBootstrap启动辅助类,通过Builder模式进行参数配置;
创建并绑定Reactor线程池EventLoopGroup;
设置并绑定服务端Channel通道类型;
绑定服务端通道数据处理器责任链Handler;
绑定并启动监听端口;
服务端初始化实例
public class TimeServer { private void bind(int port){ EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try{ ServerBootstrap b= new ServerBootstrap(); b.group(bossGroup,workerGroup).channel(NioServerSocketChannel.class) .option(ChannelOption.SO_BACKLOG,1024) .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel socketChannel) throws Exception { socketChannel.pipeline().addLast(new TimeServerHandler()); } }); ChannelFuture f = b.bind(port).sync(); f.channel().closeFuture().sync(); } catch (Exception e){ e.printStackTrace(); }finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } public static void main(String[] args) { new TimeServer().bind(8008); } }
(1) ServerBootstrap初始化
ServerBootstrap是netty启动辅助类,通过Builder模式进行参数设置4000
初始化;ServerBootstrap继承AbstracBootstrap类,需要对EventLoopGroup,Channel和ChannelHandler等参数进行配置;
public class ServerBootstrap extends AbstractBootstrap<ServerBootstrap, ServerChannel> { private final Map<ChannelOption<?>, Object> childOptions = new LinkedHashMap(); private final Map<AttributeKey<?>, Object> childAttrs = new LinkedHashMap(); private final ServerBootstrapConfig config = new ServerBootstrapConfig(this); private volatile EventLoopGroup childGroup; private volatile ChannelHandler childHandler; }
ServerBootstrap比其父类AbstractBootstrap多出四个part需要进行设置
(2) EventLoop线程池初始化
EventLoopGroup初始化是创建创建两个NioEventLoopGroup类型的Reactor线程池bossGroup和workGroup分别用来处理客户端的连接请求和通道IO事件;EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); ServerBootstrap b= new ServerBootstrap(); b.group(boosGroup,workGroup)
通过group()方法设置EventLoop
将bossGroup传入到AbstractBootstrap中设置到group属性上,将workGroup设置到ServerBootstrap的childGroup属性上;
如果只传入了一个EventLoopGroup则最后传入两个相同的group;
public ServerBootstrap group(EventLoopGroup group) { return this.group(group, group); } public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup) { super.group(parentGroup); if(childGroup == null) { throw new NullPointerException("childGroup"); } else if(this.childGroup != null) { throw new IllegalStateException("childGroup set already"); } else { this.childGroup = childGroup; return this; } }
super.group(parentGroup)方法对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通道等;ChannelFactory通道工程类设置
在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; } }
Channel通道实例化
配置好AbstractBootstrap的channelFactory工厂类,Channel的实例化通过ChannelFactory.newChannel()方法实现;具体的newChannel()方法的调用链是:ServerBootstrap.bind() -> AbstractBootstrap.doBind() -> AbstractBootstrap.initAndRegister() -> ChannelFactory.newChannel();
public T newChannel() { try { return (Channel)this.clazz.newInstance(); } catch (Throwable var2) { throw new ChannelException("Unable to create Channel from class " + this.clazz, var2); } }
通过clazz.newInstance()方法调用构造器创建NioServerSocketChannel实例
public NioServerSocketChannel() { this(newSocket(DEFAULT_SELECTOR_PROVIDER)); }
调用newSocket()方法创建ServerSocketChannel实例,这里的ServerSocketChannel和NIO中的ServerSocketChannel是同一个东西,接下来会调用父类构造器对其进行外部封装和相关参数的配置;
public NioServerSocketChannel(java.nio.channels.ServerSocketChannel channel) { super((Channel)null, channel, 16); this.config = new NioServerSocketChannel.NioServerSocketChannelConfig(this, this.javaChannel().socket()); }
在 NioServerSocketChannsl 实例化过程中, 所需要做的工作
调用 NioServerSocketChannel.newSocket(DEFAULT_SELECTOR_PROVIDER) 打开一个新的 Java NIO ServerSocketChannel
AbstractNioChannel 中的属性:
SelectableChannel ch 被设置为 Java ServerSocketChannel, 即 NioServerSocketChannel#newSocket 返回的 Java NIO ServerSocketChannel.
readInterestOp 被设置为 SelectionKey.OP_ACCEPT
SelectableChannel ch 被配置为非阻塞的 ch.configureBlocking(false)
AbstractChannel(Channel parent) 中初始化 AbstractChannel 的属性:
parent 属性置为 null
unsafe 通过newUnsafe() 实例化一个 unsafe 对象, 它的类型是 AbstractNioMessageChannel#AbstractNioUnsafe 内部类
pipeline 是 new DefaultChannelPipeline(this) 新创建的绑定管道实例.
NioServerSocketChannel 中的属性:
ServerSocketChannelConfig config = new NioServerSocketChannelConfig(this, javaChannel().socket())
Channel通道注册
在channel通道创建和初始化完毕后,会通过group.register()方法将channel通道注册到EventLoop线程池中;final ChannelFuture initAndRegister() { // 去掉非关键代码 final Channel channel = channelFactory().newChannel(); init(channel); ChannelFuture regFuture = group().register(channel); }
通过一系列的注册方法调用:AbstractBootstrap.initAndRegister -> MultithreadEventLoopGroup.register -> SingleThreadEventLoop.register -> AbstractUnsafe.register,最终是通过Unsafe类的register0()方法
private void register0(ChannelPromise promise) { boolean firstRegistration = neverRegistered; doRegister(); neverRegistered = false; registered = true; safeSetSuccess(promise); pipeline.fireChannelRegistered(); // Only fire a channelActive if the channel has never been registered. This prevents firing // multiple channel actives if the channel is deregistered and re-registered. if (firstRegistration && isActive()) { pipeline.fireChannelActive(); } }
register0()方法调用了doRegister()方法实现通道注册到线程池中(EventLoop线程池会绑定一个selector选择器)
@Override protected void doRegister() throws Exception { // 省略错误处理 selectionKey = javaChannel().register(eventLoop().selector, 0, this); }
(4)Pipeline管道初始化
每一个Channel通道在初始化时都会创建并绑定一个管道类,用来作为通道数据流的处理;pipeline管道的实例化是在AbstractChannel 的构造器中;在创建DefaultChannelPipeline实例时会传入一个Channel对象,这个Channel对象就是之前实例化的NioServerSocketChannel实例,将pipeline管道和channel通道进行绑定;
DefaultChannelPipeline中维护了一个以AbstractChannelHandlerContext为节点的双向链表,包含两个字段head和tail分别指向双向链表的头部和尾部;
public DefaultChannelPipeline(AbstractChannel channel) { if (channel == null) { throw new NullPointerException("channel"); } this.channel = channel; tail = new TailContext(this); head = new HeadContext(this); head.next = tail; tail.prev = head; }
(5)handler处理器的添加过程
我们可以自定义Handler处理器并将其加入到pipeline管道中,进而像插件一样自由组合各种handler完成具体的业务逻辑;添加handler的过程是获取与channel通道绑定的管道pipeline然后将自定义的handler添加进pipeline内部维护的一个双向链表;bootstrap.childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel socketChannel) throws Exception { socketChannel.pipeline().addLast(new TimeServerHandler()); } });
Bootstrap.childerHandler方法接收一个 ChannelHandler, 而我们传递的是一个 派生于ChannelInitializer的匿名类,它正好也实现了 ChannelHandler接口,因此将ChannelHandler实例赋值给ServerBootstrap的childHandler属性;
public ServerBootstrap childHandler(ChannelHandler childHandler) { if(childHandler == null) { throw new NullPointerException("childHandler"); } else { this.childHandler = childHandler; return this; } }
在启动服务端绑定端口时候最终通过调用initAndRegister()方法创建Channel实例,并将通过init()方法将系统定义的处理器ServerBootstrapAccptor添加到与channel绑定的pipeline通道中;
@Override void init(Channel channel) throws Exception { ... ChannelPipeline p = channel.pipeline(); final EventLoopGroup currentChildGroup = childGroup; final ChannelHandler currentChildHandler = childHandler; final Entry<ChannelOption<?>, Object>[] currentChildOptions; final Entry<AttributeKey<?>, Object>[] currentChildAttrs; p.addLast(new ChannelInitializer<Channel>() { @Override public void initChannel(Channel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); ChannelHandler handler = handler(); if (handler != null) { pipeline.addLast(handler); } pipeline.addLast(new ServerBootstrapAcceptor( currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs)); } }); }
在ServerBootstrapAcceptor中重写了channelRead()方法,将自定义的handler处理器添加到管道中;
public void channelRead(ChannelHandlerContext ctx, Object msg) { final Channel child = (Channel) msg; child.pipeline().addLast(childHandler); ... childGroup.register(child).addListener(...); }
服务器端的 handler 与 childHandler 的区别与联系:
服务器 NioServerSocketChannel 的 pipeline 中添加的是 handler 与 ServerBootstrapAcceptor.
当有新的客户端连接请求时, ServerBootstrapAcceptor.channelRead 中负责新建此连接的NioSocketChannel并添加 childHandler 到 NioSocketChannel 对应的pipeline中, 并将此channel绑定到workerGroup中的某个eventLoop中;
handler是在accept阶段起作用, 它处理客户端的连接请求,ServerBootstrap也能设置handler()方法添加ServerSocketChannel的自定义处理器;
总结
Netty服务端的初始化主要是创建初始化辅助类ServerBootstrap,并对辅助类的相关参数进行初始化包括EventLoop线程池,Channle通道类型和ChannleHandler通道处理器等;在调用bind()方法进行端口绑定时,会根据ServerBootsrap中的初始化参数启动服务端,具体的启动流程为:
创建ServerBootstrap启动辅助类实例,并对其Channel,EventLoopGroup,Handler等参数进行配置;
调用bootstrap.bind()方法时触发启动,会根据配置的Channle类型创建Channel实例,比如NioServerSocketChannel等
在实例化Channel时候会初始化Pipeline管道并与AbstractChannel绑定
将channel管道注册到EventLoopGroup线程池中,从线程池中轮询获取一个线程EventLoop并与之绑定;
启动线程,线程执行绑定的selector的select()方法监听注册的channel的状态,并执行定时任务
相关文章推荐
- netty源码分析(三)Netty服务端ServerBootstrap的初始化与反射在其中的应用分析
- Netty学习之旅----源码分析netty服务端初始化流程(Reactor主从模式实现)
- Netty源码分析之服务端启动过程
- 【Netty源码分析】Netty服务端bind端口过程
- Netty 4.0源码分析1:服务端启动过程中的Channel与EventLoopGroup的注册
- Netty源码分析:服务端启动全过程(篇幅很长)
- dubbo源码分析-客户端DubboInvoker调用服务端体会Netty的非阻塞IO使用
- [netty源码分析]--服务端启动的工作流程分析
- Netty 源码分析之 一 服务端创建(ServerBootstrap )
- netty源码分析之-服务端启动核心源码分析(5)
- netty源码分析之服务端启动
- netty 5 alph1源码分析(服务端创建过程)
- netty源码分析之服务端启动全解析
- netty源码分析之服务端启动全解析
- 【Netty源码分析】客户端connect服务端过程
- Netty4 服务端启动源码分析-线程的创建
- netty 服务端发布源码分析
- netty源码分析之服务端
- ZooKeeper服务端单机版 ZooKeeperServer初始化源码分析
- 【Netty源码分析】客户端connect服务端过程