Netty源码解读------------ServerBootstrap的启动(一)
来源:互联网 发布:form表单转换成json 编辑:程序博客网 时间:2024/05/16 15:50
在阅读Netty源码之前,务必要学习nio的知识,否则很难理解。
自jdk1.4自后,便引入了nio的类库。为了提高nio的系统性能以及吞吐量,有人就在其基础上再次进行封装,便出了Netty框架。现在不少问nio的技术面试官,大部分会问到你用过Netty框架吗?读过它的源码吗?由此,我便尝试着解读其源码,一起和大家分享,^__^。
- Netty主要类
- ServerBootstrap
- NioServerSocketChannelFactory
- NioWorker
- PipeFactorySinkeFactory
- DefaultChannelPipeline
- Binder
- NioServerSocketPipelineSink
- NioServerSocketChannel
1. 首先分析它是如何启动监听的
package com.netty.test; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.channel.*; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; import org.jboss.netty.handler.codec.string.StringDecoder; import org.jboss.netty.handler.codec.string.StringEncoder; import java.net.InetSocketAddress; import java.util.concurrent.Executors; /** * God Bless You! * Author: Fangniude * Date: 2013-07-15 */ public class NettyServer { public static void main(String[] args) { ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool())); // Set up the default event pipeline. bootstrap.setPipelineFactory(new ChannelPipelineFactory() { public ChannelPipeline getPipeline() throws Exception { return Channels.pipeline(new StringDecoder(), new StringEncoder(), new ServerHandler()); } }); // Bind and start to accept incoming connections. Channel bind = bootstrap.bind(new InetSocketAddress(8000)); System.out.println("Server已经启动,监听端口: " + bind.getLocalAddress() + ", 等待客户端注册。。。"); } private static class ServerHandler extends SimpleChannelHandler { @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { if (e.getMessage() instanceof String) { String message = (String) e.getMessage(); System.out.println("Client发来:" + message); e.getChannel().write("Server已收到刚发送的:" + message); System.out.println("\n等待客户端输入。。。"); } super.messageReceived(ctx, e); } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { super.exceptionCaught(ctx, e); } @Override public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { System.out.println("有一个客户端注册上来了。。。"); System.out.println("Client:" + e.getChannel().getRemoteAddress()); System.out.println("Server:" + e.getChannel().getLocalAddress()); System.out.println("\n等待客户端输入。。。"); super.channelConnected(ctx, e); } } }
上面这段代码是启动服务器端的代码。
在ServerBootstrap里面bind方法是这样写的。
public Channel bind(final SocketAddress localAddress) { if (localAddress == null) { throw new NullPointerException("localAddress"); } //存储被注册的channel队列 final BlockingQueue<ChannelFuture> futureQueue = new LinkedBlockingQueue<ChannelFuture>(); //这是一个解析触发事件 实现了SimpleChannelUpstreamHandler ChannelHandler binder = new Binder(localAddress, futureQueue); //默认是空 ChannelHandler parentHandler = getParentHandler(); //存储事件和触发事件的对象 ChannelPipeline bossPipeline = pipeline(); bossPipeline.addLast("binder", binder); if (parentHandler != null) { bossPipeline.addLast("userHandler", parentHandler); } //通过ChannelFactory创建一个ServerSocketChannel对象 Channel channel = getFactory().newChannel(bossPipeline); // Wait until the future is available. ChannelFuture future = null; boolean interrupted = false; do { try { //获取NioServerSocketChannel对象 future = futureQueue.poll(Integer.MAX_VALUE, TimeUnit.SECONDS); } catch (InterruptedException e) { interrupted = true; } } while (future == null); if (interrupted) { Thread.currentThread().interrupt(); } // Wait for the future. future.awaitUninterruptibly(); if (!future.isSuccess()) { future.getChannel().close().awaitUninterruptibly(); throw new ChannelException("Failed to bind to: " + localAddress, future.getCause()); } return channel; }
下面看下 Channel channel = getFactory().newChannel(bossPipeline); 里面的写法。
NioServerSocketChannel( ChannelFactory factory, ChannelPipeline pipeline, ChannelSink sink) { super(factory, pipeline, sink); try { socket = ServerSocketChannel.open(); } catch (IOException e) { throw new ChannelException( "Failed to open a server socket.", e); } try { socket.configureBlocking(false); } catch (IOException e) { try { socket.close(); } catch (IOException e2) { logger.warn( "Failed to close a partially initialized socket.", e2); } throw new ChannelException("Failed to enter non-blocking mode.", e); } config = new DefaultServerSocketChannelConfig(socket.socket()); //注意这里, 这里是触发打开事件, 看这个里面的实现 fireChannelOpen(this); }
/** * Sends a {@code "channelOpen"} event to the first * {@link ChannelUpstreamHandler} in the {@link ChannelPipeline} of * the specified {@link Channel}. If the specified channel has a parent, * a {@code "childChannelOpen"} event will be sent, too. */ public static void fireChannelOpen(Channel channel) { // Notify the parent handler. if (channel.getParent() != null) { fireChildChannelStateChanged(channel.getParent(), channel); } //这个pipeline就是之前在ServerBootstrap放进去的DefaultPipeLine对象,当时放了2个handler进去了。 sendUpStream则是取出向上去取里面的handler对象, 然后做处理.这里触发的是OPEN事件,发的是TRUE值,后面会用到。 channel.getPipeline().sendUpstream( new UpstreamChannelStateEvent( channel, ChannelState.OPEN, Boolean.TRUE)); }void sendUpstream(DefaultChannelHandlerContext ctx, ChannelEvent e) { try { //看handlerUpstream代码 ((ChannelUpstreamHandler) ctx.getHandler()).handleUpstream(ctx, e); } catch (Throwable t) { notifyHandlerException(e, t); } }
/** * {@inheritDoc} Down-casts the received upstream event into more * meaningful sub-type event and calls an appropriate handler method with * the down-casted event. */ public void handleUpstream( ChannelHandlerContext ctx, ChannelEvent e) throws Exception { if (e instanceof MessageEvent) { messageReceived(ctx, (MessageEvent) e); } else if (e instanceof WriteCompletionEvent) { WriteCompletionEvent evt = (WriteCompletionEvent) e; writeComplete(ctx, evt); } else if (e instanceof ChildChannelStateEvent) { ChildChannelStateEvent evt = (ChildChannelStateEvent) e; if (evt.getChildChannel().isOpen()) { childChannelOpen(ctx, evt); } else { childChannelClosed(ctx, evt); } } else if (e instanceof ChannelStateEvent) { ChannelStateEvent evt = (ChannelStateEvent) e; switch (evt.getState()) { case OPEN: //发送的是OPEN事件,触发这里。 if (Boolean.TRUE.equals(evt.getValue())) { //Binder类里面的方法 channelOpen(ctx, evt); } else { channelClosed(ctx, evt); } break; case BOUND: if (evt.getValue() != null) { channelBound(ctx, evt); } else { channelUnbound(ctx, evt); } break; case CONNECTED: if (evt.getValue() != null) { channelConnected(ctx, evt); } else { channelDisconnected(ctx, evt); } break; case INTEREST_OPS: channelInterestChanged(ctx, evt); break; default: ctx.sendUpstream(e); } } else if (e instanceof ExceptionEvent) { exceptionCaught(ctx, (ExceptionEvent) e); } else { ctx.sendUpstream(e); } }
private final class Binder extends SimpleChannelUpstreamHandler { private final SocketAddress localAddress; private final BlockingQueue<ChannelFuture> futureQueue; private final Map<String, Object> childOptions = new HashMap<String, Object>(); Binder(SocketAddress localAddress, BlockingQueue<ChannelFuture> futureQueue) { this.localAddress = localAddress; this.futureQueue = futureQueue; } @Override public void channelOpen( ChannelHandlerContext ctx, ChannelStateEvent evt) { try { evt.getChannel().getConfig().setPipelineFactory(getPipelineFactory()); // Split options into two categories: parent and child. Map<String, Object> allOptions = getOptions(); Map<String, Object> parentOptions = new HashMap<String, Object>(); for (Entry<String, Object> e: allOptions.entrySet()) { if (e.getKey().startsWith("child.")) { childOptions.put( e.getKey().substring(6), e.getValue()); } else if (!e.getKey().equals("pipelineFactory")) { parentOptions.put(e.getKey(), e.getValue()); } } // Apply parent options. evt.getChannel().getConfig().setOptions(parentOptions); } finally { ctx.sendUpstream(evt); } //这里就是之前ServerBootstrap里面的futureQueue那个对象。存放了一个 boolean finished = futureQueue.offer(evt.getChannel().bind(localAddress)); assert finished; }
下节将会讲解Netty的socket监听以及读取信息。
1 0
- Netty源码解读------------ServerBootstrap的启动(一)
- Netty源码阅读(一) ServerBootstrap启动
- Netty源码阅读(一) ServerBootstrap启动
- java netty之ServerBootstrap的启动
- netty 之 ServerBootstrap的启动流程
- 【Netty源码学习】ServerBootStrap
- Netty源码分析:ServerBootstrap
- Netty源码学习-ServerBootstrap启动及事件处理过程
- netty源码分析之-ServerBootstrap启动流程分析(3)
- Netty 源码分析之 一 服务端创建(ServerBootstrap )
- netty源码学习一(Serverbootstrap引导程序)
- netty的引导程序ServerBootStrap
- netty源码分析(三)Netty服务端ServerBootstrap的初始化与反射在其中的应用分析
- Java NIO框架Netty教程(四) – ServerBootStrap启动流程源码分析
- Java NIO框架Netty教程(四) – ServerBootStrap启动流程源码分析
- Java NIO框架Netty教程(四) – ServerBootStrap启动流程源码分析
- Java NIO框架Netty教程(四) – ServerBootStrap启动流程源码分析
- Java NIO框架Netty教程(四) – ServerBootStrap启动流程源码分析
- xml字符串解析
- MySQL 如何存储大数据
- 33个2017年必须了解的iOS开源库
- 进击的NB-IoT:满眼望去,全是5G世界的样子
- malloc、calloc、realloc的区别
- Netty源码解读------------ServerBootstrap的启动(一)
- 关于直播,所有的技术细节都在这里了(一)
- 队列的链式存储结构
- 数据库服务器磁盘空间爆满导致锁等待超时
- 开源框架(整理)
- iOS几个github上的pod开源库
- Rxjava 快速上手
- CSS样式笔记
- jpa的一级和二级缓存