前言
-
这个系列主要讲优秀的开源框架对于责任链这个设计模式的运用,对于好的设计,我们关键是学习他的思想并运用在我们的编码中。
-
这个系列的所有代码都是我根据源码提炼之后的代码,不依赖原项目或框架,可以直接跑。
-
我不会讲每个具体是如何实现的,如果你觉得光看代码比较吃力,那么可以将代码复制下来,自己多运行几遍,我相信你一定能掌握。
-
欢迎访问我的个人网站,里面有超多开源组件和项目,另外还有付费项目和博客,地址:https://openbytecode.com/
-
前五个小节主要介绍了 Tomcat 的 Filter 设计、SpringMVC 的 Interceptor 设计、 Spring 中 AOP 的设计、Mybatis 的 Plugin 设计、Dubbo 的 Filter 设计,本小节主要讲 Netty 的 Pepeline 设计。
-
本系列 Github 地址:https://github.com/lijunping365/Open-Design
Netty 之 Pepeline
public interface ChannelPipeline {
/**
* Inserts a {@link io.netty.channel.ChannelHandler} at the first position of this pipeline.
*
* @param name the name of the handler to insert first
* @param handler the handler to insert first
*
* @throws IllegalArgumentException
* if there's an entry with the same name already in the pipeline
* @throws NullPointerException
* if the specified handler is {@code null}
*/
ChannelPipeline addFirst(String name, ChannelHandler handler);
/**
* Appends a {@link ChannelHandler} at the last position of this pipeline.
*
* @param name the name of the handler to append
* @param handler the handler to append
*
* @throws IllegalArgumentException
* if there's an entry with the same name already in the pipeline
* @throws NullPointerException
* if the specified handler is {@code null}
*/
ChannelPipeline addLast(String name, ChannelHandler handler);
/**
* A {@link io.netty.channel.Channel} received a message.
*
* This will result in having the {@link ChannelInboundHandler#channelRead(io.netty.channel.ChannelHandlerContext, Object)}
* method called of the next {@link ChannelInboundHandler} contained in the {@link io.netty.channel.ChannelPipeline} of the
* {@link io.netty.channel.Channel}.
*/
void fireChannelRead(Object msg);
/**
* Triggers an {@link ChannelInboundHandler#channelReadComplete(io.netty.channel.ChannelHandlerContext)}
* event to the next {@link ChannelInboundHandler} in the {@link io.netty.channel.ChannelPipeline}.
*/
void fireChannelReadComplete();
/**
* A {@link io.netty.channel.Channel} received an {@link Throwable} in one of its inbound operations.
*
* This will result in having the {@link ChannelInboundHandler#exceptionCaught(io.netty.channel.ChannelHandlerContext, Throwable)}
* method called of the next {@link ChannelInboundHandler} contained in the {@link io.netty.channel.ChannelPipeline} of the
* {@link io.netty.channel.Channel}.
*/
void fireExceptionCaught(Throwable cause);
}
public class DefaultChannelPipeline implements ChannelPipeline{
private final DefaultChannelHandlerContext head;
private final DefaultChannelHandlerContext tail;
public DefaultChannelPipeline() {
head = new DefaultChannelHandlerContext("HEAD");
tail = new DefaultChannelHandlerContext("TAIL");
head.next = tail;
tail.prev = head;
}
@Override
public ChannelPipeline addFirst(String name, ChannelHandler handler) {
final DefaultChannelHandlerContext newNode;
synchronized (this) {
newNode = newHandlerNode(name, handler);
addFirst0(newNode);
}
return this;
}
@Override
public ChannelPipeline addLast(String name, ChannelHandler handler) {
final DefaultChannelHandlerContext newNode;
synchronized (this) {
newNode = newHandlerNode(name, handler);
addLast0(newNode);
}
return this;
}
@Override
public void fireChannelRead(Object msg) {
DefaultChannelHandlerContext.invokeChannelRead(head, msg);
}
@Override
public void fireChannelReadComplete() {
DefaultChannelHandlerContext.invokeChannelReadComplete(head);
}
@Override
public void fireExceptionCaught(Throwable cause) {
DefaultChannelHandlerContext.invokeExceptionCaught(head, cause);
}
private DefaultChannelHandlerContext newHandlerNode(String name, ChannelHandler handler) {
return new DefaultChannelHandlerContext(name, handler);
}
private void addFirst0(DefaultChannelHandlerContext newNode) {
DefaultChannelHandlerContext next = head.next;
newNode.prev = head;
newNode.next = next;
head.next = newNode;
next.prev = newNode;
}
private void addLast0(DefaultChannelHandlerContext newNode) {
DefaultChannelHandlerContext prev = tail.prev;
newNode.prev = prev;
newNode.next = tail;
prev.next = newNode;
tail.prev = newNode;
}
}
public interface ChannelHandlerContext {
ChannelHandler handler();
/**
* A {@link io.netty.channel.Channel} received a message.
*
* This will result in having the {@link ChannelInboundHandler#channelRead(io.netty.channel.ChannelHandlerContext, Object)}
* method called of the next {@link ChannelInboundHandler} contained in the {@link io.netty.channel.ChannelPipeline} of the
* {@link io.netty.channel.Channel}.
*/
void fireChannelRead(Object msg);
/**
* Triggers an {@link ChannelInboundHandler#channelReadComplete(io.netty.channel.ChannelHandlerContext)}
* event to the next {@link ChannelInboundHandler} in the {@link io.netty.channel.ChannelPipeline}.
*/
void fireChannelReadComplete();
/**
* A {@link io.netty.channel.Channel} received an {@link Throwable} in one of its inbound operations.
*
* This will result in having the {@link ChannelInboundHandler#exceptionCaught(io.netty.channel.ChannelHandlerContext, Throwable)}
* method called of the next {@link ChannelInboundHandler} contained in the {@link io.netty.channel.ChannelPipeline} of the
* {@link io.netty.channel.Channel}.
*/
void fireExceptionCaught(Throwable cause);
}
public class DefaultChannelHandlerContext implements ChannelHandlerContext{
volatile DefaultChannelHandlerContext next;
volatile DefaultChannelHandlerContext prev;
private ChannelHandler handler;
private final String name;
public DefaultChannelHandlerContext(String name) {
this.name = name;
}
public DefaultChannelHandlerContext(String name, ChannelHandler handler) {
this.name = name;
this.handler = handler;
}
@Override
public ChannelHandler handler() {
return this.handler;
}
@Override
public void fireChannelRead(Object msg) {
invokeChannelRead(next, msg);
}
@Override
public void fireChannelReadComplete() {
invokeChannelReadComplete(next);
}
@Override
public void fireExceptionCaught(Throwable cause) {
invokeExceptionCaught(next, cause);
}
public static void invokeChannelRead(final DefaultChannelHandlerContext next, Object msg) {
if (null != next){
next.invokeChannelRead(msg);
}
}
public static void invokeChannelReadComplete(DefaultChannelHandlerContext next) {
if (null != next){
next.invokeChannelReadComplete();
}
}
public static void invokeExceptionCaught(DefaultChannelHandlerContext next, Throwable cause) {
if (null != next){
next.invokeExceptionCaught(cause);
}
}
private void invokeChannelRead(Object msg) {
if (null != handler){
try {
handler.channelRead(this, msg);
} catch (Exception e){
invokeExceptionCaught(e);
}
} else {
fireChannelRead(msg);
}
}
private void invokeChannelReadComplete() {
if (null != handler){
try {
handler.channelReadComplete(this);
} catch (Exception e){
invokeExceptionCaught(e);
}
} else {
fireChannelReadComplete();
}
}
private void invokeExceptionCaught(final Throwable cause) {
if (null != handler){
try {
handler.exceptionCaught(this, cause);
} catch (Exception e){
System.out.println(e.getMessage());
}
} else {
fireExceptionCaught(cause);
}
}
}
public interface ChannelHandler {
/**
* Invoked when the current {@link io.netty.channel.Channel} has read a message from the peer.
*/
void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception;
/**
* Invoked when the last message read by the current read operation has been consumed by
* {@link #channelRead(io.netty.channel.ChannelHandlerContext, Object)}. If {@link ChannelOption#AUTO_READ} is off, no further
* attempt to read an inbound data from the current {@link Channel} will be made until
* {@link io.netty.channel.ChannelHandlerContext#read()} is called.
*/
void channelReadComplete(ChannelHandlerContext ctx) throws Exception;
/**
* Gets called if a {@link Throwable} was thrown.
*/
void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception;
}
public interface Dispatcher {
void doDispatcher(String msg);
}
public class DefaultDispatcher implements Dispatcher{
private final ChannelPipeline channelPipeline;
public DefaultDispatcher(ChannelPipeline channelPipeline) {
this.channelPipeline = channelPipeline;
}
@Override
public void doDispatcher(String msg) {
try {
channelPipeline.fireChannelRead(msg);
}catch (Exception e){
channelPipeline.fireExceptionCaught(e);
}
channelPipeline.fireChannelReadComplete();
}
}
测试
public class HandlerOne implements ChannelHandler {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("HandlerOne................. Before");
ctx.fireChannelRead(msg);
System.out.println("HandlerOne................. After");
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
System.out.println("HandlerOne=======ReadComplete");
ctx.fireChannelReadComplete();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
System.out.println("HandlerOne=======exceptionCaught");
ctx.fireExceptionCaught(cause);
}
}
public class HandlerTwo implements ChannelHandler {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("HandlerTwo................. Before");
ctx.fireChannelRead(msg);
System.out.println("HandlerTwo................. After");
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
System.out.println("HandlerTwo=======ReadComplete");
ctx.fireChannelReadComplete();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
System.out.println("HandlerTwo=======exceptionCaught");
ctx.fireExceptionCaught(cause);
}
}
public class HandlerThree implements ChannelHandler {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("HandlerThree................. Before");
ctx.fireChannelRead(msg);
System.out.println("HandlerThree................. After");
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
System.out.println("HandlerThree=======ReadComplete");
ctx.fireChannelReadComplete();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
System.out.println("HandlerThree=======exceptionCaught");
ctx.fireExceptionCaught(cause);
}
}
测试类
public class PipelineTest {
public static void main(String[] args) {
DefaultChannelPipeline pipeline = new DefaultChannelPipeline();
pipeline.addLast("handlerOne", new HandlerOne());
pipeline.addLast("handlerTwo", new HandlerTwo());
pipeline.addLast("handlerThree", new HandlerThree());
DefaultDispatcher dispatcher = new DefaultDispatcher(pipeline);
dispatcher.doDispatcher("aaaaaaaaaaaaaaaaaa");
}
}
输出结果:
HandlerOne................. Before
HandlerTwo................. Before
HandlerThree................. Before
HandlerThree................. After
HandlerTwo................. After
HandlerOne................. After
HandlerOne=======ReadComplete
HandlerTwo=======ReadComplete
HandlerThree=======ReadComplete
你可以在 HandlerOne 的 channelRead 方法中抛出异常,看下输出是怎样的。
欢迎在评论区留下你的总结