本文主要讲redisTempalte的几种常用的序列化方式
package sca.pro.core.redis.configuration;
import cn.hutool.core.convert.Convert;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisPassword;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.time.Duration;
@Configuration
@EnableCaching
public class RedisTemplateConfig {
@Value("${spring.redis.database}")
private int database;
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.password}")
private String password;
@Value("${spring.redis.port}")
private String port;
@Value("${spring.redis.timeout}")
private String timeout;
@Value("${spring.redis.lettuce.pool.max-idle}")
private String maxIdle;
@Value("${spring.redis.lettuce.pool.min-idle}")
private String minIdle;
@Value("${spring.redis.lettuce.pool.max-active}")
private String maxActive;
@Value("${spring.redis.lettuce.pool.max-wait}")
private String maxWait;
@Bean
public LettuceConnectionFactory lettuceConnectionFactory() {
GenericObjectPoolConfig genericObjectPoolConfig = new GenericObjectPoolConfig();
genericObjectPoolConfig.setMaxIdle(Convert.toInt(maxIdle));
genericObjectPoolConfig.setMinIdle(Convert.toInt(minIdle));
genericObjectPoolConfig.setMaxTotal(Convert.toInt(maxActive));
genericObjectPoolConfig.setMaxWaitMillis(Convert.toLong(maxWait));
genericObjectPoolConfig.setTimeBetweenEvictionRunsMillis(100);
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
redisStandaloneConfiguration.setDatabase(database);
redisStandaloneConfiguration.setHostName(host);
redisStandaloneConfiguration.setPort(Convert.toInt(port));
redisStandaloneConfiguration.setPassword(RedisPassword.of(password));
LettuceClientConfiguration clientConfig = LettucePoolingClientConfiguration.builder()
.commandTimeout(Duration.ofMillis(Convert.toLong(timeout)))
.poolConfig(genericObjectPoolConfig)
.build();
LettuceConnectionFactory factory = new LettuceConnectionFactory(redisStandaloneConfiguration, clientConfig);
return factory;
}
@Bean
public RedisTemplate redisTemplate(LettuceConnectionFactory factory) {
// 配置redisTemplate
RedisTemplate redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(factory);
redisTemplate.setKeySerializer(new StringRedisSerializer());//key序列化
redisTemplate.setValueSerializer(new StringRedisSerializer());//value序列化
//设置hash的key的序列化方式
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
//设置hash的value的序列化方式
redisTemplate.setHashValueSerializer(new StringRedisSerializer());
redisTemplate.afterPropertiesSet();//使上面参数生效
return redisTemplate;
}
}
其实如果key和value都是string,那就等效于我们直接引入StringRedisTemplate
pom
com.google.guava
guava
18.0
org.springframework.boot
spring-boot-starter-data-redis
com.dyuproject.protostuff
protostuff-core
1.1.3
com.dyuproject.protostuff
protostuff-runtime
1.1.3
2.自己编写序列化工具
@Slf4j
public class ProtoStuffUtil {
/**
* 序列化对象
*
* @param obj
* @return
*/
public static byte[] serialize(T obj) {
if (obj == null) {
log.error("Failed to serializer, obj is null");
throw new RuntimeException("Failed to serializer");
}
@SuppressWarnings("unchecked") Schema schema = (Schema) RuntimeSchema.getSchema(obj.getClass());
LinkedBuffer buffer = LinkedBuffer.allocate(1024 * 1024);
byte[] protoStuff;
try {
protoStuff = ProtostuffIOUtil.toByteArray(obj, schema, buffer);
} catch (Exception e) {
log.error("Failed to serializer, obj:{}", obj, e);
throw new RuntimeException("Failed to serializer");
} finally {
buffer.clear();
}
return protoStuff;
}
/**
* 反序列化对象
*
* @param paramArrayOfByte
* @param targetClass
* @return
*/
public static T deserialize(byte[] paramArrayOfByte, Class targetClass) {
if (paramArrayOfByte == null || paramArrayOfByte.length == 0) {
log.error("Failed to deserialize, byte is empty");
throw new RuntimeException("Failed to deserialize");
}
T instance;
try {
instance = targetClass.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
log.error("Failed to deserialize", e);
throw new RuntimeException("Failed to deserialize");
}
Schema schema = RuntimeSchema.getSchema(targetClass);
ProtostuffIOUtil.mergeFrom(paramArrayOfByte, instance, schema);
return instance;
}
/**
* 序列化列表
*
* @param objList
* @return
*/
public static byte[] serializeList(List objList) {
if (objList == null || objList.isEmpty()) {
log.error("Failed to serializer, objList is empty");
throw new RuntimeException("Failed to serializer");
}
@SuppressWarnings("unchecked") Schema schema =
(Schema) RuntimeSchema.getSchema(objList.get(0).getClass());
LinkedBuffer buffer = LinkedBuffer.allocate(1024 * 1024);
byte[] protoStuff;
ByteArrayOutputStream bos = null;
try {
bos = new ByteArrayOutputStream();
ProtostuffIOUtil.writeListTo(bos, objList, schema, buffer);
protoStuff = bos.toByteArray();
} catch (Exception e) {
log.error("Failed to serializer, obj list:{}", objList, e);
throw new RuntimeException("Failed to serializer");
} finally {
buffer.clear();
try {
if (bos != null) {
bos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return protoStuff;
}
/**
* 反序列化列表
*
* @param paramArrayOfByte
* @param targetClass
* @return
*/
public static List deserializeList(byte[] paramArrayOfByte, Class targetClass) {
if (paramArrayOfByte == null || paramArrayOfByte.length == 0) {
log.error("Failed to deserialize, byte is empty");
throw new RuntimeException("Failed to deserialize");
}
Schema schema = RuntimeSchema.getSchema(targetClass);
List result;
try {
result = ProtostuffIOUtil.parseListFrom(new ByteArrayInputStream(paramArrayOfByte), schema);
} catch (IOException e) {
log.error("Failed to deserialize", e);
throw new RuntimeException("Failed to deserialize");
}
return result;
}
}
3.RedisTemplate的工具类方法
@Component
public class RedisClient {
private final RedisTemplate redisTemplate;
@Autowired
public RedisClient(RedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
}
/**
* get cache
*
* @param field
* @param targetClass
* @param
* @return
*/
public T get(final String field, Class targetClass) {
byte[] result = redisTemplate.execute((RedisCallback) connection -> connection.get(field.getBytes()));
if (result == null) {
return null;
}
return ProtoStuffUtil.deserialize(result, targetClass);
}
/**
* put cache
*
* @param field
* @param obj
* @param
* @return
*/
public void set(String field, T obj) {
final byte[] value = ProtoStuffUtil.serialize(obj);
redisTemplate.execute((RedisCallback) connection -> {
connection.set(field.getBytes(), value);
return null;
});
}
/**
* put cache with expire time
*
* @param field
* @param obj
* @param expireTime 单位: s
* @param
*/
public void setWithExpire(String field, T obj, final long expireTime) {
final byte[] value = ProtoStuffUtil.serialize(obj);
redisTemplate.execute((RedisCallback) connection -> {
connection.setEx(field.getBytes(), expireTime, value);
return null;
});
}
/**
* get list cache
*
* @param field
* @param targetClass
* @param
* @return
*/
public List getList(final String field, Class targetClass) {
byte[] result = redisTemplate.execute((RedisCallback) connection -> connection.get(field.getBytes()));
if (result == null) {
return null;
}
return ProtoStuffUtil.deserializeList(result, targetClass);
}
/**
* put list cache
*
* @param field
* @param objList
* @param
* @return
*/
public void setList(String field, List objList) {
final byte[] value = ProtoStuffUtil.serializeList(objList);
redisTemplate.execute((RedisCallback) connection -> {
connection.set(field.getBytes(), value);
return null;
});
}
/**
* put list cache with expire time
*
* @param field
* @param objList
* @param expireTime
* @param
* @return
*/
public void setListWithExpire(String field, List objList, final long expireTime) {
final byte[] value = ProtoStuffUtil.serializeList(objList);
redisTemplate.execute((RedisCallback) connection -> {
connection.setEx(field.getBytes(), expireTime, value);
return null;
});
}
/**
* get h cache
*
* @param key
* @param field
* @param targetClass
* @param
* @return
*/
public T hGet(final String key, final String field, Class targetClass) {
byte[] result = redisTemplate
.execute((RedisCallback) connection -> connection.hGet(key.getBytes(), field.getBytes()));
if (result == null) {
return null;
}
return ProtoStuffUtil.deserialize(result, targetClass);
}
/**
* put hash cache
*
* @param key
* @param field
* @param obj
* @param
* @return
*/
public boolean hSet(String key, String field, T obj) {
final byte[] value = ProtoStuffUtil.serialize(obj);
return redisTemplate.execute(
(RedisCallback) connection -> connection.hSet(key.getBytes(), field.getBytes(), value));
}
/**
* put hash cache
*
* @param key
* @param field
* @param obj
* @param
*/
public void hSetWithExpire(String key, String field, T obj, long expireTime) {
final byte[] value = ProtoStuffUtil.serialize(obj);
redisTemplate.execute((RedisCallback) connection -> {
connection.hSet(key.getBytes(), field.getBytes(), value);
connection.expire(key.getBytes(), expireTime);
return null;
});
}
/**
* get list cache
*
* @param key
* @param field
* @param targetClass
* @param
* @return
*/
public List hGetList(final String key, final String field, Class targetClass) {
byte[] result = redisTemplate
.execute((RedisCallback) connection -> connection.hGet(key.getBytes(), field.getBytes()));
if (result == null) {
return null;
}
return ProtoStuffUtil.deserializeList(result, targetClass);
}
/**
* put list cache
*
* @param key
* @param field
* @param objList
* @param
* @return
*/
public boolean hSetList(String key, String field, List objList) {
final byte[] value = ProtoStuffUtil.serializeList(objList);
return redisTemplate.execute(
(RedisCallback) connection -> connection.hSet(key.getBytes(), field.getBytes(), value));
}
/**
* get cache by keys
*
* @param key
* @param fields
* @param targetClass
* @param
* @return
*/
public Map hMGet(String key, Collection fields, Class targetClass) {
List byteFields = fields.stream().map(String::getBytes).collect(Collectors.toList());
byte[][] queryFields = new byte[byteFields.size()][];
byteFields.toArray(queryFields);
List cache = redisTemplate
.execute((RedisCallback>) connection -> connection.hMGet(key.getBytes(), queryFields));
Map results = new HashMap<>(16);
Iterator it = fields.iterator();
int index = 0;
while (it.hasNext()) {
String k = it.next();
if (cache.get(index) == null) {
index++;
continue;
}
results.put(k, ProtoStuffUtil.deserialize(cache.get(index), targetClass));
index++;
}
return results;
}
/**
* set cache by keys
*
* @param field
* @param values
* @param
*/
public void hMSet(String field, Map values) {
Map byteValues = new HashMap<>(16);
for (Map.Entry value : values.entrySet()) {
byteValues.put(value.getKey().getBytes(), ProtoStuffUtil.serialize(value.getValue()));
}
redisTemplate.execute((RedisCallback) connection -> {
connection.hMSet(field.getBytes(), byteValues);
return null;
});
}
/**
* get caches in hash
*
* @param key
* @param targetClass
* @param
* @return
*/
public Map hGetAll(String key, Class targetClass) {
Map records = redisTemplate
.execute((RedisCallback
@Bean
@ConditionalOnMissingBean(name = "redisTemplate")
public RedisTemplate redisTemplate(RedisConnectionFactory factory){
RedisTemplate template = new RedisTemplate<>();
template.setConnectionFactory(factory);
//String的序列化方式
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// 使用GenericJackson2JsonRedisSerializer 替换默认序列化(默认采用的是JDK序列化)
GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
//key序列化方式采用String类型
template.setKeySerializer(stringRedisSerializer);
//value序列化方式采用jackson类型
template.setValueSerializer(genericJackson2JsonRedisSerializer);
//hash的key序列化方式也是采用String类型
template.setHashKeySerializer(stringRedisSerializer);
//hash的value也是采用jackson类型
template.setHashValueSerializer(genericJackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}
运行下边的测试类测试GenericJackson2JsonRedisSerializer,发现不管是字符串还是对象还是数组都很通用
@Test
void redisTemplateSerializeTest() {
String redisTemplateStringKey = "redisTemplateStringKey";
String redisTemplateUserObjectKey = "redisTemplateUserObjectKey";
String redisTemplateUserArrayObjectKey = "redisTemplateUserArrayObjectKey";
String redisTemplateJSONObjectKey = "redisTemplateJSONObjectKey";
String redisTemplateJSONArrayKey = "redisTemplateJSONArrayKey";
//序列化String类型和反序列化String类型
redisTemplate.opsForValue().set(redisTemplateStringKey, "austin");
String austin = (String) redisTemplate.opsForValue().get(redisTemplateStringKey);
System.out.println("stringGet: " + austin);
//序列化Object对象类型和反序列化Object对象类型 (User对象)
User user = new User("123", "austin", 25);
redisTemplate.opsForValue().set(redisTemplateUserObjectKey, user);
User userGet = (User) redisTemplate.opsForValue().get(redisTemplateUserObjectKey);
System.out.println("userGet: " + userGet);
//序列化Object对象数组类型和反序列化Object对象数组类型 (User[]对象数组)
User user1 = new User("1", "austin1", 25);
User user2 = new User("2", "austin2", 25);
User[] userArray = new User[]{user1, user2};
redisTemplate.opsForValue().set(redisTemplateUserArrayObjectKey, userArray);
User[] userArrayGet = (User[]) redisTemplate.opsForValue().get(redisTemplateUserArrayObjectKey);
System.out.println("userArrayGet: " + userArrayGet);
//序列化JSONObject对象类型和反序列化JSONObject对象类型
JSONObject jsonObject = new JSONObject();
jsonObject.put("id", "123");
jsonObject.put("name", "austin");
jsonObject.put("age", 25);
redisTemplate.opsForValue().set(redisTemplateJSONObjectKey, jsonObject);
JSONObject jsonObjectGet = (JSONObject) redisTemplate.opsForValue().get(redisTemplateJSONObjectKey);
System.out.println("jsonObjectGet: " + jsonObjectGet);
//序列化JSONArray对象类型和反序列化JSONArray对象类型
JSONArray jsonArray = new JSONArray();
JSONObject jsonObject1 = new JSONObject();
jsonObject1.put("id", "1");
jsonObject1.put("name", "austin1");
jsonObject1.put("age", 25);
JSONObject jsonObject2 = new JSONObject();
jsonObject2.put("id", "1");
jsonObject2.put("name", "austin2");
jsonObject2.put("age", 25);
jsonArray.add(jsonObject1);
jsonArray.add(jsonObject2);
redisTemplate.opsForValue().set(redisTemplateJSONArrayKey, jsonArray);
JSONArray jsonArrayGet = (JSONArray) redisTemplate.opsForValue().get(redisTemplateJSONArrayKey);
System.out.println("jsonArrayGet: " + jsonArrayGet);
}
key- value :
字符串类型
Key: redisTemplateStringKey
Value: "austin"
对象类型
Key: redisTemplateUserObjectKey
Value:
{
"@class": "com.example.jedisserializefrombytestojson.User",
"id": "123",
"name": "austin",
"age": 25
}
对象数组类型
Key: redisTemplateUserArrayObjectKey
Value:
[
"[Lcom.example.jedisserializefrombytestojson.User;",
[
{
"@class": "com.example.jedisserializefrombytestojson.User",
"id": "1",
"name": "austin1",
"age": 25
},
{
"@class": "com.example.jedisserializefrombytestojson.User",
"id": "2",
"name": "austin2",
"age": 25
}
]
]
JSONObject类型
Key: redisTemplateJSONObjectKey
Value:
{
"@class": "com.alibaba.fastjson.JSONObject",
"name": "austin",
"id": "123",
"age": 25
}
JSONArray类型
Key: redisTemplateJSONArrayKey
Value:
[
"com.alibaba.fastjson.JSONArray",
[
{
"@class": "com.alibaba.fastjson.JSONObject",
"name": "austin1",
"id": "1",
"age": 25
},
{
"@class": "com.alibaba.fastjson.JSONObject",
"name": "austin2",
"id": "1",
"age": 25
}
]
]