前言:
moco-runner是github上一個(gè)基于netty的mock開源項(xiàng)目
這里以Http服務(wù)啟動(dòng)時(shí)的moco-runner為例介紹
以Socket服務(wù)啟動(dòng)時(shí)基本處理邏輯是一致的
啟動(dòng)流程
Netty服務(wù)端創(chuàng)建時(shí)序圖
結(jié)合Netty的Demo代碼
moco-runner封裝程度比較高涩赢,用Demo代碼結(jié)合上面的時(shí)序圖自己捋一下基礎(chǔ)實(shí)現(xiàn)
public class NettyDemo {
public static void main(String[] args) {
NioEventLoopGroup boosGroup = new NioEventLoopGroup();
NioEventLoopGroup workerGroup = new NioEventLoopGroup();
final ServerBootstrap serverBootstrap = new ServerBootstrap();
// 1. 創(chuàng)建ServerBootStrap實(shí)例
// 在moco-runner中 : MocoServer類 : start(final int port, final ChannelInitializer<? extends Channel> pipelineFactory)
serverBootstrap
.group(boosGroup, workerGroup)
// 2. 設(shè)置并綁定Reactor線程池:EventLoopGroup, EventLoop就是處理所有注冊(cè)到本線程的Selector上面的Channel
// 在moco-runner中 : MocoServer類 : group = new NioEventLoopGroup(0, MocoExecutors.executor());
.channel(NioServerSocketChannel.class)
// 3. 設(shè)置并綁定服務(wù)端的channel
.option(ChannelOption.SO_BACKLOG, 1024)
.childOption(ChannelOption.SO_KEEPALIVE, true)
.childOption(ChannelOption.TCP_NODELAY, true)
.childHandler(new ChannelInitializer<SocketChannel>() {
// 4和5. 創(chuàng)建處理網(wǎng)絡(luò)事件的ChannelPipeline和handler滑绒,網(wǎng)絡(luò)時(shí)間以流的形式在其中流轉(zhuǎn)蛤育,handler完成多數(shù)的功能定制:比如編解碼 SSl安全認(rèn)證
// 在moco-runner中 : ServerRunner類 : ((MocoHttpServer)configuration).channelInitializer()
// 在moco-runner中 : MocoHttpServer的channelInitializer實(shí)現(xiàn)如下(省略部分非關(guān)鍵代碼)
private ActualHttpServer serverSetting;
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addFirst("ssl", serverSetting.sslHandler().get());
ServerConfig serverConfig = serverSetting.getServerConfig();
pipeline.addLast("codec", new HttpServerCodec(4096,
serverConfig.getHeaderSize(),
8192, false));
pipeline.addLast("aggregator", new HttpObjectAggregator(serverConfig.getContentLength()));
pipeline.addLast("handler", new MocoHandler(serverSetting));
}
});
serverBootstrap.bind(8001);
// 6. 綁定監(jiān)聽端口并啟動(dòng)服務(wù)端
}
}
業(yè)務(wù)處理流程
moco-runner主Handler : MocoHandler
SimpleChannelInboundHandler<T>是用來接收解碼消息当船,并處理該數(shù)據(jù)業(yè)務(wù)邏輯的一個(gè)抽象類實(shí)現(xiàn)。
MocoHandler繼承自SimpleChannelInboundHandler<T>處理Mock流程
對(duì)于SimpleChannelInboundHandler<T>中的T為待處理的消息的Java類型
對(duì)于MocoHandler贤牛,所有Mock的業(yè)務(wù)邏輯都在channelRead0()中實(shí)現(xiàn)
MocoHandler的構(gòu)造器參數(shù)(ActualHttpServer)serverSetting從哪來碎乃?是什么?
回到MocoHandler的實(shí)例化過程:
- MocoHandler在MocoHttpServer類的channelInitializer方法中實(shí)例化鳖枕,構(gòu)造參數(shù)(ActualHttpServer)serverSetting又來自于MocoHttpServer的構(gòu)造器參數(shù)
- MocoHttpServer在Runner類的類方法runner(final HttpServer server)中被實(shí)例化魄梯,構(gòu)造參數(shù)(HttpServer)server又來自于runner方法的參數(shù)
- runner在StandaloneRunner類中的newRunner方法被調(diào)用
- newRunner方法在StandaloneRunner類中的run方法被調(diào)用
- run方法在JsonRunner類中的run方法被調(diào)用,參數(shù)(Server)server在JsonRunner的構(gòu)造方法中
private JsonRunner(final Iterable<? extends RunnerSetting> settings, final StartArgs startArgs) {
this.server = newServer(settings, startArgs);
}
通過以下方法組裝
private Server newServer(final Iterable<? extends RunnerSetting> settings, final StartArgs startArgs) {
// 省略對(duì)Socket服務(wù)器的判斷與處理
return createHttpServer(settings, startArgs);
}
private HttpServer createHttpServer(final Iterable<? extends RunnerSetting> settings, final StartArgs startArgs) {
HttpServer targetServer = createBaseHttpServer(settings, startArgs);
return targetServer;
}
private HttpServer createBaseHttpServer(final Iterable<? extends RunnerSetting> settings,
final StartArgs startArgs) {
HttpServer targetServer = createHttpServer(startArgs);
// 遍歷settings
for (RunnerSetting setting : settings) {
// httpParser.parseServer()最終是在BaseActualServer類中處理配置文件json列表中的request/response匹配響應(yīng)配置(接口擋板配置)宾符,獲取對(duì)應(yīng)擋板配置的HttpServer實(shí)例
HttpServer parsedServer = httpParser.parseServer(setting.getStreams(),
startArgs.getPort(), toConfigs(setting));
// 合并parsedServer與原targetServer
targetServer = mergeServer(targetServer, parsedServer);
}
return targetServer;
}
其中
private HttpServer createHttpServer(final StartArgs startArgs) {
// 省略Https的情況
return ActualHttpServer.createLogServer(startArgs.getPort().or(0));
}
這里來看下最終返回的HttpServer對(duì)象targetServer酿秸,也就是MocoHandler類的構(gòu)造器參數(shù)(ActualHttpServer)serverSetting
它是mocorunner定義的一個(gè)接口,定義了post/get/put/delete/proxy等接口方法
而我們實(shí)際最終使用的ActualHttpServer類實(shí)例是它的一個(gè)子類魏烫,ActualHttpServer直接繼承自HttpConfiguration辣苏,
而HttpConfiguration實(shí)現(xiàn)了HttpServer接口的同時(shí)又繼承自BaseActualServer
單從以上服務(wù)器的啟動(dòng)邏輯來看肝箱,BaseActualServer是我們目前更需要關(guān)注的類,
它的實(shí)例實(shí)際持有了擋板的配置項(xiàng)(List<Setting<T>>)settings稀蟋,
并可以通過BaseActualServer的mergeServer(final U thatServer)方法煌张,
將thatServer實(shí)例的settings合并到當(dāng)前BaseActualServer的實(shí)例中
MocoHandler類實(shí)例持有的屬性ImmutableList<Setting<HttpResponseSetting>> settings
看清楚以上邏輯后,這里就知道了MocoHandler持有的屬性settings退客,就是來自于前期經(jīng)過多次merge的BaseActualServer實(shí)例的settings骏融,保存的是擋板的配置項(xiàng)
這個(gè)settings在MocoHandler的業(yè)務(wù)處理方法
channelRead0(final ChannelHandlerContext ctx, final FullHttpRequest message)
的子調(diào)用
doGetHttpResponse(final HttpRequest request)
中被遍歷>匹配>命中則調(diào)用writeToResponse處理實(shí)際業(yè)務(wù)并作返回
for (Setting setting : settings) {
if (setting.match(request)) {
logger.info(String.format("Response by setting : %s", setting.toString()));
setting.writeToResponse(context);
return httpResponse;
}
}