博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
netty 学习 (2)Handler的执行顺序
阅读量:6226 次
发布时间:2019-06-21

本文共 7892 字,大约阅读时间需要 26 分钟。

  hot3.png

Handler在netty中,无疑占据着非常重要的地位。Handler与Servlet中的filter很像,通过Handler可以完成通讯报文的解码编码、拦截指定的报文、统一对日志错误进行处理、统一对请求进行计数、控制Handler执行与否。一句话,没有它做不到的只有你想不到的。

Netty中的所有handler都实现自ChannelHandler接口。按照输出输出来分,分为ChannelInboundHandler、ChannelOutboundHandler两大类。ChannelInboundHandler对从客户端发往服务器的报文进行处理,一般用来执行解码、读取客户端数据、进行业务处理等;ChannelOutboundHandler对从服务器发往客户端的报文进行处理,一般用来进行编码、发送报文到客户端。

Netty中,可以注册多个handler。ChannelInboundHandler按照注册的先后顺序执行;ChannelOutboundHandler按照注册的先后顺序逆序执行,如下图所示,按照注册的先后顺序对Handler进行排序,request进入Netty后的执行顺序为:

下面例子涉及的类包括:

一、HelloServer:

package com.yao.nettyhandler;import io.netty.bootstrap.ServerBootstrap;import io.netty.channel.ChannelFuture;import io.netty.channel.ChannelInitializer;import io.netty.channel.ChannelOption;import io.netty.channel.EventLoopGroup;import io.netty.channel.nio.NioEventLoopGroup;import io.netty.channel.socket.SocketChannel;import io.netty.channel.socket.nio.NioServerSocketChannel;public class HelloServer {	public void start(int port) throws Exception {		EventLoopGroup bossGroup = new NioEventLoopGroup(); 		EventLoopGroup workerGroup = new NioEventLoopGroup();		try {			ServerBootstrap b = new ServerBootstrap(); 			b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class) 					.childHandler(new ChannelInitializer
() { @Override public void initChannel(SocketChannel ch) throws Exception { // 注册两个OutboundHandler,执行顺序为注册顺序的逆序,所以应该是OutboundHandler2 OutboundHandler1 ch.pipeline().addLast(new OutboundHandler1()); ch.pipeline().addLast(new OutboundHandler2()); // 注册两个InboundHandler,执行顺序为注册顺序,所以应该是InboundHandler1 InboundHandler2 ch.pipeline().addLast(new InboundHandler1()); ch.pipeline().addLast(new InboundHandler2()); } }).option(ChannelOption.SO_BACKLOG, 128) .childOption(ChannelOption.SO_KEEPALIVE, true); ChannelFuture f = b.bind(port).sync(); f.channel().closeFuture().sync(); } finally { workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } } public static void main(String[] args) throws Exception { HelloServer server = new HelloServer(); server.start(8000); }}
二、InboundHandler1:

package com.yao.nettyhandler;import io.netty.channel.ChannelHandlerContext;import io.netty.channel.ChannelInboundHandlerAdapter;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;public class InboundHandler1 extends ChannelInboundHandlerAdapter {	private static Log logger = LogFactory.getLog(InboundHandler1.class);	@Override	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {		logger.info("InboundHandler1.channelRead: ctx :" + ctx);				// 通知执行下一个InboundHandler		//ctx.fireChannelRead(msg);	}	@Override	public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {		logger.info("InboundHandler1.channelReadComplete");		ctx.flush();	}}
三、InboundHandler2:

package com.yao.nettyhandler;import io.netty.buffer.ByteBuf;import io.netty.channel.ChannelHandlerContext;import io.netty.channel.ChannelInboundHandlerAdapter;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;public class InboundHandler2 extends ChannelInboundHandlerAdapter {	private static Log	logger	= LogFactory.getLog(InboundHandler2.class);	@Override	// 读取Client发送的信息,并打印出来	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {		logger.info("InboundHandler2.channelRead: ctx :" + ctx);		ByteBuf result = (ByteBuf) msg;		byte[] result1 = new byte[result.readableBytes()];		result.readBytes(result1);		String resultStr = new String(result1);		System.out.println("Client said:" + resultStr);		result.release();		ctx.write(msg);	}	@Override	public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {		logger.info("InboundHandler2.channelReadComplete");		ctx.flush();	}}
四、OutboundHandler1 :

package com.yao.nettyhandler;import io.netty.buffer.ByteBuf;import io.netty.channel.ChannelHandlerContext;import io.netty.channel.ChannelOutboundHandlerAdapter;import io.netty.channel.ChannelPromise;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;public class OutboundHandler1 extends ChannelOutboundHandlerAdapter {	private static Log	logger	= LogFactory.getLog(OutboundHandler1.class);	@Override	// 向client发送消息	public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {		logger.info("OutboundHandler1.write");		String response = "I am ok!";		ByteBuf encoded = ctx.alloc().buffer(4 * response.length());		encoded.writeBytes(response.getBytes());		ctx.write(encoded);		ctx.flush();	}		}

五、OutboundHandler2:

package com.yao.nettyhandler;import io.netty.channel.ChannelHandlerContext;import io.netty.channel.ChannelOutboundHandlerAdapter;import io.netty.channel.ChannelPromise;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;public class OutboundHandler2 extends ChannelOutboundHandlerAdapter {	private static Log	logger	= LogFactory.getLog(OutboundHandler2.class);		@Override	public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {		logger.info("OutboundHandler2.write");		// 执行下一个OutboundHandler		super.write(ctx, msg, promise);	}}

下面是客户端

六、HelloClient:

package com.yao.nettyhandler;import io.netty.bootstrap.Bootstrap;import io.netty.channel.ChannelFuture;import io.netty.channel.ChannelInitializer;import io.netty.channel.ChannelOption;import io.netty.channel.EventLoopGroup;import io.netty.channel.nio.NioEventLoopGroup;import io.netty.channel.socket.SocketChannel;import io.netty.channel.socket.nio.NioSocketChannel;public class HelloClient {	public void connect(String host, int port) throws Exception {		EventLoopGroup workerGroup = new NioEventLoopGroup();		try {			Bootstrap b = new Bootstrap();			b.group(workerGroup);			b.channel(NioSocketChannel.class);			b.option(ChannelOption.SO_KEEPALIVE, true);			b.handler(new ChannelInitializer
() { @Override public void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new HelloClientIntHandler()); } }); // Start the client. ChannelFuture f = b.connect(host, port).sync(); f.channel().closeFuture().sync(); } finally { workerGroup.shutdownGracefully(); } } public static void main(String[] args) throws Exception { HelloClient client = new HelloClient(); client.connect("127.0.0.1", 8000); }}

七、HelloClientIntHandler:

package com.yao.nettyhandler;import io.netty.buffer.ByteBuf;import io.netty.channel.ChannelHandlerContext;import io.netty.channel.ChannelInboundHandlerAdapter;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;public class HelloClientIntHandler extends ChannelInboundHandlerAdapter {	private static Log	logger	= LogFactory.getLog(HelloClientIntHandler.class);	@Override	// 读取服务端的信息	public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {		logger.info("HelloClientIntHandler.channelRead");		ByteBuf result = (ByteBuf) msg;		byte[] result1 = new byte[result.readableBytes()];		result.readBytes(result1);		result.release();		ctx.close();		System.out.println("Server said:" + new String(result1));	}	@Override	// 当连接建立的时候向服务端发送消息 ,channelActive 事件当连接建立的时候会触发	public void channelActive(ChannelHandlerContext ctx) throws Exception {		logger.info("HelloClientIntHandler.channelActive");		String msg = "Are you ok?";		ByteBuf encoded = ctx.alloc().buffer(4 * msg.length());		encoded.writeBytes(msg.getBytes());		ctx.write(encoded);		ctx.flush();	}}
八、总结:

在使用Handler的过程中,需要注意:

1、ChannelInboundHandler之间的传递,通过调用 ctx.fireChannelRead(msg) 实现;调用ctx.write(msg) 将传递到ChannelOutboundHandler。
2、ctx.write()方法执行后,需要调用flush()方法才能令它立即执行。
3、ChannelOutboundHandler 在注册的时候需要放在最后一个ChannelInboundHandler之前,否则将无法传递到ChannelOutboundHandler。
4、Handler的消费处理放在最后一个处理。

转载于:https://my.oschina.net/jamaly/blog/272385

你可能感兴趣的文章
request获取url链接和参数
查看>>
腾讯视频播放器V 1.0 去广告补丁
查看>>
实现本地上传的Kindetitor的Servlet版本
查看>>
Android学习笔记—第九章 Activity的加载模式
查看>>
C#设计模式系列:代理模式(Proxy)
查看>>
javaEE项目建立多个数据源并配置事务
查看>>
python-字符串格式化
查看>>
DNS配置笔记
查看>>
Chrome自定义最小字号
查看>>
Android多人视频聊天应用的开发(一)快速集成
查看>>
谷歌web站点安全扫描软件skipfish安装、配置、使用
查看>>
Centos 中如何快速定制二进制的内核 RPM 包
查看>>
zabbix 自动发现tomcat的war包并实现监控
查看>>
网络安全简介
查看>>
Nginx基本概念和安装
查看>>
我的友情链接
查看>>
10年以后第一次做作业的感受
查看>>
SpannableString与SpannableStringBuilder使用
查看>>
fastreport打印,设置
查看>>
如何批量导出已经开通Lync权限的用户
查看>>