一起学Netty(十五)之 AttributeMap属性

来源:互联网 发布:定向数据流量 编辑:程序博客网 时间:2024/05/21 17:36
本来没打算研究这个东西的,一开始觉得没啥用,甚至觉得这个东西有点鸡肋,不过慢慢接触之后,发现了这个AttributeMap的重要性

初学这个东西,我们还是先理解AttributeMap的用法吧


1)AttributeMap这是是绑定在Channel或者ChannelHandlerContext上的一个附件,相当于依附在这两个对象上的寄生虫一样,相当于附件一样,如图所示:

这个图还算比较形象地描述了AttributeMap的作用,我们知道每一个ChannelHandlerContext都是ChannelHandler和ChannelPipeline之间连接的桥梁,每一个ChannelHandlerContext都有属于自己的上下文,也就说每一个ChannelHandlerContext上如果有AttributeMap都是绑定上下文的,也就说如果A的ChannelHandlerContext中的AttributeMap,B的ChannelHandlerContext是无法读取到的


但是Channel上的AttributeMap就是大家共享的,每一个ChannelHandler都能获取到


我们再看看AttributeMap的结构:


可以看出这个是线程安全的,所以我们可以放心使用,再看看AttributeMap的结构,其实和Map的格式很像,key是AttributeKey,value是Attribute,我们可以根据AttributeKey找到对应的Attribute,并且我们可以指定Attribute的类型T:


我们可以这样使用:

1)首先定义一个AttributeKey:

[java] view plain copy
  1. public static final AttributeKey<NettyChannel> NETTY_CHANNEL_KEY = AttributeKey.valueOf("netty.channel");  

我们AttributeMap中存储的是NettyChannel,这是我们自定义的一个类:

[java] view plain copy
  1. package com.lyncc.netty.attributeMap;  
  2.   
  3. import java.util.Date;  
  4.   
  5. public class NettyChannel {  
  6.       
  7.     private String name;  
  8.       
  9.       
  10.     private Date createDate;  
  11.   
  12.   
  13.     public NettyChannel(String name,Date createDate) {  
  14.         this.name = name;  
  15.         this.createDate = createDate;  
  16.     }  
  17.   
  18.     public String getName() {  
  19.         return name;  
  20.     }  
  21.   
  22.   
  23.     public void setName(String name) {  
  24.         this.name = name;  
  25.     }  
  26.   
  27.   
  28.     public Date getCreateDate() {  
  29.         return createDate;  
  30.     }  
  31.   
  32.     public void setCreateDate(Date createDate) {  
  33.         this.createDate = createDate;  
  34.     }  
  35.       
  36.   
  37. }  

那么我们可以这么使用ChannelHandler中这么使用:

[java] view plain copy
  1. @Override  
  2.     public void channelActive(ChannelHandlerContext ctx) {  
  3.         Attribute<NettyChannel> attr = ctx.attr(NETTY_CHANNEL_KEY);  
  4.         NettyChannel nChannel = attr.get();  
  5.         if (nChannel == null) {  
  6.             NettyChannel newNChannel = new NettyChannel("HelloWorld0Client"new Date());  
  7.             nChannel = attr.setIfAbsent(newNChannel);  
  8.         } else {  
  9.             System.out.println("attributeMap 中是有值的");  
  10.             System.out.println(nChannel.getName() + "=======" + nChannel.getCreateDate());  
  11.         }  
  12.         System.out.println("HelloWorldC0ientHandler Active");  
  13.         ctx.fireChannelActive();  
  14.     }  
channelActive方法中的ChannelHandlerContext方法可以使用attr方法传入AttributeKey获取一个Attribute,如果我们之前没有赋值,那么此时的Attribute值应该是null,我们就创建一个NettyChannel,并使用setIfAbsent这个方法,这个方法是线程安全的,大体的使用方法就是如此


现在我们举两个简单的例子


1)测试ChannelHandler上的AttributeMap是不是上下文绑定的------------首先我们在客户端写两个自定义的ChannelHandler方法,这两个方法的的ChannelActive都会在ChannelHandlerContext上的AttributeMap上写一些属性,然后在对应的ChannelRead方法上读取对应的值,看其是否能读取到:

我们先贴服务端的代码。很简单:

[java] view plain copy
  1. package com.lyncc.netty.attributeMap;  
  2.   
  3. import io.netty.bootstrap.ServerBootstrap;  
  4. import io.netty.channel.ChannelFuture;  
  5. import io.netty.channel.ChannelInitializer;  
  6. import io.netty.channel.ChannelOption;  
  7. import io.netty.channel.EventLoopGroup;  
  8. import io.netty.channel.nio.NioEventLoopGroup;  
  9. import io.netty.channel.socket.SocketChannel;  
  10. import io.netty.channel.socket.nio.NioServerSocketChannel;  
  11. import io.netty.handler.codec.string.StringDecoder;  
  12. import io.netty.handler.codec.string.StringEncoder;  
  13.   
  14. import java.net.InetSocketAddress;  
  15.   
  16. public class HelloWorldServer {  
  17.   
  18.     private int port;  
  19.       
  20.     public HelloWorldServer(int port) {  
  21.         this.port = port;  
  22.     }  
  23.       
  24.     public void start(){  
  25.         EventLoopGroup bossGroup = new NioEventLoopGroup(1);  
  26.         EventLoopGroup workerGroup = new NioEventLoopGroup();  
  27.         try {  
  28.             ServerBootstrap sbs = new ServerBootstrap().group(bossGroup,workerGroup).channel(NioServerSocketChannel.class).localAddress(new InetSocketAddress(port))  
  29.                     .childHandler(new ChannelInitializer<SocketChannel>() {  
  30.                           
  31.                         protected void initChannel(SocketChannel ch) throws Exception {  
  32.                             ch.pipeline().addLast("decoder"new StringDecoder());  
  33.                             ch.pipeline().addLast("encoder"new StringEncoder());  
  34.                             ch.pipeline().addLast(new HelloWorldServerHandler());  
  35.                         };  
  36.                           
  37.                     }).option(ChannelOption.SO_BACKLOG, 128)     
  38.                     .childOption(ChannelOption.SO_KEEPALIVE, true);  
  39.              // 绑定端口,开始接收进来的连接  
  40.              ChannelFuture future = sbs.bind(port).sync();    
  41.                
  42.              System.out.println("Server start listen at " + port );  
  43.              future.channel().closeFuture().sync();  
  44.         } catch (Exception e) {  
  45.             bossGroup.shutdownGracefully();  
  46.             workerGroup.shutdownGracefully();  
  47.         }  
  48.     }  
  49.       
  50.     public static void main(String[] args) throws Exception {  
  51.         int port;  
  52.         if (args.length > 0) {  
  53.             port = Integer.parseInt(args[0]);  
  54.         } else {  
  55.             port = 8080;  
  56.         }  
  57.         new HelloWorldServer(port).start();  
  58.     }  
  59. }  
Channel:

[java] view plain copy
  1. package com.lyncc.netty.attributeMap;  
  2.   
  3. import io.netty.channel.ChannelHandlerContext;  
  4. import io.netty.channel.ChannelInboundHandlerAdapter;  
  5.   
  6. public class HelloWorldServerHandler extends ChannelInboundHandlerAdapter{  
  7.       
  8.       
  9.     @Override  
  10.     public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {  
  11.         System.out.println("server channelRead..");  
  12.         System.out.println(ctx.channel().remoteAddress()+"->Server :"+ msg.toString());  
  13.         ctx.write("server write"+msg);  
  14.         ctx.flush();  
  15.     }  
  16.       
  17.     @Override  
  18.     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {  
  19.         cause.printStackTrace();  
  20.         ctx.close();  
  21.     }  
  22.   
  23. }  
客户端的bootstrap代码:

[java] view plain copy
  1. package com.lyncc.netty.attributeMap;  
  2.   
  3. import io.netty.bootstrap.Bootstrap;  
  4. import io.netty.channel.ChannelFuture;  
  5. import io.netty.channel.ChannelInitializer;  
  6. import io.netty.channel.ChannelOption;  
  7. import io.netty.channel.ChannelPipeline;  
  8. import io.netty.channel.EventLoopGroup;  
  9. import io.netty.channel.nio.NioEventLoopGroup;  
  10. import io.netty.channel.socket.SocketChannel;  
  11. import io.netty.channel.socket.nio.NioSocketChannel;  
  12. import io.netty.handler.codec.string.StringDecoder;  
  13. import io.netty.handler.codec.string.StringEncoder;  
  14.   
  15. public class HelloWorldClient {  
  16.       
  17.     static final String HOST = System.getProperty("host""127.0.0.1");  
  18.     static final int PORT = Integer.parseInt(System.getProperty("port""8080"));  
  19.     static final int SIZE = Integer.parseInt(System.getProperty("size""256"));  
  20.   
  21.     public static void main(String[] args) throws Exception {  
  22.         initChannel();  
  23.     }  
  24.       
  25.     public static void initChannel() throws InterruptedException{  
  26.         // Configure the client.  
  27.         EventLoopGroup group = new NioEventLoopGroup();  
  28.         try {  
  29.             Bootstrap b = new Bootstrap();  
  30.             b.group(group)  
  31.              .channel(NioSocketChannel.class)  
  32.              .option(ChannelOption.TCP_NODELAY, true)  
  33.              .handler(new ChannelInitializer<SocketChannel>() {  
  34.                  @Override  
  35.                  public void initChannel(SocketChannel ch) throws Exception {  
  36.                      ChannelPipeline p = ch.pipeline();  
  37.                      p.addLast("decoder"new StringDecoder());  
  38.                      p.addLast("encoder"new StringEncoder());  
  39.                      p.addLast(new HelloWorldClientHandler());  
  40.                      p.addLast(new HelloWorld2ClientHandler());  
  41.                  }  
  42.              });  
  43.   
  44.             ChannelFuture future = b.connect(HOST, PORT).sync();  
  45.             future.channel().writeAndFlush("hello Netty,Test attributeMap");  
  46.             future.channel().closeFuture().sync();  
  47.         } finally {  
  48.             group.shutdownGracefully();  
  49.         }  
  50.       
  51.     }  
  52.   
  53. }  

一个常量类:

[java] view plain copy
  1. package com.lyncc.netty.attributeMap;  
  2.   
  3. import io.netty.util.AttributeKey;  
  4.   
  5. public class AttributeMapConstant {  
  6.       
  7.     public static final AttributeKey<NettyChannel> NETTY_CHANNEL_KEY = AttributeKey.valueOf("netty.channel");  
  8.   
  9. }  
两个客户端的handler:

[java] view plain copy
  1. package com.lyncc.netty.attributeMap;  
  2.   
  3. import static com.lyncc.netty.attributeMap.AttributeMapConstant.NETTY_CHANNEL_KEY;  
  4. import io.netty.channel.ChannelHandlerContext;  
  5. import io.netty.channel.ChannelInboundHandlerAdapter;  
  6. import io.netty.util.Attribute;  
  7.   
  8. import java.util.Date;  
  9. public class HelloWorldClientHandler extends ChannelInboundHandlerAdapter {  
  10.   
  11.   
  12.     @Override  
  13.     public void channelActive(ChannelHandlerContext ctx) {  
  14.         Attribute<NettyChannel> attr = ctx.attr(NETTY_CHANNEL_KEY);  
  15.         NettyChannel nChannel = attr.get();  
  16.         if (nChannel == null) {  
  17.             NettyChannel newNChannel = new NettyChannel("HelloWorld0Client"new Date());  
  18.             nChannel = attr.setIfAbsent(newNChannel);  
  19.         } else {  
  20.             System.out.println("channelActive attributeMap 中是有值的");  
  21.             System.out.println(nChannel.getName() + "=======" + nChannel.getCreateDate());  
  22.         }  
  23.         System.out.println("HelloWorldC0ientHandler Active");  
  24.         ctx.fireChannelActive();  
  25.     }  
  26.   
  27.     @Override  
  28.     public void channelRead(ChannelHandlerContext ctx, Object msg) {  
  29.         Attribute<NettyChannel> attr = ctx.attr(NETTY_CHANNEL_KEY);  
  30.         NettyChannel nChannel = attr.get();  
  31.         if (nChannel == null) {  
  32.             NettyChannel newNChannel = new NettyChannel("HelloWorld0Client"new Date());  
  33.             nChannel = attr.setIfAbsent(newNChannel);  
  34.         } else {  
  35.             System.out.println("channelRead attributeMap 中是有值的");  
  36.             System.out.println(nChannel.getName() + "=======" + nChannel.getCreateDate());  
  37.         }  
  38.         System.out.println("HelloWorldClientHandler read Message:" + msg);  
  39.           
  40.         ctx.fireChannelRead(msg);  
  41.     }  
  42.   
  43.     @Override  
  44.     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {  
  45.         cause.printStackTrace();  
  46.         ctx.close();  
  47.     }  
  48.   
  49. }  
handler2:

[java] view plain copy
  1. package com.lyncc.netty.attributeMap;  
  2.   
  3. import static com.lyncc.netty.attributeMap.AttributeMapConstant.NETTY_CHANNEL_KEY;  
  4. import io.netty.channel.ChannelHandlerContext;  
  5. import io.netty.channel.ChannelInboundHandlerAdapter;  
  6. import io.netty.util.Attribute;  
  7.   
  8. import java.util.Date;  
  9.   
  10. public class HelloWorld2ClientHandler extends ChannelInboundHandlerAdapter {  
  11.   
  12.   
  13.     @Override  
  14.     public void channelActive(ChannelHandlerContext ctx) {  
  15.         Attribute<NettyChannel> attr = ctx.attr(NETTY_CHANNEL_KEY);  
  16.         NettyChannel nChannel = attr.get();  
  17.         if (nChannel == null) {  
  18.             NettyChannel newNChannel = new NettyChannel("HelloWorld2Client"new Date());  
  19.             nChannel = attr.setIfAbsent(newNChannel);  
  20.         } else {  
  21.             System.out.println("channelActive attributeMap 中是有值的");  
  22.             System.out.println(nChannel.getName() + "=======" + nChannel.getCreateDate());  
  23.         }  
  24.         System.out.println("HelloWorldC2ientHandler Active");  
  25.         ctx.fireChannelActive();  
  26.     }  
  27.   
  28.     @Override  
  29.     public void channelRead(ChannelHandlerContext ctx, Object msg) {  
  30.         Attribute<NettyChannel> attr = ctx.attr(NETTY_CHANNEL_KEY);  
  31.         NettyChannel nChannel = attr.get();  
  32.         if (nChannel == null) {  
  33.             NettyChannel newNChannel = new NettyChannel("HelloWorld0Client"new Date());  
  34.             nChannel = attr.setIfAbsent(newNChannel);  
  35.         } else {  
  36.             System.out.println("channelRead attributeMap 中是有值的");  
  37.             System.out.println(nChannel.getName() + "=======" + nChannel.getCreateDate());  
  38.         }  
  39.         System.out.println("HelloWorldClientHandler read Message:" + msg);  
  40.     }  
  41.   
  42.     @Override  
  43.     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {  
  44.         cause.printStackTrace();  
  45.         ctx.close();  
  46.     }  
  47.   
  48. }  


我们先运行服务器端:


客户端控制台:


这说明每个ChannelHandlerContext上的AttributeMap是相互不影响的



2)测试Channel上的AttributeMap:


我们只需要把2个channel获取Attribute的方法改下就可以了:

[java] view plain copy
  1. Attribute<NettyChannel> attr = ctx.channel().attr(NETTY_CHANNEL_KEY);  
两个channel共有四处需要修改,改成获取channel后获取attribute:


再次运行:



好了,首先在ChannelHandler1中赋值了,然后在channelHandlerHandler2中的channelActivew打印了attributeMap中有值了,然后都能够在channelRead中读取到最新值


关于AttributeMap的一些内幕详解,参考一下:

http://blog.csdn.net/zxhoo/article/details/17719333

原创粉丝点击