Redis - Spring Boot Redis 使用 msgpack 作为序列化
Posted Lux_Sun
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis - Spring Boot Redis 使用 msgpack 作为序列化相关的知识,希望对你有一定的参考价值。
首先引入 msgpack 所需要的包
<dependency>
<groupId>org.msgpack</groupId>
<artifactId>msgpack-core</artifactId>
<version>0.8.13</version>
</dependency>
<dependency>
<groupId>org.msgpack</groupId>
<artifactId>jackson-dataformat-msgpack</artifactId>
<version>0.8.13</version>
</dependency>
- 版本一定要对齐,之前 jackson-dataformat-msgpack 版本太低导致无法使用。
RedisConfig.java(Spring Boot Redis 配置类)
import com.fasterxml.jackson.databind.ObjectMapper;
import org.msgpack.jackson.dataformat.MessagePackFactory;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.*;
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
/**
* 设置spring redis data 序列化模板
* @param factory
* @return
*/
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory factory) {
StringRedisTemplate template = new StringRedisTemplate(factory);
ObjectMapper mapper = new ObjectMapper(new MessagePackFactory());
Jackson2JsonRedisSerializer Jackson2Serializer = new Jackson2JsonRedisSerializer(Object.class);
Jackson2Serializer.setObjectMapper(mapper);
RedisSerializer redisSerializer= Jackson2Serializer;
template.setValueSerializer(redisSerializer);
template.setKeySerializer(new StringRedisSerializer());
return template;
}
/**
* 整合spring cache
* 设置@cacheable 序列化方式
* @return
*/
@Bean
public RedisCacheConfiguration redisCacheConfiguration() {
RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig();
configuration = configuration.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericMsgpackRedisSerializer()));
return configuration;
}
}
GenericMsgpackRedisSerializer.java(Spring Cache msgpack 序列化类)
import com.fasterxml.jackson.annotation.JsonTypeInfo.As;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ObjectMapper.DefaultTyping;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import java.io.IOException;
import org.msgpack.core.annotations.Nullable;
import org.msgpack.jackson.dataformat.MessagePackFactory;
import org.springframework.cache.support.NullValue;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
public class GenericMsgpackRedisSerializer implements RedisSerializer<Object> {
static final byte[] EMPTY_ARRAY = new byte[0];
private final ObjectMapper mapper;
public GenericMsgpackRedisSerializer() {
this.mapper = new ObjectMapper(new MessagePackFactory());
this.mapper.registerModule((new SimpleModule()).addSerializer(new GenericMsgpackRedisSerializer.NullValueSerializer(null)));
this.mapper.enableDefaultTyping(DefaultTyping.NON_FINAL, As.PROPERTY);
}
@Override
public byte[] serialize(@Nullable Object source) throws SerializationException {
if (source == null) {
return EMPTY_ARRAY;
} else {
try {
return this.mapper.writeValueAsBytes(source);
} catch (JsonProcessingException var3) {
throw new SerializationException("Could not write JSON: " + var3.getMessage(), var3);
}
}
}
@Override
public Object deserialize(@Nullable byte[] source) throws SerializationException {
return this.deserialize(source, Object.class);
}
@Nullable
public <T> T deserialize(@Nullable byte[] source, Class<T> type) throws SerializationException {
Assert.notNull(type, "Deserialization type must not be null! Pleaes provide Object.class to make use of Jackson2 default typing.");
if (source == null || source.length == 0) {
return null;
} else {
try {
return this.mapper.readValue(source, type);
} catch (Exception var4) {
throw new SerializationException("Could not read JSON: " + var4.getMessage(), var4);
}
}
}
private class NullValueSerializer extends StdSerializer<NullValue> {
private static final long serialVersionUID = 2199052150128658111L;
private final String classIdentifier;
NullValueSerializer(@Nullable String classIdentifier) {
super(NullValue.class);
this.classIdentifier = StringUtils.hasText(classIdentifier) ? classIdentifier : "@class";
}
@Override
public void serialize(NullValue value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
jgen.writeStartObject();
jgen.writeStringField(this.classIdentifier, NullValue.class.getName());
jgen.writeEndObject();
}
}
}
RedisCacheRedisUtils.java(序列化工具类)
import java.util.Set;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.msgpack.jackson.dataformat.MessagePackFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* @description: redis缓存工具类
* @version:1.0
*/
@Component
public class RedisCacheUtils {
private static Logger logger = LoggerFactory.getLogger(RedisCacheUtils.class);
private final static Boolean REDIS_ENABLE = true;
@Resource
private RedisTemplate redisTemplate;
@Resource
RedisConnectionFactory redisConnectionFactory;
public RedisTemplate getRedisTemplate() {
return redisTemplate;
}
public void setRedisTemplate(RedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
}
public RedisCacheUtils(RedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
}
/**
* 缓存基本的对象,Integer、String、实体类等
*
* @param key 缓存的键值
* @param value 缓存的值
* @return缓存的对象
*/
public boolean setCacheObject(String key, Object value) {
if (!REDIS_ENABLE) {
return false;
}
logger.debug("存入缓存 key:" + key);
try {
ValueOperations<String, Object> operation = redisTemplate.opsForValue();
operation.set(key, value);
return true;
} catch (Exception ex) {
logger.error(ex.getMessage());
return false;
}
}
/**
* 根据pattern匹配清除缓存
* @param pattern
*/
public void clear(String pattern) {
if (!REDIS_ENABLE) {
return;
}
logger.debug("清除缓存 pattern:" + pattern);
try {
ValueOperations<String, Object> valueOper = redisTemplate.opsForValue();
RedisOperations<String, Object> redisOperations = valueOper.getOperations();
redisOperations.keys(pattern);
Set<String> keys = redisOperations.keys(pattern);
for (String key : keys) {
redisOperations.delete(key);
}
} catch (Exception ex) {
logger.error(ex.getMessage());
return;
}
}
/**
* 根据key清除缓存
* @param key
*/
public void delete(String key) {
if (!REDIS_ENABLE) {
return;
}
logger.debug("删除缓存 key:" + key);
try {
ValueOperations<String, Object> valueOper = redisTemplate.opsForValue();
RedisOperations<String, Object> redisOperations = valueOper.getOperations();
redisOperations.delete(key);
} catch (Exception ex) {
logger.error(ex.getMessage());
return;
}
}
/**
* 获得缓存的基本对象。
* @param key 缓存键值
* @return 缓存键值对应的数据
*
*/
public Object getCacheObject(String key) {
if (!REDIS_ENABLE) {
return null;
}
logger.debug("获取缓存 key:" + key);
try {
ValueOperations<String, Object> operation = redisTemplate.opsForValue();
return operation.get(key);
} catch (Exception ex) {
logger.error(ex.getMessage());
return null;
}
}
/**
* 获得缓存的基本对象。
* @param key 缓存键值
* @return 缓存键值对应的数据
*
*/
public <T> T getCacheObject(String key, Class<T> clazz) {
if (!REDIS_ENABLE) {
return null;
}
logger.debug("获取缓存 key:" + key);
RedisTemplate template = new StringRedisTemplate(redisConnectionFactory);
Jackson2JsonRedisSerializer Jackson2Serializer = new Jackson2JsonRedisSerializer(clazz);
Jackson2Serializer.setObjectMapper(new ObjectMapper(new MessagePackFactory()));
RedisSerializer redisSerializer = Jackson2Serializer;
template.setValueSerializer(redisSerializer);
try {
ValueOperations<String, T> operation = template.opsForValue();
return (T) operation.get(key);
} catch (Exception ex) {
logger.error(ex.getMessage());
return null;
}
}
}
启动 Spring Boot 开始测试
@RestController
public class TestController {
@Resource
RedisCacheUtils redisCacheUtils;
@GetMapping("/getCache")
public Object getCache() {
List<String> result = redisCacheUtils.getCacheObject("list_cache", new ArrayList<HashMap<String, String>>().getClass());
return result;
}
@GetMapping("/setCache")
public Object setCache() {
List<Map> list = new ArrayList<>();
for (int i = 0; i < 100; i++) {
Map map = new HashMap<String, String>();
map.put("id", i);
map.put("name", "index=" + i);
list.add(map);
}
return redisCacheUtils.setCacheObject("list_cache", list);
}
}
- 缓存结果(msgpack:大小1893字节)
- 缓存结果(fastjson:大小2781字节)
- 速度比较(10000条数据测试,非专业测试结果,仅供参考)
排名结果:msgpack > fastJson > jackson
以上是关于Redis - Spring Boot Redis 使用 msgpack 作为序列化的主要内容,如果未能解决你的问题,请参考以下文章
spring boot:Spring Boot中Redis的使用
Spring boot在Spring boot中Redis的使用