下属是一个Netty中pipeline设计模式的高仿示例。下述代码中:Channel对应netty中的AbstractChannel, AbstractContext对应netty中的 AbstractChannelHandlerContext , Inhander对应netty中的ChannelInboundHandler,OutHandler对应netty中的ChannelOutboundHandler,Initializer对应netty中的ChannelInitializer, ChannelPipeLine对应netty中的DefaultChannelPipeline,测试的main方法在Channel中。感兴趣的同学可以拷贝运行代码,并对照netty源码研究。
Context:
public interface Context {
public Handler handler();
}
AbstractContext:
public abstract class AbstractContext implements Context {
volatile AbstractContext next;
volatile AbstractContext prev;
private final boolean inbound;
private final boolean outbound;
private final ChannelPipeLine pipeline;
private final String name;
public AbstractContext(String name, ChannelPipeLine pipeline, boolean inbound, boolean outbound) {
this.inbound = inbound;
this.outbound = outbound;
this.name = name;
this.pipeline = pipeline;
}
public ChannelPipeLine pipeline() {
return pipeline;
}
public Channel channel() {
return pipeline.channel();
}
public String getName() {
return name;
}
private AbstractContext findContextInbound() {
AbstractContext ctx = this;
do {
ctx = ctx.next;
} while (!ctx.inbound);
return ctx;
}
private AbstractContext findContextOutbound() {
AbstractContext ctx = this;
do {
ctx = ctx.prev;
} while (!ctx.outbound);
return ctx;
}
public void request() {
final AbstractContext next = findContextOutbound();
next.invokeRequest();
}
private void invokeRequest() {
OutHandler outhandler = (OutHandler)handler();
outhandler.request(this);
}
public void response() {
final AbstractContext next = findContextInbound();
next.invokeResponse();
}
private void invokeResponse() {
InHandler inhandler = (InHandler)handler();
inhandler.response(this);
}
public void register() {
AbstractContext contextInbound = findContextInbound();
contextInbound.invokeRegister();
}
private void invokeRegister() {
InHandler inhandler = (InHandler)handler();
inhandler.register(this);
}
}
DefaultContext:
public class DefaultContext extends AbstractContext {
private Handler handler;
public DefaultContext(String name, ChannelPipeLine pipeline, Handler handler) {
super(name, pipeline, isInbout(handler), isOutbound(handler));
this.handler = handler;
}
@Override
public Handler handler() {
return handler;
}
private static boolean isInbout(Handler handler) {
return handler instanceof InHandler;
}
private static boolean isOutbound(Handler handler) {
return handler instanceof OutHandler;
}
}
Handler:
public interface Handler {
}
InHandler:
public interface InHandler extends Handler {
public void response(AbstractContext ctx);
public void register(AbstractContext ctx);
}
OutHandler:
public interface OutHandler extends Handler {
public void request(AbstractContext ctx);
}
HeadCtx:
public class HeadCtx extends AbstractContext implements OutHandler {
public HeadCtx(ChannelPipeLine pipeline) {
super("Head", pipeline, false, true);
}
@Override
public Handler handler() {
return this;
}
@Override
public void request(AbstractContext ctx) {
System.out.println("head connect method is called!!!");
/* ChannelPipeLine pipeLine = getPipeline();
pipeLine.response();*/
}
public void fireRegister() {
}
}
TailCtx:
public class TailCtx extends AbstractContext implements InHandler {
public TailCtx(ChannelPipeLine pipeline) {
super("Tail", pipeline, true, false);
}
@Override
public Handler handler() {
return this;
}
@Override
public void response(AbstractContext ctx) {
System.out.println("taill response is called !!!");
/* ChannelPipeLine pipeline = getPipeline();
pipeline.request();*/
}
@Override
public void register(AbstractContext ctx) {
}
}
ChannelPipeLine:
import java.util.NoSuchElementException;
import java.util.concurrent.atomic.AtomicInteger;
public class ChannelPipeLine {
private Channel channel;
final AbstractContext head;
final AbstractContext tail;
final AtomicInteger inCounter = new AtomicInteger(0);
final AtomicInteger outCounter = new AtomicInteger(0);
public ChannelPipeLine(Channel channel) {
this.channel = channel;
head = new HeadCtx(this);
tail = new TailCtx(this);
head.next = tail;
tail.prev = head;
}
public Channel channel() {
return channel;
}
public final AbstractContext context(Handler handler) {
if (handler == null) {
throw new NullPointerException("handler");
}
AbstractContext ctx = head.next;
for (;;) {
if (ctx == null) {
return null;
}
if (ctx.handler() == handler) {
return ctx;
}
ctx = ctx.next;
}
}
public final ChannelPipeLine remove(Handler handler) {
remove(getContextOrDie(handler));
return this;
}
private AbstractContext getContextOrDie(Handler handler) {
AbstractContext ctx = context(handler);
if (ctx == null) {
throw new NoSuchElementException(handler.getClass().getName());
} else {
return ctx;
}
}
private AbstractContext remove(final AbstractContext ctx) {
assert ctx != head && ctx != tail;
synchronized (this) {
remove0(ctx);
}
return ctx;
}
private static void remove0(AbstractContext ctx) {
AbstractContext prev = ctx.prev;
AbstractContext next = ctx.next;
prev.next = next;
next.prev = prev;
}
public ChannelPipeLine addLast(Handler handler) {
DefaultContext newCtx = null;
if (handler instanceof OutHandler) {
newCtx = new DefaultContext("OutHandler#" + inCounter.getAndAdd(1), this, handler);
} else if (handler instanceof InHandler) {
newCtx = new DefaultContext("InHandler#" + outCounter.getAndAdd(1), this, handler);
} else {
throw new IllegalArgumentException("handler must be InHandler or OutHandler");
}
addLast0(newCtx);
return this;
}
private void addLast0(AbstractContext newCtx) {
AbstractContext prev = tail.prev;
newCtx.prev = prev;
newCtx.next = tail;
prev.next = newCtx;
tail.prev = newCtx;
}
public void request() {
tail.request();
}
public void response() {
head.response();
}
public ChannelPipeLine register() {
head.register();
return this;
}
}
Initializer:
public abstract class Initializer implements InHandler {
private String name = "initializer";
@Override
public void response(AbstractContext ctx) {
}
@Override
public void register(AbstractContext ctx) {
initChannel(ctx);
ctx.register();
}
private void initChannel(AbstractContext ctx) {
try {
Channel channel = ctx.channel();
initChannel(channel);
} finally {
remove(ctx);
}
}
public abstract void initChannel(Channel channel);
private void remove(AbstractContext ctx) {
ChannelPipeLine pipeline = ctx.pipeline();
if (pipeline.context(this) != null) {
pipeline.remove(this);
}
}
}
Channel:
public class Channel {
private ChannelPipeLine pipeLine;
public Channel() {
this.pipeLine = new ChannelPipeLine(this);
}
public ChannelPipeLine pipeLine() {
return this.pipeLine;
}
public static void main(String[] args) {
Handler inHandler1 = new InHandler() {
private String name = "InHandler1";
@Override
public void response(AbstractContext ctx) {
System.out.println("InHandler1 response called !!!");
ctx.response();
}
@Override
public void register(AbstractContext ctx) {
System.out.println("inHandler 1 register called !!!");
ctx.register();
}
};
Handler outHandler1 = new OutHandler() {
private String name = "OutHandler1";
@Override
public void request(AbstractContext ctx) {
System.out.println("OutHandler1 connect called !!!");
ctx.request();
}
};
Handler inHandler2 = new InHandler() {
private String name = "InHandler2";
@Override
public void response(AbstractContext ctx) {
System.out.println("InHandler2 response called !!!");
ctx.response();
}
@Override
public void register(AbstractContext ctx) {
System.out.println("inHandler 2 register called !!!");
ctx.register();
}
};
Handler outHandler2 = new OutHandler() {
private String name = "OutHandler2";
@Override
public void request(AbstractContext ctx) {
System.out.println("OutHandler2 connect called !!!");
ctx.request();
}
};
Channel channel = new Channel();
ChannelPipeLine pipeLine = channel.pipeLine();
pipeLine.addLast(new Initializer() {
@Override
public void initChannel(Channel channel) {
ChannelPipeLine pipeLine = channel.pipeLine();
pipeLine.addLast(inHandler1);
pipeLine.addLast(outHandler1);
pipeLine.addLast(inHandler2);
pipeLine.addLast(outHandler2);
}
});
pipeLine.register();
System.out.println("add done !!!");
System.out.println();
System.out.println("out bount event start !!!");
pipeLine.request();
System.out.println();
System.out.println("in bount event start !!!");
pipeLine.response();
}
}