简单粗暴地将原有Netty组件集成到Vert.x的办法
前情提要
Vert.x写的很爽,但是那个vertx.createNetServer()获取到的tcp服务器中还是需要自己处理“粘包”,“半包”(这里只做比喻用,就是如何处理数据边界问题),而且更重要的是无法复用Netty库或者旧有的codec
为了解决这个问题我根据vertx.createNetServer()的源码,自己从ServerBootstrap开始造,挺费劲的
在和Vertx中国用户组的群友们吹水的时候,有人提到可以进行一个类型强转获取到Netty的pipeline,让我去参考io.vertx.mysqlclient.impl.MySQLSocketConnection#init()这个方法
实战
版本
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-core</artifactId>
<version>4.0.0</version>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-mysql-client</artifactId>
<version>4.0.0</version>
代码
vertx.createNetServer(netServerOptions)
.connectHandler(socket -> {
ChannelPipeline pipeline = ((NetSocketInternal) socket).channelHandlerContext().pipeline();
})
.listen(port)
.map(netServer -> {
setNetServer(netServer);
return this;
});
嗯,就这么简单。。。。。。
原理
前置知识
Http(3.0除外),MySQL,Redis等协议都是基于TCP协议的,也就说Vertx下面的这些Client也是基于Netty的
为什么不可能是基于Vertx本体的?因为那个api真的很难用。
所以只要去看看其Client的源码就知道了
源码
这里选取MySQL的Client查看,直接查找pipeline
@Override
public void init() {
//....无关代码已经省略
ChannelPipeline pipeline = socket.channelHandlerContext().pipeline();
//....无关代码已经省略
}
然后再去看看socket是个什么东西,是其父类io.vertx.sqlclient.impl.SocketConnectionBase
中的一个字段,其类型为io.vertx.core.net.impl.NetSocketInternal,再反查他是在哪里初始化的
public SocketConnectionBase(NetSocketInternal socket,
boolean cachePreparedStatements,
int preparedStatementCacheSize,
Predicate<String> preparedStatementCacheSqlFilter,
int pipeliningLimit,
ContextInternal context) {
this.socket = socket;
//....无关代码已经省略
}
在反查其使用,看看这个NetSocketInternal是怎么传入的,经过多次跳转可以看到在这里io.vertx.mysqlclient.impl.MySQLConnectionFactory#doConnectInternal的代码告诉我到底传入了什么,嗯,果然是类型强转来的
@Override
protected void doConnectInternal(Promise<Connection> promise) {
//netClient类型 NetClient netClient;
Future<NetSocket> fut = netClient.connect(socketAddress);
fut.onComplete(ar -> {
if (ar.succeeded()) {
NetSocket so = ar.result();
MySQLSocketConnection conn = new MySQLSocketConnection((NetSocketInternal) so, cachePreparedStatements, preparedStatementCacheSize, preparedStatementCacheSqlFilter, context);
conn.init();
conn.sendStartupMessage(username, password, database, collation, serverRsaPublicKey, properties, sslMode, initialCapabilitiesFlags, charsetEncoding, authenticationPlugin, promise);
} else {
promise.fail(ar.cause());
}
});
}
预告
上一个强行获取Eventloop线程做的嵌入,写都写了,过两天也写写吧