我一直在尝试更改spring-boot redis缓存的默认序列化程序,因为我想从Default更改为Jackson2Json实现之一。 Jackson2Json库中有两种实现,其中之一是:GenericJackson2JsonRedisSerializer,我可以在以下bean实例中使用它:
@Bean
@Primary
public RedisCacheConfiguration defaultCacheConfig(ObjectMapper objectMapper) {
return RedisCacheConfiguration.defaultCacheConfig()
.serializeKeysWith(
SerializationPair.fromSerializer(
new StringRedisSerializer()
)
)
.serializeValuesWith(
SerializationPair.fromSerializer(
new GenericJackson2JsonRedisSerializer(objectMapper)
)
)
.prefixKeysWith("");
}
当我使用此序列化程序时,序列化工作正常,所有内容都存储在redis服务器上,但是当尝试对存储在redis服务器上的JSON进行反序列化时,会收到以下异常:
java.util.LinkedHashMap cannot be cast to tutorial.Person with root cause
java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to tutorial.Person
缓存的使用方式如下:
@Cacheable(cacheNames = "person", key = "'person:'.concat(#post.id)")
public Person findPostAuthor(Post post){
}
序列化器不知道如何从LinkedHashMap转换为Person,我如何告诉他该怎么做?
我尝试使用的另一个序列化器是Jackson2JsonRedisSerializer:
@Bean
@Primary
public RedisCacheConfiguration defaultCacheConfig(ObjectMapper objectMapper) {
Jackson2JsonRedisSerializer<Person> serializer = new Jackson2JsonRedisSerializer<>(Person.class);
serializer.setObjectMapper(objectMapper);
return RedisCacheConfiguration.defaultCacheConfig()
.serializeKeysWith(
SerializationPair.fromSerializer(
new StringRedisSerializer()
)
)
.serializeValuesWith(
SerializationPair.fromSerializer(
serializer
)
)
.prefixKeysWith("");
}
这样,我将必须为Redis缓存上保存的每个对象声明一个bean,但是我可以正确地序列化/反序列化。
当我直接在Redis缓存上插入JSON时,我无法使用此序列化器反序列化该序列化器,序列化器只给我一个Person对象,该对象具有空名称,电子邮件和id属性。有办法解决这个问题吗?
如果有办法改善我的问题,请告诉我。
答案 0 :(得分:2)
GenericJackson2JsonRedisSerializer
假设杰克逊的default typing。使用GenericJackson2JsonRedisSerializer
实例创建ObjectMapper
时,请确保配置默认类型(enableDefaultTyping(…)
)。
默认类型输入最适合非最终类型,并且在所有JSON有效负载中都要求该类型具有一致的属性名称,以便Jackson可以识别要反序列化的适当类型。
默认类型使用动态类型标记,如果您的数据源(Redis实例)不受完全信任,那么这可能会成为安全隐患。
Jackson2JsonRedisSerializer
被固定到特定类型,并消除了动态打字风险。
答案 1 :(得分:1)
你可以使用 Spring Data Redis
添加依赖项:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
启用缓存和使用 Jackson2JsonRedisSerializer
package com.redis.demo.redisdemo.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
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.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@EnableCaching
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
@Autowired
private RedisConnectionFactory redisConnectionFactory;
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
serializer.setObjectMapper(objectMapper);
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(serializer);
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(serializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
@Bean
public RedisCacheManager redisCacheManager(RedisTemplate redisTemplate) {
RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisTemplate.getConnectionFactory());
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(redisTemplate.getValueSerializer()));
return new RedisCacheManager(redisCacheWriter, redisCacheConfiguration);
}
}
在方法中添加Cacheable注解缓存在redis中
@Cacheable(value = "employee", key = "#id")
public Employee getEmployee(Integer id) {
log.info("Get Employee By Id: {}", id);
Optional<Employee> employeeOptional = employeeRepository.findById(id);
if (!employeeOptional.isPresent()) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Id Not foud");
}
return employeeOptional.get();
}
答案 2 :(得分:0)
我知道这个问题已经很久了,但可能有人仍然需要答案。
我遇到了同样的问题,我使用 JdkSerializationRedisSerializer
而不是 GenericJackson2JsonRedisSerializer
解决了它。
我的 RedisCacheConfiguration
bean 看起来像:
return RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofHours("your-long-value"))
.serializeKeysWith(SerializationPair.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(SerializationPair.fromSerializer(new JdkSerializationRedisSerializer()));