Redission核心代码流程使用Promise模式。 这归功于netty优秀的架构,是Redission提供异步和同步编程的核心。
Config config = new Config();
config.useSingleServer().setAddress("redis://192.168.2.41:6379")
.setPassword("rabbit123@");
//创建客户端
RedissonClient redisson = Redisson.create(config);
//创建Bucket对象
RBucket rBucket = redisson.getBucket("dddd");
rBucket.set("ffff");
String ss = rBucket.get();
这篇博客主要详细介绍Redission提供的RBucket 类。
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.redisson.api;
import java.util.concurrent.TimeUnit;
public interface RBucket extends RExpirable, RBucketAsync {
long size();
V get();
V getAndDelete();
boolean trySet(V var1);
boolean trySet(V var1, long var2, TimeUnit var4);
boolean setIfExists(V var1);
boolean setIfExists(V var1, long var2, TimeUnit var4);
boolean compareAndSet(V var1, V var2);
V getAndSet(V var1);
V getAndSet(V var1, long var2, TimeUnit var4);
void set(V var1);
void set(V var1, long var2, TimeUnit var4);
int addListener(ObjectListener var1);
}
RBucket提供set()和sget()方法用于保存和获取对象。RedissonBucket 是对RBucket对象的实现。RedissonBucket实现set()和get()同步方法和异步方法。
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.redisson;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
import java.util.function.BiConsumer;
import org.redisson.api.ObjectListener;
import org.redisson.api.RBucket;
import org.redisson.api.RFuture;
import org.redisson.api.RPatternTopic;
import org.redisson.api.listener.SetObjectListener;
import org.redisson.client.codec.Codec;
import org.redisson.client.codec.StringCodec;
import org.redisson.client.protocol.RedisCommands;
import org.redisson.command.CommandAsyncExecutor;
import org.redisson.misc.CountableListener;
import org.redisson.misc.RPromise;
import org.redisson.misc.RedissonPromise;
public class RedissonBucket extends RedissonExpirable implements RBucket {
public RedissonBucket(CommandAsyncExecutor connectionManager, String name) {
super(connectionManager, name);
}
public RedissonBucket(Codec codec, CommandAsyncExecutor connectionManager, String name) {
super(codec, connectionManager, name);
}
public boolean compareAndSet(V expect, V update) {
return (Boolean)this.get(this.compareAndSetAsync(expect, update));
}
public RFuture compareAndSetAsync(V expect, V update) {
if (expect == null && update == null) {
return this.trySetAsync((Object)null);
} else if (expect == null) {
return this.trySetAsync(update);
} else {
return update == null ? this.commandExecutor.evalWriteAsync(this.getName(), this.codec, RedisCommands.EVAL_BOOLEAN, "if redis.call('get', KEYS[1]) == ARGV[1] then redis.call('del', KEYS[1]); return 1 else return 0 end", Collections.singletonList(this.getName()), new Object[]{this.encode(expect)}) : this.commandExecutor.evalWriteAsync(this.getName(), this.codec, RedisCommands.EVAL_BOOLEAN, "if redis.call('get', KEYS[1]) == ARGV[1] then redis.call('set', KEYS[1], ARGV[2]); return 1 else return 0 end", Collections.singletonList(this.getName()), new Object[]{this.encode(expect), this.encode(update)});
}
}
public V getAndSet(V newValue) {
return this.get(this.getAndSetAsync(newValue));
}
public RFuture getAndSetAsync(V newValue) {
return newValue == null ? this.commandExecutor.evalWriteAsync(this.getName(), this.codec, RedisCommands.EVAL_OBJECT, "local v = redis.call('get', KEYS[1]); redis.call('del', KEYS[1]); return v", Collections.singletonList(this.getName()), new Object[0]) : this.commandExecutor.writeAsync(this.getName(), this.codec, RedisCommands.GETSET, new Object[]{this.getName(), this.encode(newValue)});
}
public V get() {
return this.get(this.getAsync());
}
public RFuture getAsync() {
return this.commandExecutor.readAsync(this.getName(), this.codec, RedisCommands.GET, new Object[]{this.getName()});
}
public V getAndDelete() {
return this.get(this.getAndDeleteAsync());
}
public RFuture getAndDeleteAsync() {
return this.commandExecutor.evalWriteAsync(this.getName(), this.codec, RedisCommands.EVAL_OBJECT, "local currValue = redis.call('get', KEYS[1]); redis.call('del', KEYS[1]); return currValue; ", Collections.singletonList(this.getName()), new Object[0]);
}
public long size() {
return (Long)this.get(this.sizeAsync());
}
public RFuture sizeAsync() {
return this.commandExecutor.readAsync(this.getName(), this.codec, RedisCommands.STRLEN, new Object[]{this.getName()});
}
public void set(V value) {
this.get(this.setAsync(value));
}
public RFuture setAsync(V value) {
return value == null ? this.commandExecutor.writeAsync(this.getName(), RedisCommands.DEL_VOID, new Object[]{this.getName()}) : this.commandExecutor.writeAsync(this.getName(), this.codec, RedisCommands.SET, new Object[]{this.getName(), this.encode(value)});
}
public void set(V value, long timeToLive, TimeUnit timeUnit) {
this.get(this.setAsync(value, timeToLive, timeUnit));
}
public RFuture setAsync(V value, long timeToLive, TimeUnit timeUnit) {
return value == null ? this.commandExecutor.writeAsync(this.getName(), RedisCommands.DEL_VOID, new Object[]{this.getName()}) : this.commandExecutor.writeAsync(this.getName(), this.codec, RedisCommands.PSETEX, new Object[]{this.getName(), timeUnit.toMillis(timeToLive), this.encode(value)});
}
public RFuture trySetAsync(V value) {
return value == null ? this.commandExecutor.readAsync(this.getName(), this.codec, RedisCommands.NOT_EXISTS, new Object[]{this.getName()}) : this.commandExecutor.writeAsync(this.getName(), this.codec, RedisCommands.SETNX, new Object[]{this.getName(), this.encode(value)});
}
public RFuture trySetAsync(V value, long timeToLive, TimeUnit timeUnit) {
if (value == null) {
throw new IllegalArgumentException("Value can't be null");
} else {
return this.commandExecutor.writeAsync(this.getName(), this.codec, RedisCommands.SET_BOOLEAN, new Object[]{this.getName(), this.encode(value), "PX", timeUnit.toMillis(timeToLive), "NX"});
}
}
public boolean trySet(V value, long timeToLive, TimeUnit timeUnit) {
return (Boolean)this.get(this.trySetAsync(value, timeToLive, timeUnit));
}
public boolean trySet(V value) {
return (Boolean)this.get(this.trySetAsync(value));
}
public boolean setIfExists(V value) {
return (Boolean)this.get(this.setIfExistsAsync(value));
}
public RFuture setIfExistsAsync(V value) {
return value == null ? this.commandExecutor.evalWriteAsync(this.getName(), this.codec, RedisCommands.EVAL_BOOLEAN, "local currValue = redis.call('get', KEYS[1]); if currValue ~= false then redis.call('del', KEYS[1]); return 1;end;return 0; ", Collections.singletonList(this.getName()), new Object[0]) : this.commandExecutor.writeAsync(this.getName(), this.codec, RedisCommands.SET_BOOLEAN, new Object[]{this.getName(), this.encode(value), "XX"});
}
public boolean setIfExists(V value, long timeToLive, TimeUnit timeUnit) {
return (Boolean)this.get(this.setIfExistsAsync(value, timeToLive, timeUnit));
}
public RFuture setIfExistsAsync(V value, long timeToLive, TimeUnit timeUnit) {
if (value == null) {
throw new IllegalArgumentException("Value can't be null");
} else {
return this.commandExecutor.writeAsync(this.getName(), this.codec, RedisCommands.SET_BOOLEAN, new Object[]{this.getName(), this.encode(value), "PX", timeUnit.toMillis(timeToLive), "XX"});
}
}
public RFuture getAndSetAsync(V value, long timeToLive, TimeUnit timeUnit) {
return this.commandExecutor.evalWriteAsync(this.getName(), this.codec, RedisCommands.EVAL_OBJECT, "local currValue = redis.call('get', KEYS[1]); redis.call('psetex', KEYS[1], ARGV[2], ARGV[1]); return currValue; ", Collections.singletonList(this.getName()), new Object[]{this.encode(value), timeUnit.toMillis(timeToLive)});
}
public V getAndSet(V value, long timeToLive, TimeUnit timeUnit) {
return this.get(this.getAndSetAsync(value, timeToLive, timeUnit));
}
public int addListener(ObjectListener listener) {
return listener instanceof SetObjectListener ? this.addListener("__keyevent@*:set", (SetObjectListener)listener, SetObjectListener::onSet) : super.addListener(listener);
}
public RFuture addListenerAsync(ObjectListener listener) {
return listener instanceof SetObjectListener ? this.addListenerAsync("__keyevent@*:set", (SetObjectListener)listener, SetObjectListener::onSet) : super.addListenerAsync(listener);
}
public void removeListener(int listenerId) {
RPatternTopic expiredTopic = new RedissonPatternTopic(StringCodec.INSTANCE, this.commandExecutor, "__keyevent@*:set");
expiredTopic.removeListener(listenerId);
super.removeListener(listenerId);
}
public RFuture removeListenerAsync(int listenerId) {
RPromise result = new RedissonPromise();
CountableListener listener = new CountableListener(result, (Object)null, 3);
RPatternTopic setTopic = new RedissonPatternTopic(StringCodec.INSTANCE, this.commandExecutor, "__keyevent@*:set");
setTopic.removeListenerAsync(listenerId).onComplete(listener);
this.removeListenersAsync(listenerId, listener);
return result;
}
}
RedissonBucket 对象又继承了基类RedissionObject对象。 在RedissionObject 包含name 作为键,codec 作为编码解码器,commandExecutor 用来执行所以的操作。
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.redisson;
import io.netty.buffer.ByteBuf;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.concurrent.TimeUnit;
import java.util.function.BiConsumer;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import org.redisson.api.DeletedObjectListener;
import org.redisson.api.ExpiredObjectListener;
import org.redisson.api.ObjectListener;
import org.redisson.api.RFuture;
import org.redisson.api.RObject;
import org.redisson.api.RPatternTopic;
import org.redisson.api.listener.PatternMessageListener;
import org.redisson.client.codec.ByteArrayCodec;
import org.redisson.client.codec.Codec;
import org.redisson.client.codec.StringCodec;
import org.redisson.client.protocol.RedisCommands;
import org.redisson.command.CommandAsyncExecutor;
import org.redisson.misc.CountableListener;
import org.redisson.misc.Hash;
import org.redisson.misc.RPromise;
import org.redisson.misc.RedissonPromise;
public abstract class RedissonObject implements RObject {
protected final CommandAsyncExecutor commandExecutor;
protected String name;
protected final Codec codec;
public RedissonObject(Codec codec, CommandAsyncExecutor commandExecutor, String name) {
this.codec = codec;
this.name = name;
this.commandExecutor = commandExecutor;
}
public RedissonObject(CommandAsyncExecutor commandExecutor, String name) {
this(commandExecutor.getConnectionManager().getCodec(), commandExecutor, name);
}
public static String prefixName(String prefix, String name) {
return name.contains("{") ? prefix + ":" + name : prefix + ":{" + name + "}";
}
public static String suffixName(String name, String suffix) {
return name.contains("{") ? name + ":" + suffix : "{" + name + "}:" + suffix;
}
protected final Stream toStream(Iterator iterator) {
Spliterator spliterator = Spliterators.spliteratorUnknownSize(iterator, 256);
return StreamSupport.stream(spliterator, false);
}
protected final V get(RFuture future) {
return this.commandExecutor.get(future);
}
protected final long toSeconds(long timeout, TimeUnit unit) {
long seconds = unit.toSeconds(timeout);
if (timeout != 0L && seconds == 0L) {
seconds = 1L;
}
return seconds;
}
public String getName() {
return this.name;
}
protected String getName(Object o) {
return this.getName();
}
public void rename(String newName) {
this.get(this.renameAsync(newName));
}
public RFuture sizeInMemoryAsync() {
return this.commandExecutor.writeAsync(this.getName(), StringCodec.INSTANCE, RedisCommands.MEMORY_USAGE, new Object[]{this.getName()});
}
public final RFuture sizeInMemoryAsync(List
当RedissionBucket执行set()方法时,这将是Redission整个流程的核心。
1 -RedissonBucket 执行set()方法,并通过get()方法获取返回值
public void set(V value) {
this.get(this.setAsync(value));
}
2 -真正执行set操作,为CommandAsyncExecutor 来完成。主要封装redis的键值,命令以及所需要的参数
public RFuture setAsync(V value) {
return value == null ? this.commandExecutor.writeAsync(this.getName(), RedisCommands.DEL_VOID, new Object[]{this.getName()}) : this.commandExecutor.writeAsync(this.getName(), this.codec, RedisCommands.SET, new Object[]{this.getName(), this.encode(value)});
}
3-CommandAsyncService 首先通过netty框架创建一个promise接口,并且返回。
public RFuture writeAsync(String key, Codec codec, RedisCommand command, Object... params) {
RPromise mainPromise = this.createPromise();
NodeSource source = this.getNodeSource(key);
this.async(false, source, codec, command, params, mainPromise, false);
return mainPromise;
}
在此,RBucket 执行一个set操作,由netty创建一个promise对象,并且RBucket通过get()同步方法获取promise完成时的结果。