通过走读Lettuce异步读取源码,针对Lettuce连接建立过程进行源码走读
总体展示一个Lettuce异步get时序
通过时序图可以发现MasterSlaveChannelWriter主要提供一个负载分配的功能,并不是真正的命令发送服务
下面通过源码分析实现过程
public static <K, V> StatefulRedisMasterSlaveConnection<K, V> connect(RedisClient redisClient, RedisCodec<K, V> codec,
Iterable<RedisURI> redisURIs) {
LettuceAssert.notNull(redisClient, "RedisClient must not be null");
LettuceAssert.notNull(codec, "RedisCodec must not be null");
LettuceAssert.notNull(redisURIs, "RedisURIs must not be null");
List<RedisURI> uriList = LettuceLists.newList(redisURIs);
LettuceAssert.isTrue(!uriList.isEmpty(), "RedisURIs must not be empty");
if (isSentinel(uriList.get(0))) {
return connectSentinel(redisClient, codec, uriList.get(0));
} else {
return connectStaticMasterSlave(redisClient, codec, uriList);
}
}
private static <K, V> StatefulRedisMasterSlaveConnection<K, V> connectSentinel(RedisClient redisClient,
RedisCodec<K, V> codec, RedisURI redisURI) {
//创建拓扑提供者为哨兵拓扑
TopologyProvider topologyProvider = new SentinelTopologyProvider(redisURI.getSentinelMasterId(), redisClient, redisURI);
//创建哨兵拓扑刷新服务
SentinelTopologyRefresh sentinelTopologyRefresh = new SentinelTopologyRefresh(redisClient,
redisURI.getSentinelMasterId(), redisURI.getSentinels());
//利用拓扑提供者和redisClient创建主备拓扑刷新服务
MasterSlaveTopologyRefresh refresh = new MasterSlaveTopologyRefresh(redisClient, topologyProvider);
//创建主备连接提供者
MasterSlaveConnectionProvider<K, V> connectionProvider = new MasterSlaveConnectionProvider<>(redisClient, codec,
redisURI, Collections.emptyMap());
//使用主备拓扑刷新服务获取所有节点将其设置到连接提供者中
connectionProvider.setKnownNodes(refresh.getNodes(redisURI));
//使用连接提供者创建主备通道写入器
MasterSlaveChannelWriter<K, V> channelWriter = new MasterSlaveChannelWriter<>(connectionProvider);
//创建连接
StatefulRedisMasterSlaveConnectionImpl<K, V> connection = new StatefulRedisMasterSlaveConnectionImpl<>(channelWriter,
codec, redisURI.getTimeout());
connection.setOptions(redisClient.getOptions());
Runnable runnable = () -> {
try {
LOG.debug("Refreshing topology");
List<RedisNodeDescription> nodes = refresh.getNodes(redisURI);
if (nodes.isEmpty()) {
LOG.warn("Topology refresh returned no nodes from {}", redisURI);
}
LOG.debug("New topology: {}", nodes);
connectionProvider.setKnownNodes(nodes);
} catch (Exception e) {
LOG.error("Error during background refresh", e);
}
};
try {
//向连接注册可关闭服务
connection.registerCloseables(new ArrayList<>(), sentinelTopologyRefresh);
//绑定哨兵拓扑结构变化执行逻辑
sentinelTopologyRefresh.bind(runnable);
} catch (RuntimeException e) {
connection.close();
throw e;
}
return connection;
}
public StatefulRedisConnectionImpl(RedisChannelWriter writer, RedisCodec<K, V> codec, Duration timeout) {
super(writer, timeout);
this.codec = codec;
//创建异步步连接
this.async = newRedisAsyncCommandsImpl();
//创建同步连接
this.sync = newRedisSyncCommandsImpl();
//创建响应式连接
this.reactive = newRedisReactiveCommandsImpl();
}
protected RedisAsyncCommandsImpl<K, V> newRedisAsyncCommandsImpl() {
//使用装饰器模式对当前实例进行增强
return new RedisAsyncCommandsImpl<>(this, codec);
}
public RedisAsyncCommandsImpl(StatefulRedisConnection<K, V> connection, RedisCodec<K, V> codec) {
super(connection, codec);
}
public AbstractRedisAsyncCommands(StatefulConnection<K, V> connection, RedisCodec<K, V> codec) {
this.connection = connection;
this.codec = codec;
this.commandBuilder = new RedisCommandBuilder<>(codec);
}
StatefulRedisConnectionImpl
@Override
public <T> RedisCommand<K, V, T> dispatch(RedisCommand<K, V, T> command) {
//前置处理
RedisCommand<K, V, T> toSend = preProc