spring redisson 使用样例
目标
- 尽量避免重复造轮子
- 与spring data保持数据兼容
- 配置信息使用spring通用的配置机制
redisson spring starter
redisson提供了对spring的支持,url地址:https://github.com/redisson/redisson/tree/master/redisson-spring-boot-starter#spring-boot-starter 。此starter提供下列spring bean:
• RedissonClient
• RedissonRxClient
• RedissonReactiveClient
• RedisTemlate
• ReactiveRedisTemplate
pom文件
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.15.5</version>
<exclusions>
<exclusion>
<groupId>org.redisson</groupId>
<artifactId>redission-spring-data-24</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-data-23</artifactId>
<version>3.15.5</version>
</dependency>
引入此starter,可以使用redisson的方式使用redis,也可以使用spring-boot-starter-data-redis中RedisTemplate方式使用redis。
序列化/反序列化
无论是redisson-spring-boot-starter还是spring-boot-starter-data-redis,都提供了RedisTemplate和StringRedisTemplate。
但是多数场景下,redis中的key是String,value是Object,所以增加RedisTemplate类型的bean。
在默认情况下redisson和redisTemplate的序列化/反序列化方式不同,导致不同redis客户端写入的数据只能使用各自的客户端读取,甚至在redis-cli中也无法手工维护。
所以value需要保存为json格式,json格式的序列化/反序列化使用jackson实现。
使用RedisTemplate好处是,RedisTemplate已经提我们反序列化缓存为正确的bean,不需要手工再次把String转换为bean。
可以这样使用:
WarehouseInfo warehouseJson = (WarehouseInfo)redisTemplate.opsForValue().get("redisson:redis:warehouse:json");
redisson的json序列化通过配置编码方式实现。把编码设置为org.redisson.codec.JsonJacksonCodec。RedisTemplate需要增加bean定义,并配置序列化/反序列化配置。
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(
Object.class);
ObjectMapper om = new ObjectMapper();
om.setSerializationInclusion(JsonInclude.Include.NON_NULL);
om.enable(JsonGenerator.Feature.WRITE_BIGDECIMAL_AS_PLAIN);
// 指定要序列化的域,field、get和set,以及修饰符范围,ANY包括private和public
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// 调用此方法的用途是生成的json包括类名,DefaultTyping.EVERYTHING的意思是:所有的类型(包括引用类型、原生类型)类信息都会写入json中
// JsonTypeInfo.As.PROPERTY:将包含@class属性,作为序列化的一个属性,值就是完全限定名类型。
// {"@class":"com.haole.redissionspring.dto.WarehouseInfo","warehouseId":["java.lang.Long",100000000],"warehouseName":"青岛中心仓"}
om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.EVERYTHING,
JsonTypeInfo.As.PROPERTY);
jackson2JsonRedisSerializer.setObjectMapper(om);
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
redisTemplate.setKeySerializer(stringRedisSerializer);
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setHashKeySerializer(stringRedisSerializer);
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
这样就实现了redisson和redisTemplate数据兼容,并且在redis-cli中也可以手工维护。
根据配置不同,有多种json格式,如果出现redisson或者RedisTemplate无法处理的json,可以使用StringRedisTemplate,得到String格式的缓存,自己手工想法解析。
————————————————
配置文件
spring:
application:
name: redission-spring
redis:
redisson:
file: classpath:redisson.yml
redisson.yml内容是redis集群模式的样例
clusterServersConfig:
idleConnectionTimeout: 10000
connectTimeout: 10000
timeout: 3000
retryAttempts: 3
retryInterval: 1500
failedSlaveReconnectionInterval: 3000
failedSlaveCheckInterval: 60000
password: null
subscriptionsPerConnection: 5
clientName: null
loadBalancer: !<org.redisson.connection.balancer.RoundRobinLoadBalancer> { }
subscriptionConnectionMinimumIdleSize: 1
subscriptionConnectionPoolSize: 50
slaveConnectionMinimumIdleSize: 24
slaveConnectionPoolSize: 64
masterConnectionMinimumIdleSize: 32
masterConnectionPoolSize: 64
readMode: "SLAVE"
subscriptionMode: "SLAVE"
nodeAddresses:
- "redis://127.0.0.1:6379"
- "redis://127.0.0.1:6380"
scanInterval: 1000
pingConnectionInterval: 0
keepAlive: false
tcpNoDelay: false
threads: 16
nettyThreads: 32
codec: !<org.redisson.codec.JsonJacksonCodec> { }
transportMode: "NIO"
其中codec指定了json格式的编码方式。redisson这种使用文件的配置方式无法使用spring cloud的配置中心,因为从源码来看,是从工程的本地读取文件。针对这种情况,可以config方式,但是config方式也有一个问题,因为整个config是字符串。
RedisTemplate使用
// 字符串缓存
redisTemplate.opsForValue().set("redisson:redis:string", "test string new");
// bean缓存
WarehouseInfo warehouse = new WarehouseInfo();
warehouse.setWarehouseId(100000000L);
warehouse.setWarehouseName("青岛中心仓");
redisTemplate.opsForValue().set("redisson:redis:warehouse", warehouse);
RedissonClient使用
// 字符串缓存
RBucket<String> bucket = redissonClient.getBucket("redisson:redisson:string");
bucket.set("redisson string");
// bean缓存
WarehouseInfo warehouse = new WarehouseInfo();
warehouse.setWarehouseId(100000079L);
warehouse.setWarehouseName("洛阳中心仓");
RBucket<WarehouseInfo> bucket1 = redissonClient.getBucket("redisson:redisson:warehouse");
bucket1.set(warehouse);
// get redisTemplate 写入在缓存
RBucket<WarehouseInfo> bucket2 = redissonClient.getBucket("redisson:redis:warehouse");
WarehouseInfo warehouseInfo = bucket2.get();
跨工程使用
采用上述编码方式,如果缓存只在一个工程内使用,序列化/反序列化只有一种,无论采用何种方式,都没有问题。但是,如果跨不同工程使用同一个缓存,
需要序列化/反序列化方式一样,并且也需要全类名也必须一样,但是这点很难做到。解决这个问题的一个思路,编码使用org.redisson.client.codec.StringCodec,
写入缓存之前先手工序列化为json,读取缓存后,手工反序列化json。这样也可以使用StringRedisTemplate。