Zuul2的核心架构就是就是两大体系,netty体系和filter体系。
1 Netty体系
Zuul2底层采用Netty的事件响应模式,要掌握zuul2就必须先要掌握Netty。
1.1 Channel、Event、EventLoop、EventLoopGroup、ChannelHandler
Channel:每一次通信就会启动一个channel,一个channel对应一个socket
Event:事件,channel的入站和出站都会触发一些列的事件,这些事件会回调ChannelHandler的逻辑。入站:连接已被激活或者连接失活;数据读取;用户事件;错误事件。出站:打开或者关闭到远程节点的连接;将数据写到或者冲刷到套接字。
EventLoop:事件循环,控制流、多线程处理以及并发处理。每个EventLoop对应一个线程。
EventLoopGroup:负责给每个创建的channel分配一个EventLoop。
解释说明:
EventLoop与Channel是多对多的,一个线程可以支持多个channel,一旦一个Channel 被分配给一个EventLoop,它将在它的整个生命周期中都使用这个EventLoop,所以我们面向channel开发时不需要担心线程安全的问题。
1.2 ChannelPipeline、ChannelHandler、ChannelHandelerContext
ChannelHandler:每个ChannelHandler 的实例都类似于一种为了响应特定事件而被执行的回调。Handler分为入站和出站两种类型。
ChannelPipeline:一组ChannelHandler的编排,入站事件从头部开始执行,出站事件从尾部开始执行。
ChannelHandlerContext:代表了ChannelHandler 和ChannelPipeline 之间的关联,是channel信息维护的手段。
关联关系:
解释说明:
ChannelPipeline、ChannelHandler是池的概念,channel和ChannelHandlerContext的生命周期是临时性的。
1.3 BootStarp和ServerBootStarp
Netty网络编程中的2个概念,面向客户端的是BootStarp,面向服务端的是ServerBootStarp,像我们统一网关的应用场景就是面向服务端。
BootStarp:连接到远程节点的客户端应用程序。
ServerBootstrap:就是比BootStarp在前面绑定一个接口多嵌套一个ServerChannel来处理套接字,后面还是交给BootStarp与客户端交互。
2 Filter体系:
Zuul2实现了一种基于filter的体系设计,通过实现ZuulFilter来定制属于自己的网关,抛开netty不讲我们来看看这套体系是如何运作的。
这套体系核心接口:ZuulFilter、ZuulMessage、FilterRunner、FilterUsageNotifier,其中每个接口都有很深层级的继承和实现。
ZuulFiter:官宣暴漏给用户自己实现的接口,位置和运行方式两个维度。位置分为:inbound、outbound、endpoint,方式分为同步和异步。其中endpoint只有同步方式。
ZuulMessage:filter体系中传递的消息信息,核心属性是SessionContext,分为Request和Response两种message。
FilterRunner:filter体系的调度中心,filter中抽象方法都有runner来调用。分为EndPointRunner和FilterChainRunner两种。
FilterUsageNotifier:filter体系的调用通知机制,目前功能比较单一,只实现了统计功能,但是从体系设计中看得出可以扩展出更多服务能力。
UML图:
核心代码在BaseZuulFilterRunner的filter方法,传入ZuulMessage和ZuulFilter完成对他们的调度,本质上还是让zuulFilter自己消费了ZuulMessage。
ZuulFilterChainRunner完成了Filter链的调用。
3 如何结合:
上面说的Netty体系和Filter体系是Zuul2中的两大独立体系,我们直接没有看到它们之间有什么关联。因为讲Netty的时候没有提到过Filter,讲Filter的时候也没有提到过Channel。那么这两个体系是怎么关联的呢?
本质是上Filter体系作为Netty体系Pipeline中的一环,或者理解为内部的一次嵌套。秘密在ZuulFilterChainHandler和BaseZuulChannelInitializer中。
ZuulFilterChainHandler通过channelRead方法和方法,在channel的读取和自定义事件回调时织入了filter体系的逻辑,而ZuulFilterChainHandler本身又通过BaseZuulChannelInitializer的addZuulHandlers方法被织入了channel的Pipeline中。
ZuulFilterChainHandler:
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof HttpRequestMessage) {
zuulRequest = (HttpRequestMessage)msg;
//Replace NETTY_SERVER_CHANNEL_HANDLER_CONTEXT in SessionContext
final SessionContext zuulCtx = zuulRequest.getContext();
zuulCtx.put(NETTY_SERVER_CHANNEL_HANDLER_CONTEXT, ctx);
zuulCtx.put(ZUUL_FILTER_CHAIN, requestFilterChain);
requestFilterChain.filter(zuulRequest);
}
else if ((msg instanceof HttpContent)&&(zuulRequest != null)) {
requestFilterChain.filter(zuulRequest, (HttpContent) msg);
}
else {
LOG.debug("Received unrecognized message type. " + msg.getClass().getName());
ReferenceCountUtil.release(msg);
}
}
BaseZuulChannelInitializer:
protected void addZuulHandlers(final ChannelPipeline pipeline)
{
pipeline.addLast("logger", nettyLogger);
pipeline.addLast(new ClientRequestReceiver(sessionContextDecorator));
pipeline.addLast(passportLoggingHandler);
addZuulFilterChainHandler(pipeline);
pipeline.addLast(new ClientResponseWriter(requestCompleteHandler, registry));
}
简洁说,netty是外圈,filter是其中一环上的内圈;netty为zuul2提供基础设施,filter在基础设施上做上层建设。