其中:
- RedisAccessor用来设置ConnectFactory即spring初始化时, 检查设置redisTempalte的序列化实例的
- RedisOperations用来定义通用命令(与数据结构类型无关)及opsForXXX、execute等所有操作
- StringRedisTemplate是将定序列化器全部为StringSerializer的子类
配置redis连接参数及连接管理
private RedisConnectionFactory connectionFactory;//管理redis连接和配置参数
如果用cluster模式或codis等框架, 只需set对应的RedisConnectionFactory
实现即可.
序列化器, 用来完成读写时对象和byte[] 的相互转换.
//开启事务,事务的前提操作是基于同一个连接.否则可能多节点是可能MULTI/EXEC等打到不同节点
private boolean enableTransactionSupport = false;
private boolean exposeConnection = false;//是否对连接进行暴露
private boolean initialized = false;//执行afterProperties后的初始化标志,不初始化会报错
private boolean enableDefaultSerializer = true;//如果未设置序列化器,是否使用默认
private RedisSerializer<?> defaultSerializer;//默认的序列化器
private RedisSerializer<String> stringSerializer = new StringRedisSerializer();//暴露给应用的String类型的的序列化器
private RedisSerializer keySerializer = null;//负责所有类型的key序列化
private RedisSerializer valueSerializer = null;
private RedisSerializer hashKeySerializer = null;
private RedisSerializer hashValueSerializer = null;
//string类型:value采用valueSerializer
//hash类型:field采用hashKeySerializer,value采用hashValueSerializer
//list类型:value采用valueSerializer
//set类型:member采用valueSerializer
//zset类型:member采用valueSerializer
//script类型:args和result均用valueSerializer
如果不设置, 默认为JdkSerializationRedisSerializer
:
public void serialize(Object object, OutputStream outputStream) throws IOException {
if (!(object instanceof Serializable)) {
throw new IllegalArgumentException(this.getClass().getSimpleName() + " requires a Serializable payload but received an object of type [" + object.getClass().getName() + "]");
} else {
ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
objectOutputStream.writeObject(object);
objectOutputStream.flush();
}
}
默认的JDK占用空间比较大,可读性差, 一般是先将对象转化为JSON串, 再储存到redis. 当然为了节省空间, 也可以使用kryo/protobuf等框架进行序列化, 但可读性比较差.
private ScriptExecutor<K> scriptExecutor;//执行script时的执行器
private ValueOperations<K, V> valueOps;//opsForValue返回String操作API
private ListOperations<K, V> listOps;//opsForList返回List操作API
private SetOperations<K, V> setOps;//opsForSet返回Set操作API
private ZSetOperations<K, V> zSetOps;//opsForZset返回Zset操作API
private GeoOperations<K, V> geoOps;
private HyperLogLogOperations<K, V> hllOps;
//注意: opsForHash每次返回新的HashOprerations操作实例
其中各数据类型的操作API见对应的Operations接口定义.
模版方法: RedisTemplate提供Connection, CallBack提供执行逻辑
定义在RedisOperations接口中:
<T> T execute(RedisCallback<T> var1);
<T> T execute(SessionCallback<T> var1);
List<Object> executePipelined(RedisCallback<?> var1);
List<Object> executePipelined(RedisCallback<?> var1, RedisSerializer<?> var2);
List<Object> executePipelined(SessionCallback<?> var1);
List<Object> executePipelined(SessionCallback<?> var1, RedisSerializer<?> var2);
<T> T execute(RedisScript<T> var1, List<K> var2, Object... var3);
RedisCallback基于原生RedisConnection的命令来操作. 支持pipeLine. RedisCallback执行期间使用的是同一个连接操作, 不绑定到线程(意味着无法保证连续两个Callback是同一个的连接), 开启事务执行事务时需要自己执行MULTI/EXE命令
public interface RedisCallback<T> {
T doInRedis(RedisConnection var1) throws DataAccessException;
}
SessionCallback基于RedisOperations的命令来操作. 支持pipeLine. SessionCallback执行期间默认会将Connection绑定到线程, SessionCallback执行完成后会解绑(意味着无法保证连续两个Callback是同一个的连接), 这样执行期间通过RedisConnectionUtils.getConnection
获取连接时可以复用同一个连接, 基于RedisOperations的操作大多是基于RedisCallback的回调来操作, 基本都是通过RedisConnectionUtils.getConnection
复用连接, 开启事务后框架会帮执行MULTI/EXE命令
public interface SessionCallback<T> {
<K, V> T execute(RedisOperations<K, V> var1) throws DataAccessException;
}
这个是redis原本支持的功能, 多个操作时可以打到先发送命令不必等返回最后统一返回的效果. 可以理解为Future一样的效果. pipeLine的前提是同一个连接.
如果是redis集群,执行pipeLine时命令数量不要太多,否则可能导致redisServer关闭了链接导致ConnectionReset异常(建议小于200分页)
如果使用RedisTemplate前都已经将对象转化为String了(一般为JSON格式), 那就只需要将String和byte[]进行转化了. 此时可以使用StringRedisTemplate. 默认调用String.getByte(“UTF-8”)来序列化.
public class StringRedisTemplate extends RedisTemplate<String, String> {
public StringRedisTemplate() {
RedisSerializer<String> stringSerializer = new StringRedisSerializer();
this.setKeySerializer(stringSerializer);
this.setValueSerializer(stringSerializer);
this.setHashKeySerializer(stringSerializer);
this.setHashValueSerializer(stringSerializer);
}
public StringRedisTemplate(RedisConnectionFactory connectionFactory) {
this();
this.setConnectionFactory(connectionFactory);
this.afterPropertiesSet();//使用RedisTemplate,如果没集成spring需要手动调用.这里简化了操作
}
}