前言
通過異步化從串行處理轉爲並行處理實現減少處理時間。
t1 + t2 + t3 -> max(t1, t2, t3)
通過Reddision客戶端連接redis服務器時需要經過一系列的處理(認證、數據庫選擇、ping...),這些操作的特點是不互相依賴,具有無狀態性。因此可以以並行執行的方式節省連接時間。
Reactive框架的使用
Reactive與RxJava2類型,是一個封裝良好的異步框架。Redisson學習的Netty對Java的Future接口進行了加強,自定義了RFuture接口
Java的Future的缺點
TBC
RPromise
繼承了RFuture接口,增加了boolean trySuccess(T result)和boolean tryFailure(Throwable cause)方法,程序中通過它們來觸發事件的成功或失敗監聽方法。
BaseConnectionHandler源碼
public abstract class BaseConnectionHandler<C extends RedisConnection> extends ChannelInboundHandlerAdapter {
final RedisClient redisClient;
final RPromise<C> connectionPromise = new RedissonPromise<C>();
C connection;
public BaseConnectionHandler(RedisClient redisClient) {
super();
this.redisClient = redisClient;
}
@Override
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
if (connection == null) {
connection = createConnection(ctx);
}
super.channelRegistered(ctx);
}
abstract C createConnection(ChannelHandlerContext ctx);
@Override
public void channelActive(final ChannelHandlerContext ctx) {
List<RFuture<Object>> futures = new ArrayList<RFuture<Object>>();
RedisClientConfig config = redisClient.getConfig();
if (config.getPassword() != null) {
RFuture<Object> future = connection.async(RedisCommands.AUTH, config.getPassword());
futures.add(future);
}
if (config.getDatabase() != 0) {
RFuture<Object> future = connection.async(RedisCommands.SELECT, config.getDatabase());
futures.add(future);
}
if (config.getClientName() != null) {
RFuture<Object> future = connection.async(RedisCommands.CLIENT_SETNAME, config.getClientName());
futures.add(future);
}
if (config.isReadOnly()) {
RFuture<Object> future = connection.async(RedisCommands.READONLY);
futures.add(future);
}
if (config.getPingConnectionInterval() > 0) {
RFuture<Object> future = connection.async(RedisCommands.PING);
futures.add(future);
}
if (futures.isEmpty()) {
ctx.fireChannelActive();
connectionPromise.trySuccess(connection);
return;
}
final AtomicBoolean retry = new AtomicBoolean();
final AtomicInteger commandsCounter = new AtomicInteger(futures.size());
for (RFuture<Object> future : futures) {//由於是取最長的時間,所以可以直接for循環
future.onComplete((res, e) -> {
if (e != null) {
if (e instanceof RedisLoadingException) {
if (retry.compareAndSet(false, true)) {
ctx.executor().schedule(() -> {
channelActive(ctx);
}, 1, TimeUnit.SECONDS);
}
return;
}
connection.closeAsync();
connectionPromise.tryFailure(e);
return;
}
if (commandsCounter.decrementAndGet() == 0) {
//只有在所有的command執行完後,纔會處理ChannelPipeline中下一個inboundHandler的channelActive方法
ctx.fireChannelActive();
//觸發成功事件監聽器的監聽方法,並把connection對象傳遞過去
connectionPromise.trySuccess(connection);
}
});
}
}
}