当前位置: 首页 > news >正文

杭州外贸建站公司小游戏入口免费游戏

杭州外贸建站公司,小游戏入口免费游戏,网络广告类型有哪几种,江苏省建筑工程网1 Pipeline设计原理 在Netty中每个Channel都有且仅有一个ChannelPipeline与之对应#xff0c;它们的组成关系如下图#xff1a; 通过上图可以看到#xff0c;一个Channel包含了一个ChannelPipeline#xff0c;而ChannelPipeline中又维护了一个由ChannelHandlerContext组成的…1 Pipeline设计原理 在Netty中每个Channel都有且仅有一个ChannelPipeline与之对应它们的组成关系如下图 通过上图可以看到一个Channel包含了一个ChannelPipeline而ChannelPipeline中又维护了一个由ChannelHandlerContext组成的双向链表。这个链表的头是HeadContext链表的尾是TailContext并且每个ChannelHandlerContext又关联着一个ChannelHandler。 通过分析代码已经知道了一个Channel初始化的基本过程下面在回顾一下。AbstractChannel构造器的代码如下 protected AbstractChannel(Channel parent) {this.parent parent;id newId();unsafe newUnsafe();pipeline newChannelPipeline();} AbstractChannel有一个pipeline属性在构造器中会把它初始化为DefaultChannelPipeline的实例。这里的代码就印证了这一点每个Channel都有一个ChannelPipeline。来看一下DefaultChannelPipeline的构造器代码如下 protected DefaultChannelPipeline(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);head.next tail;tail.prev head;} 在DefaultChannelPipeline构造器中首先将与之关联的Channel保存到属性channel中。然后实例化两个ChannelHandlerContext一个是HeadContext实例Head另一个是TailContext实例Tail。接着将Head和Tail互相指向构成一个双向链表。 特别注意的是在开始的示意图中Head和Tail并没有包含ChannelHandler这是因为HeadContext和TailContext继承于AbstractChannelHandlerContext的同时也实现了ChannelHandler接口所以它们有Context和Handler的双重属性。 2 ChannelPipeline初始化 下面看一下ChannelPipeline的初始化具体做了哪些工作。先回顾一下在实例化一个Channel时会伴随着一个ChannelPipeline的实例化并且此Channel会与这个ChannelPipeline相互关联这一点可以通过NioEventLoop的父类AbstractChannel的构造器予以佐证代码如下 protected AbstractChannel(Channel parent) {this.parent parent;id newId();unsafe newUnsafe();pipeline newChannelPipeline();} 当实例化一个NioSocketChannel时其pipeline属性就是新创建的DefaultChannelPipeline对象再来回顾一下DefaultChannelPipeline的构造方法代码如下 protected DefaultChannelPipeline(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);head.next tail;tail.prev head;} 上面代码中的Head实现了ChannelInboundHandler接口而Tail实现了ChannelOutboundHandler接口因此可以说Head和Tail就是ChannelHandler又是ChannelHandlerContext。 3 ChannelInitializer的添加 前面分析过Channel的组成最开始的时候ChannelPipeline中含有两个ChannelHandlerContext但是此时的Pipeline并不能实现特定的功能因为还没有添加自定义的ChannelHandler。通常来说在初始化Bootstrap时会添加自定义的ChannelHandler下面就以具体的客户端启动代码片段举例 Bootstrap bootstrap new Bootstrap();bootstrap.group(group).channel(NioSocketChannel.class).option(ChannelOption.SO_KEEPALIVE,true).handler(new ChannelInitializerSocketChannel() {Overrideprotected void initChannel(SocketChannel socketChannel) throws Exception {ChannelPipeline pipeline socketChannel.pipeline();pipeline.addLast(new StringDecoder());pipeline.addLast(new StringEncoder());System.out.println(初始化channel: socketChannel);}}); 在调用Handler时传入ChannelInitializer对象它提供了一个initChannel方法来初始化ChannelHandler。通过代码跟踪发现ChannelInitializer是在Bootstrap的init方法中添加到ChannelPipiline中的代码如下 void init(Channel channel) throws Exception {ChannelPipeline p channel.pipeline();p.addLast(new ChannelHandler[]{this.config.handler()});MapChannelOption?, Object options this.options0();synchronized(options) {Iterator i$ options.entrySet().iterator();while(true) {if (!i$.hasNext()) {break;}Entry e (Entry)i$.next();try {if (!channel.config().setOption((ChannelOption)e.getKey(), e.getValue())) {logger.warn(Unknown channel option: e);}} catch (Throwable var10) {logger.warn(Failed to set a channel option: channel, var10);}}}MapAttributeKey?, Object attrs this.attrs0();synchronized(attrs) {Iterator i$ attrs.entrySet().iterator();while(i$.hasNext()) {EntryAttributeKey?, Object e (Entry)i$.next();channel.attr((AttributeKey)e.getKey()).set(e.getValue());}}} 从上面的代码可见将handler()方法返回的ChannelHandler添加到Pipeline中而handler()方法返回的其实就是在初始化Bootstrap时通过handler方法设置的ChannelInitializer实例因此这里就将ChannelInitializer插到了Pipieline的末端。此时Pipeline的结构如下图所示 这是会有一个疑问明明插入的是 ChannelInitializer实例为什么在ChannelPipeline的双向链表中的元素却是一个ChannelHandlerContext呢继续看源码在Bootstrap的init方法中会调用p.addList()方法将ChannelInitializer插入链表的末端代码如下 Overridepublic final ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler) {final AbstractChannelHandlerContext newCtx;synchronized (this) {checkMultiplicity(handler);newCtx newContext(group, filterName(name, handler), handler);addLast0(newCtx);// If the registered is false it means that the channel was not registered on an eventloop yet.// In this case we add the context to the pipeline and add a task that will call// ChannelHandler.handlerAdded(...) once the channel is registered.if (!registered) {newCtx.setAddPending();callHandlerCallbackLater(newCtx, true);return this;}EventExecutor executor newCtx.executor();if (!executor.inEventLoop()) {newCtx.setAddPending();executor.execute(new Runnable() {Overridepublic void run() {callHandlerAdded0(newCtx);}});return this;}}callHandlerAdded0(newCtx);return this;} addList方法有很多重载的方法只需要关注这个方法即可。上面的addList方法中首先检查ChannelHandler的名字是否重复如果不重复则调用newContext方法为这个Handler创建一个对应的DefaultChannelHandlerContext实例并与之关联起来。 为了添加一个Handler到Pipeline中必须把此Handler包装成ChannelHandlerContext。因此在上面的代码中我们新实例化一个newCx对象并将Handler作为参数传递到构造方法中。下面来看一下DefaultChannelHandlerContext的构造器。 DefaultChannelHandlerContext(DefaultChannelPipeline pipeline, EventExecutor executor, String name, ChannelHandler handler) {super(pipeline, executor, name, isInbound(handler), isOutbound(handler));if (handler null) {throw new NullPointerException(handler);}this.handler handler;} 在DefaultChannelHandlerContext的构造器中调用了isInbound()方法和isOutbound()方法这两个方法的代码如下 private static boolean isInbound(ChannelHandler handler) {return handler instanceof ChannelInboundHandler;}private static boolean isOutbound(ChannelHandler handler) {return handler instanceof ChannelOutboundHandler;} 从上面代码中可以看到当一个Handler实现了ChannelInboundHandler接口则isInbound返回true类似的当一个Handler实现了ChannelOutboundHandler接口则isOuntbound返回true。而这两个boolean类型变量会传递给父类AbstractChannelHandlerContext中并初始化父类的两个属性inbound和outbound。 这里的ChannelInitializer所对应的DefaultChannelHandlerContext的inbound与outbound属性分别是什么呢先来看ChannelInitializer的类层次结构图如下图 可以看到ChannelInitializer仅仅实现了ChannelInboundHandler接口因此这里实例化的DefaultChannelHandlerContext的inbound是trueoutbound是false。 inbound和outbound这两个属性关系到Pipeline事件的流向与分类因此十分关键。这里先记住一个结论ChannelInitializer所对应的DefaultChannelHandlerContext的inboundtrueoutboundfalse。 当创建好Context之后就将这个Context插入Pipeline的双向链表中。 DefaultChannelPipeline.java private void addLast0(AbstractChannelHandlerContext newCtx) {AbstractChannelHandlerContext prev tail.prev;newCtx.prev prev;newCtx.next tail;prev.next newCtx;tail.prev newCtx;} 添加完ChannelInitializer的Pipeline内部如下图所示 4 自定义ChannelHandler的添加过程 上面分析了ChannelInitializer是如何插入Pipeline中的接下来探讨ChannelInitializer在哪里被调用、ChannelInitializer的作用以及自定义的ChannelHandler是如何插入Pipeline中的。 自定义ChannelHandler的添加过程发生在AbstractUnsafe的register方法中在这个方法中调用了pipeline.fireChannelRegister()方法代码如下 Overridepublic final ChannelPipeline fireChannelRegistered() {AbstractChannelHandlerContext.invokeChannelRegistered(head);return this;} 再看AbstractChannelHandlerContext的invokeChannelRegister()方法。 static void invokeChannelRegistered(final AbstractChannelHandlerContext next) {EventExecutor executor next.executor();if (executor.inEventLoop()) {next.invokeChannelRegistered();} else {executor.execute(new Runnable() {Overridepublic void run() {next.invokeChannelRegistered();}});}} 很显然这个代码将从Head开始遍历Pipeline的双向链表然后找到第一个属性inbound为true的ChannelHandlerContext实例。在分析ChannelInitializer时专门分析了inbound和outbound属性现在这里就用上了。回想一下ChannelInitializer实现了ChannelInboundHandler因此它所对应的ChannelHandlerContext的inbound属性为true因此这里返回的就是ChannelInitializer实例所对应的ChannelHandlerContext对象如下图所示 当获取inbound的Context后就调用它的invokeChannelRegistered()方法。 private void invokeChannelRegistered() {if (invokeHandler()) {try {((ChannelInboundHandler) handler()).channelRegistered(this);} catch (Throwable t) {notifyHandlerException(t);}} else {fireChannelRegistered();}} 我们已经知道每个ChannelHandler都和一个ChannelHandlerContext关联可以通过ChannelHandlerContext获取对应的ChannelHandler。很明显这里handler()方法返回的对象其实就是一开始实例化的ChannelInitializer对象接着调用了ChannelInitializer的channelRegister()方法。ChannelInitializer的channelRegister()方法的代码如下 public final void channelRegistered(ChannelHandlerContext ctx) throws Exception {if (this.initChannel(ctx)) {ctx.pipeline().fireChannelRegistered();} else {ctx.fireChannelRegistered();}}private boolean initChannel(ChannelHandlerContext ctx) throws Exception {if (this.initMap.putIfAbsent(ctx, Boolean.TRUE) null) {try {this.initChannel(ctx.channel());} catch (Throwable var6) {this.exceptionCaught(ctx, var6);} finally {this.remove(ctx);}return true;} else {return false;} initChannel()方法就是在初始化Bootstrap时调用handler方法传入的匿名内部类所实现的方法。因此在调用这个方法之后自定义的ChannelHandler就插入到Pipeline中此时Pipeline的状态如下图 当添加完自定义的ChannelHandler后在finally代码块会删除自定义的ChannelHandler也就是remove(ctx)最终调用ctx.pipeline().remove(this)因此最后Pipeline的状态如下图 到此自定义ChannelHandler的添加过程也就分析完成了。  5 给ChannelHandler命名 pipeline.addXXX()都有一个重载方法例如addList()有一个重载的版本代码如下 public final ChannelPipeline addLast(String name, ChannelHandler handler) {return addLast(null, name, handler);} 第一个参数指定添加的是Handler的名字更准确的说是ChannelHandlerContext的名字。那么Handler的名字有什么用呢如果不设置name那么Handler默认的名字是怎么样的上面的方法会调用重载的addLast()方法代码如下 public final ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler) {final AbstractChannelHandlerContext newCtx;synchronized (this) {checkMultiplicity(handler);newCtx newContext(group, filterName(name, handler), handler);addLast0(newCtx);// If the registered is false it means that the channel was not registered on an eventloop yet.// In this case we add the context to the pipeline and add a task that will call// ChannelHandler.handlerAdded(...) once the channel is registered.if (!registered) {newCtx.setAddPending();callHandlerCallbackLater(newCtx, true);return this;}EventExecutor executor newCtx.executor();if (!executor.inEventLoop()) {newCtx.setAddPending();executor.execute(new Runnable() {Overridepublic void run() {callHandlerAdded0(newCtx);}});return this;}}callHandlerAdded0(newCtx);return this;} 第一个参数设置为null不用关心。第二个参数就是Handler的名字。有代码可知再添加一个Handler之前需要调用checkMultiplicity()方法来确定新添加的Handler名字是否与已添加的Handler名字重复。
http://www.pierceye.com/news/316898/

相关文章:

  • 梅州市建设培训中心网站济南网上房地产
  • 海口网站提升排名专业做公司logo的网站
  • fm网站开发做网站自动赚钱
  • 网站二级导航制作wordpress找人做
  • 网站建设市场占有率网站开发工程师的职责
  • wordpress 单本小说站做网站前景
  • 只做网站可以在百度里收到吗平面设计是干嘛的
  • 义乌网站建设优化推广网站开发需要哪些人怎么分工
  • 关键词排行优化网站企业seo外包
  • 自适应网站怎么做广西建设局建设行政主管部网站
  • 把网站做成手机版学网页设计的培训
  • 陕西省建设厅执业资格注册中心网站报名系统网站建设重庆最加科技
  • 网站优化软件排名器wordpress E405
  • 北京建设部网站职称集约化网站建设方案
  • 常州溧阳建设工程管理中心网站惠州网站网站建设
  • 你的网站尚未进行备案中国建设银行贵州分行网站
  • 白银做网站的董事wordpress模板搬迁
  • 专业的网站开发建访动地科技登录网站
  • 网站模板素材下载如何做二维码跳转到网站
  • 自助建站免费信息发布网站wordpress 做图库栏目
  • 做网站 我们的工人怎么写哪个网站可以做照片分享
  • 做娱乐网站一个服务器可以建几个网站
  • 外包加工网站企业邮箱免费注册申请
  • jsp网站开发模式徐州手机网站制作
  • 三合一网站开发架构怎么用dw设计网站页面
  • 资源分享网站怎么做临沂住房和城乡建设厅网站
  • 住房和城乡建设部官方网站办事大厅企业展厅设计公司信息
  • 公司网站设计单页网站怎么做排名
  • 公司产品网站应该怎么做页面模板第三方应用
  • 绍兴网站建设网站站长 网站对比