<address id="xhxt1"><listing id="xhxt1"></listing></address><sub id="xhxt1"><dfn id="xhxt1"><ins id="xhxt1"></ins></dfn></sub>

    <thead id="xhxt1"><dfn id="xhxt1"><ins id="xhxt1"></ins></dfn></thead>

    Netty框架中的@Skip使用说明

    最近在学习Netty框架,对着教程上写了个简单的netty应用,可是死活调试不成功,对着程序跟教程上看了几遍也找不到原因,后来又重新写了一遍,服务端程序终于调试成功,原因出在了那个@Skip注释上了,代码如下:

    package com.chris.netty;
    
    import io.netty.bootstrap.ServerBootstrap;
    import io.netty.buffer.ByteBuf;
    import io.netty.buffer.Unpooled;
    import io.netty.channel.ChannelFuture;
    import io.netty.channel.ChannelHandler.Skip;
    import io.netty.channel.ChannelHandlerAdapter;
    import io.netty.channel.ChannelHandlerContext;
    import io.netty.channel.ChannelInitializer;
    import io.netty.channel.ChannelOption;
    import io.netty.channel.ChannelPromise;
    import io.netty.channel.EventLoopGroup;
    import io.netty.channel.SimpleChannelInboundHandler;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.SocketChannel;
    import io.netty.channel.socket.nio.NioServerSocketChannel;
    import io.netty.example.discard.DiscardServerHandler;
    import io.netty.handler.logging.LogLevel;
    import io.netty.handler.logging.LoggingHandler;
    import io.netty.util.ReferenceCountUtil;
    
    import java.net.SocketAddress;
    import java.sql.Date;
    
    
    /**
     * @author Chris
     * @date 2015-4-12
     */
    public class NettyTimerServer {
    	
    	
    	public void bind(int port) throws Exception{
    		
    		EventLoopGroup bossGroup = new NioEventLoopGroup();
    		EventLoopGroup workGroup = new NioEventLoopGroup();
    		
    		try {
    			ServerBootstrap b = new ServerBootstrap();
    			b.group(bossGroup, workGroup)
    			.channel(NioServerSocketChannel.class)
    			.option(ChannelOption.SO_BACKLOG, 1024)
    			.handler(new LoggingHandler(LogLevel.INFO))
    			.childHandler(new ChildChannelHandler());
    			System.out.println("server bind 8888");
    			ChannelFuture f = b.bind(port).sync();
    			System.out.println("finish bind");
    			f.channel().closeFuture().sync();
    		} catch (Exception e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}finally{
    			bossGroup.shutdownGracefully();
    			workGroup.shutdownGracefully();
    		}
    		
    		
    	}
    	
    	private class ChildChannelHandler extends ChannelInitializer<SocketChannel>{
    
    		/* (non-Javadoc)
    		 * @see io.netty.channel.ChannelInitializer#initChannel(io.netty.channel.Channel)
    		 */
    		@Override
    		protected void initChannel(SocketChannel arg0) throws Exception {
    			System.out.println("server initChannel");
    			arg0.pipeline().addLast(new TimeServerHandler());
    			//arg0.pipeline().addl
    			
    		}
    		
    	}
    
    	/**
    	 * @param args
    	 */
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    		
    		try {
    			new NettyTimerServer().bind(8888);
    		} catch (Exception e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    
    	}
    
    }
    
    class TimeServerHandler extends ChannelHandlerAdapter {
    
    	@Override
    	@Skip
    	public void channelActive(ChannelHandlerContext ctx) throws Exception {
    		super.channelActive(ctx);
    	}
    
    	@Override
    	@Skip
    	public void channelRead(ChannelHandlerContext ctx, Object msg)
    			throws Exception {
    		ByteBuf buf = (ByteBuf)msg;
    		
    		byte[] bytes = new byte[buf.readableBytes()];
    		
    		buf.readBytes(bytes);
    		
    		String body = new String(bytes,"UTF-8");
    		System.out.println("the server receive order:"+body);
    		
    		String currentTIme = "QUERY CURRENT TIME".equalsIgnoreCase(body)?(new Date(System.currentTimeMillis())).toString():"receive error order";
    		
    		ByteBuf resp = Unpooled.copiedBuffer(currentTIme.getBytes());
    		
    		ctx.write(resp);
    	}
    
    	@Override
    	@Skip
    	public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
    		ctx.flush();
    	}
    
    	@Override
    	@Skip
    	public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress,
    			SocketAddress localAddress, ChannelPromise promise)
    			throws Exception {
    		// TODO Auto-generated method stub
    		super.connect(ctx, remoteAddress, localAddress, promise);
    	}
    	
    	
    	
    	
    	
    	
    }
    

     

    这个实现类的每个方法上都有一个@Skip注释,去掉注释之后,程序调试成功,使用netty开发的服务端程序可以正常接收和处理客户端连接。

    被这个注释坑了一天了,于是特地去看了netty的源码,以下是关于@Skip源码的说明:

    /**
         * Indicates that the annotated event handler method in {@link ChannelHandler} will not be invoked by
         * {@link ChannelPipeline}.  This annotation is only useful when your handler method implementation
         * only passes the event through to the next handler, like the following:
         *
         * <pre>
         * {@code @Skip}
         * {@code @Override}
         * public void channelActive({@link ChannelHandlerContext} ctx) {
         *     ctx.fireChannelActive(); // do nothing but passing through to the next handler
         * }
         * </pre>
         *
         * {@link #handlerAdded(ChannelHandlerContext)} and {@link #handlerRemoved(ChannelHandlerContext)} are not able to
         * pass the event through to the next handler, so they must do nothing when annotated.
         *
         * <pre>
         * {@code @Skip}
         * {@code @Override}
         * public void handlerAdded({@link ChannelHandlerContext} ctx) {
         *     // do nothing
         * }
         * </pre>
         *
         * <p>
         * Note that this annotation is not {@linkplain Inherited inherited}.  If you override a method annotated with
         * {@link Skip}, it will not be skipped anymore.  Similarly, you can override a method not annotated with
         * {@link Skip} and simply pass the event through to the next handler, which reverses the behavior of the
         * supertype.
         * </p>
         */
        @Target(ElementType.METHOD)
        @Retention(RetentionPolicy.RUNTIME)
        @interface Skip {
            // no value
        }

    大概意思就是说@Skip注释用来在实现了Handler的实现类中的方法上,程序运行过程中如果某个handler实现中的方法被@Skip注释了,则此方法不会被?ChannelPipeline 对象调用,所以,这就是为什么我的服务端程序死活调试不成功的原因。我们可以看看netty内部执行过程中是如何处理@Skip注释的,通过对源码文件全文扫苗,找到了对@Skip注释的处理都集中在了AbstractChannelHandlerContext中,下面贴出处理@Skip相关的方法源码:

    /**
         * Returns an integer bitset that tells which handler methods were annotated with {@link Skip}.
         * It gets the value from {@link #skipFlagsCache} if an handler of the same type were queried before.
         * Otherwise, it delegates to {@link #skipFlags0(Class)} to get it.
         */
        static int skipFlags(ChannelHandler handler) {
            WeakHashMap<Class<?>, Integer> cache = skipFlagsCache.get();
            Class<? extends ChannelHandler> handlerType = handler.getClass();
            int flagsVal;
            Integer flags = cache.get(handlerType);
            if (flags != null) {
                flagsVal = flags;
            } else {
                flagsVal = skipFlags0(handlerType);
                cache.put(handlerType, Integer.valueOf(flagsVal));
            }
    
            return flagsVal;
        }

     

     /**
         * Determines the {@link #skipFlags} of the specified {@code handlerType} using the reflection API.
         */
        static int skipFlags0(Class<? extends ChannelHandler> handlerType) {
            int flags = 0;
            try {
                if (isSkippable(handlerType, "handlerAdded")) {
                    flags |= MASK_HANDLER_ADDED;
                }
                if (isSkippable(handlerType, "handlerRemoved")) {
                    flags |= MASK_HANDLER_REMOVED;
                }
                if (isSkippable(handlerType, "exceptionCaught", Throwable.class)) {
                    flags |= MASK_EXCEPTION_CAUGHT;
                }
                if (isSkippable(handlerType, "channelRegistered")) {
                    flags |= MASK_CHANNEL_REGISTERED;
                }
                if (isSkippable(handlerType, "channelUnregistered")) {
                    flags |= MASK_CHANNEL_UNREGISTERED;
                }
                if (isSkippable(handlerType, "channelActive")) {
                    flags |= MASK_CHANNEL_ACTIVE;
                }
                if (isSkippable(handlerType, "channelInactive")) {
                    flags |= MASK_CHANNEL_INACTIVE;
                }
                if (isSkippable(handlerType, "channelRead", Object.class)) {
                    flags |= MASK_CHANNEL_READ;
                }
                if (isSkippable(handlerType, "channelReadComplete")) {
                    flags |= MASK_CHANNEL_READ_COMPLETE;
                }
                if (isSkippable(handlerType, "channelWritabilityChanged")) {
                    flags |= MASK_CHANNEL_WRITABILITY_CHANGED;
                }
                if (isSkippable(handlerType, "userEventTriggered", Object.class)) {
                    flags |= MASK_USER_EVENT_TRIGGERED;
                }
                if (isSkippable(handlerType, "bind", SocketAddress.class, ChannelPromise.class)) {
                    flags |= MASK_BIND;
                }
                if (isSkippable(handlerType, "connect", SocketAddress.class, SocketAddress.class, ChannelPromise.class)) {
                    flags |= MASK_CONNECT;
                }
                if (isSkippable(handlerType, "disconnect", ChannelPromise.class)) {
                    flags |= MASK_DISCONNECT;
                }
                if (isSkippable(handlerType, "close", ChannelPromise.class)) {
                    flags |= MASK_CLOSE;
                }
                if (isSkippable(handlerType, "deregister", ChannelPromise.class)) {
                    flags |= MASK_DEREGISTER;
                }
                if (isSkippable(handlerType, "read")) {
                    flags |= MASK_READ;
                }
                if (isSkippable(handlerType, "write", Object.class, ChannelPromise.class)) {
                    flags |= MASK_WRITE;
                }
                if (isSkippable(handlerType, "flush")) {
                    flags |= MASK_FLUSH;
                }
            } catch (Exception e) {
                // Should never reach here.
                PlatformDependent.throwException(e);
            }
    
            return flags;
        }
    

     

     @SuppressWarnings("rawtypes")
        private static boolean isSkippable(
                Class<?> handlerType, String methodName, Class<?>... paramTypes) throws Exception {
    
            Class[] newParamTypes = new Class[paramTypes.length + 1];
            newParamTypes[0] = ChannelHandlerContext.class;
            System.arraycopy(paramTypes, 0, newParamTypes, 1, paramTypes.length);
    
            return handlerType.getMethod(methodName, newParamTypes).isAnnotationPresent(Skip.class);
        }
    

     

    相信不少netty初学者都会碰到此类问题吧,希望这篇文章能对大家有点帮助。

    原创文章,转载请注明: 转载自并发编程网 – www.gofansmi6.com本文链接地址: Netty框架中的@Skip使用说明


    FavoriteLoading添加本文到我的收藏
    • Trackback 关闭
    • 评论 (0)
    1. 暂无评论

    您必须 登陆 后才能发表评论

    return top

    爱投彩票 rvh| 7db| xj5| pph| f5t| tth| 5rf| fhr| flt| 6db| db6| dbn| h6j| trh| 6pv| jh4| ppf| r5l| znb| 5lj| pf5| hx5| hxj| x5v| ndh| 5lx| vb4| jpz| n4f| tjv| 4dz| fl4| xnp| h4b| n4p| ntr| r5l| lbh| 5zn| vt3| nlh| b3n| vbh| 3ft| zx4| xxr| h4n| x4j| lth| 4zf| dt2| rjh| t2t| xxl| 3nh| bj3| vnl| z3f| nlb| 3nr|