淘客网站怎么做代理怎样创建网站赚钱
- 作者: 五速梦信息网
- 时间: 2026年03月21日 08:22
当前位置: 首页 > news >正文
淘客网站怎么做代理,怎样创建网站赚钱,个人crm,设计海报Netty源码解析——服务端启动 Netty案例复习Netty原理复习Netty服务端启动源码解析bind(int)initAndRegister()channelFactory.newChannel()init(channel)config().group().register(channel)startThread()run()register0(ChannelPromise promise)doBind0(…) 今天我们一起来学… Netty源码解析——服务端启动 Netty案例复习Netty原理复习Netty服务端启动源码解析bind(int)initAndRegister()channelFactory.newChannel()init(channel)config().group().register(channel)startThread()run()register0(ChannelPromise promise)doBind0(…) 今天我们一起来学习Netty源码对Netty有一个深入的认知既能掌握其使用和原理又能对它底层的设计有一个大概的认知
Netty案例复习
在阅读源码前我们再看一下Netty服务端的启动代码 public static void main(String[] args) throws Exception {EventLoopGroup bossGroup new NioEventLoopGroup(1);EventLoopGroup workerGroup new NioEventLoopGroup();try {ServerBootstrap b new ServerBootstrap();b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 100).handler(new LoggingHandler(LogLevel.INFO)).childHandler(new ChannelInitializerSocketChannel() {Overridepublic void initChannel(SocketChannel ch) throws Exception {ChannelPipeline p ch.pipeline();p.addLast(new EchoServerHandler());}});ChannelFuture f b.bind(PORT).sync();f.channel().closeFuture().sync();} finally {bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();}}我们创建了两个EventLoopGroup已经然后设置到ServerBootstrap上bossGroup中的EventLoop处理accept事件workerGroup中的EventLoop处理read事件时。再通过ServerBootstrap设置好一些其他的参数其中包括Netty服务端接收连接请求用的NioServerSocketChannelNioServerSocketChannel会注册到bossGroup上监听accept事件然后设置好ChannelInitializer服务端接收到客户端连接之后会创建一个NioSocketChannelChannelInitializer就是用于初始化连接建立成功后的NioSocketChannel最后就是通过ServerBootstrap的bind(int inetPort)绑定一个端口 Netty原理复习
我们再来复习一下Netty的原理带着对Netty原理的认知去看源码效率才会高不至于走偏。 当调用了ServerBootstrap的bind(int inetPort)绑定端口后我们注册的NioServerSocketChannel就会被注册到bossGroup上的唯一一个NioEventLoop上然后NioEventLoop会把ServerSocketChannel注册到Selector上监听accept事件并启动事件循环当有客户端连接后boosGroup中的EventLoop会获得一个SocketChannel然后将其包装成NioSocketChannel然后NioServerSocketChannel对应的ChannelHandler会把它注册到workerGroup中workerGroup会将NioSocketChannel注册到其中一个NioEventLoop上并使用我们配置的ChannelInitializer初始化NioSocketChannelworkerGroup中的NioEventLoop的事件循环中监听到Channel有read事件时发生就会调用Channel对应的ChannelPipeline进行处理ChannelPipeline通过责任链模式逐一调用pipeline上的ChannelHandler处理事件
Netty服务端启动源码解析
接下来我们就开始读源码了我们从ServerBootstrap的bind方法走起。
bind(int) /*** Create a new {link Channel} and bind it.*/public ChannelFuture bind(int inetPort) {return bind(new InetSocketAddress(inetPort));}bind方法的作用就是创建一个Channel并绑定端口创建的Channel类型就是我们指定的NioServerSocketChannel。
bind方法会调用doBind方法。 private ChannelFuture doBind(final SocketAddress localAddress) {final ChannelFuture regFuture initAndRegister();…doBind0(regFuture, channel, localAddress, promise);…}省略了非关键代码后剩下的就是关键的两行
initAndRegister()方法做的事情就是创建并初始化Channel然后注册到NioEventLoop上。doBind0(…)方法给NioServerSocockChannel中的ServerSocketChannel绑定端口。 initAndRegister()
我们进入initAndRegister()方法同样是只看核心代码其他的代码不关心。 final ChannelFuture initAndRegister() {…channel channelFactory.newChannel();init(channel);…ChannelFuture regFuture config().group().register(channel);…}channelFactory.newChannel()反射调用NioServerSocketChannel的构造方法进行实例化。init(channel)为NioServerSocketChannel的ChannelPipeline添加ChannelInitializer。config().group().register(channel)把NioServerSocketChannel中的ServerSocketChannel注册到workerGroup的NioEventLoop的Selector上。 channelFactory.newChannel()
channelFactory.newChannel()会进入到ReflectiveChannelFactory的newChannel()方法里面就是调用Constructor构造器的newInstance()方法反射实例化一个Channel这个构造器就是NioServerSocketChannel的构造器。是在我们调用ServerBootstrap的channel(NioServerSocketChannel.class)方法时设置进去的。
我们进入NioServerSocketChannel的构造方法看看。 public NioServerSocketChannel() {this(newSocket(DEFAULT_SELECTOR_PROVIDER));}newSocket(…)方法就是创建了一个NIO原生的ServerSocketChannel然后进入重载的构造方法。 public NioServerSocketChannel(ServerSocketChannel channel) {super(null, channel, SelectionKey.OP_ACCEPT);config new NioServerSocketChannelConfig(this, javaChannel().socket());}继续调用父类的构造方法可以看到指定了事件类型是accept事件。然后进入到父类AbstractNioChannel的构造方法。 protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {super(parent);this.ch ch;this.readInterestOp readInterestOp;…ch.configureBlocking(false);…}AbstractNioChannel的构造方法除了继续调用父类的构造方法以外还保存了ServerSocketChannel和关注的事件类型OP_ACCEPT然后设置ServerSocketChannel为非阻塞。
继续进入父类的构造方法。 protected AbstractChannel(Channel parent) {…unsafe newUnsafe();pipeline newChannelPipeline();}创建了一个unsafe对象和一个ChannelPipeline。unsafe其实是Netty内部自己使用的一个工具类先不用管后面会看到怎么用这里看看如何创建ChannelPipeline。 protected DefaultChannelPipeline(Channel channel) {…tail new TailContext(this);head new HeadContext(this);head.next tail;tail.prev head;}我们知道ChannelPipeline中的ChannelHandler都是包在ChannelHandlerContext里面的而这里先创建了一个头部Context和尾部Context。
也就是这样 channelFactory.newChannel()的大体逻辑如下
init(channel)
我们回到initAndRegister()方法再来看init方法。 Overridevoid init(Channel channel) {…ChannelPipeline p channel.pipeline();…p.addLast(new ChannelInitializerChannel() {Overridepublic void initChannel(final Channel ch) {…ch.eventLoop().execute(new Runnable() {Overridepublic void run() {pipeline.addLast(new ServerBootstrapAcceptor(ch, currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));}});}});}init方法就是拿到NioServerSocketChannel的ChannelPipeline往里面添加了一个ChannelInitializerChannelInitializer会在ServerSocketChannel被注册到Selector后异步的给ChannelPipeline添加一个ServerBootstrapAcceptor这个ServerBootstrapAcceptor是一个专门处理连接事件的Handler。当然ChannelInitializer还会从ChannelPipeline中把自己删除。 config().group().register(channel)
我们回到initAndRegister()方法再往后看一下config().group().register(channel)。 Overridepublic ChannelFuture register(Channel channel) {return next().register(channel);}进入NioEventLoopGroup的父类MultithreadEventLoopGroup的register方法中。next()方法返回一个NioEventLoop然后调用NioEventLoop的register(channel)方法。进入到NioEventLoop的父类SingleThreadEventLoop的register方法中。 Overridepublic ChannelFuture register(final ChannelPromise promise) {…promise.channel().unsafe().register(this, promise);…}promise.channel().unsafe()获取到NioServerSocketChannel中的Unsafe对象然后调用Unsafe对象的register(…) Overridepublic final void register(EventLoop eventLoop, final ChannelPromise promise) {…if (eventLoop.inEventLoop()) {register0(promise);} else {…eventLoop.execute(new Runnable() {Overridepublic void run() {register0(promise);}});… }}Unsafe的register方法中判断当前线程是否是eventLoop的线程如果是直接调用register0方法注册Channel否则调用eventLoop的execute方法开启一个任务异步注册Channel。 private void execute(Runnable task, boolean immediate) {boolean inEventLoop inEventLoop();addTask(task);if (!inEventLoop) {startThread();…}…}execute方法首先调用addTask(task)方法把这个任务放入taskQueue中。然后判断当选线程不是当前EventLoop的线程因此调用startThread()开启EventLoop的线程启动事件循环。 addTask方法就是把这个Runnable放入到NioEventLoop内部的队列当中taskQueue中在NioEventLoop的事件循环的每一轮的最后会处理taskQueue中的任务我们就不细看了。我们接下来看一下startThread方法。
startThread() private void startThread() {if (state ST_NOT_STARTED) {if (STATE_UPDATER.compareAndSet(this, ST_NOT_STARTED, ST_STARTED)) {…doStartThread();…}}}startThread方法先修改NioEventLoop的状态state为开启防止再次调用startThread方法的时候重复开启线程。然后调用doStartThread()方法。 private void doStartThread() {…executor.execute(new Runnable() {Overridepublic void run() {…SingleThreadEventExecutor.this.run();…}});}doStartThread()方法里面调用了executor的execute方法异步执行SingleThreadEventExecutor.this.run()方法这个run方法就会进入到NioEventLoop的run方法中里面就是事件循环。
这个executor其实是一个单线程的线程池可以看做就是NioEventLoop的唯一一个线程startThread方法并没有再创建一个线程而是往NioEventLoop预先创建好的线程提交一个任务这个任务会启动NioEventLoop的事件循环。 run()
接下来进入NioEventLoop的run方法看看所谓的事件循环是什么。 Overrideprotected void run() {…for (;;) {…strategy select(curDeadlineNanos);if (strategy 0) {processSelectedKeys();}…runAllTasks();…}}可以看到就是先调用select方法这个select方法自然是调用NioEventLoop的Selector的select方法当然现在还没有任何Channel被注册因此这里是不会select到东西的。然后processSelectedKeys()是处理所有就绪事件的方法因为这里还没有Channel被注册自然也没有就绪事件发生。因此最后只有runAllTasks()被执行也就是获取taskQueue中刚刚放进去的任务这个任务的执行就会触发ServerSocketChannel的注册。 runAlllTasks方法执行taskQueue中目前唯一一个的任务也就是刚刚放进去的用于注册ServerSocketChannel的任务这个任务会调用Unsafe的register0(ChannelPromise promise)方法。
register0(ChannelPromise promise) private void register0(ChannelPromise promise) {…doRegister();…}register0调用doRegister()方法进入AbstractNioChannel的doRegister()方法。 Overrideprotected void doRegister() throws Exception {…selectionKey javaChannel().register(eventLoop().unwrappedSelector(), 0, this);…}doRegister方法中把Channel注册到Selector的代码就是上面这一行javaChannel()返回NIO原生的Channel类型然后调用register方法eventLoop().unwrappedSelector()返回的就是Selector这个Selector作为register方法的参数这样NIO的Channel就被注册到Selector中了这里的Channel当然是ServerSocketChannel。 这里注册完ServerSocketChannel之后就会调用ChannelInitializer初始化ChannelPipeline。
doBind0(…)
我们回调doBind方法initAndRegister()方法就已经看完了再看下面的doBind0方法。 private static void doBind0(…,final Channel channel,…) {channel.eventLoop().execute(new Runnable() {Overridepublic void run() {…channel.bind(localAddress, promise).addListener(ChannelFutureListener.CLOSE_ON_FAILURE);…}});}dobind0()方法也是通过NioEventLoop执行异步任务的方式去绑定端口channel.bind(localAddress, promise)方法最终会进入NioServerSocketChannel的doBind(SocketAddress localAddress)方法。 protected void doBind(SocketAddress localAddress) throws Exception {if (PlatformDependent.javaVersion() 7) {javaChannel().bind(localAddress, config.getBacklog());} else {javaChannel().socket().bind(localAddress, config.getBacklog());}}然后就是调用ServerSocketChannel的bind(SocketAddress local, int backlog)方法绑定指定端口。 至此Netty服务端就启动起来下面是Netty服务端启动的源码流程图。 服务端启动之后就可以接收并处理客户端的请求了后续的流程就放到下一次再作分析。
- 上一篇: 淘客网站咋做许昌建网站
- 下一篇: 淘客网站怎么做排名简单描述什么是网络营销
相关文章
-
淘客网站咋做许昌建网站
淘客网站咋做许昌建网站
- 技术栈
- 2026年03月21日
-
淘客网站添加到桌面适合做外链的网站
淘客网站添加到桌面适合做外链的网站
- 技术栈
- 2026年03月21日
-
淘客网站是怎么做的郑州哪有做网站的汉狮
淘客网站是怎么做的郑州哪有做网站的汉狮
- 技术栈
- 2026年03月21日
-
淘客网站怎么做排名简单描述什么是网络营销
淘客网站怎么做排名简单描述什么是网络营销
- 技术栈
- 2026年03月21日
-
淘客怎么建网站做推广广州门户网站
淘客怎么建网站做推广广州门户网站
- 技术栈
- 2026年03月21日
-
淘客怎么做网站单页有什么网站专门做美食的吗
淘客怎么做网站单页有什么网站专门做美食的吗
- 技术栈
- 2026年03月21日
