Redis默认序列化是
JdkSerializationRedisSerializer
,由此可见
public void afterPropertiesSet() {
super.afterPropertiesSet();
boolean defaultUsed = false;
if (this.defaultSerializer == null) {
this.defaultSerializer = new JdkSerializationRedisSerializer(this.classLoader != null ? this.classLoader : this.getClass().getClassLoader());
}
if (this.enableDefaultSerializer) {
if (this.keySerializer == null) {
this.keySerializer = this.defaultSerializer;
defaultUsed = true;
}
if (this.valueSerializer == null) {
this.valueSerializer = this.defaultSerializer;
defaultUsed = true;
}
if (this.hashKeySerializer == null) {
this.hashKeySerializer = this.defaultSerializer;
defaultUsed = true;
}
if (this.hashValueSerializer == null) {
this.hashValueSerializer = this.defaultSerializer;
defaultUsed = true;
}
}
if (this.enableDefaultSerializer && defaultUsed) {
Assert.notNull(this.defaultSerializer, "default serializer null and not all serializers initialized");
}
if (this.scriptExecutor == null) {
this.scriptExecutor = new DefaultScriptExecutor(this);
}
this.initialized = true;
}
这里因为我们的项目需要更改默认序列策略为Jackson2JsonRedisSerializer
让它序列化为可视化的***json***语句
我们首先定义自己的RedisTemplate
,这里我们不要为了每一个类定义一个序列化器,我们定义一个统一的序列化器所以这里泛型是
,key我们使用StringRedisSerializer,value使用Jackson2JsonRedisSerializer
注释代码为修复反序列化bug的代码
@Bean
public RedisTemplate<String, Object> objectRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
RedisTemplate<String, Object> template = new RedisTemplate();
Jackson2JsonRedisSerializer<Object> jsonSerial = new Jackson2JsonRedisSerializer(Object.class);
// //修复反序列化bug
// ObjectMapper om = new ObjectMapper();
// om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
// jsonSerial.setObjectMapper(om);
template.setDefaultSerializer(jsonSerial);
template.setKeySerializer(RedisSerializer.string());
template.setConnectionFactory(redisConnectionFactory);
template.afterPropertiesSet();
return template;
}
测试代码为
@Test
public void redisSaveObject(){
UserDO ob = new UserDO();
ob.setName("name");
ob.setCity("city");
objectRedisTemplate.opsForValue().set("ob1",ob);
Object ob2 = objectRedisTemplate.opsForValue().get("ob1");
UserDO ob1 = (UserDO)ob2;
System.out.println(ob1);
}
运行结果为
java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.hcy.core.model.UserDO
at com.hcy.core.redistest.RedisTest.redisSaveObject(RedisTest.java:42)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at
很明显是对象强制转换错误
这是因为泛型的原因,redis在序列化时候把他当成Object序列化的,所以这里反序列化为Object是可以的,但是因为这个Object没有类型定义所以无法强转。
解决办法
在RedisTemplate中对序列化器Jackson2JsonRedisSerializer进行修改添加如下代码,上文注释了
//修复反序列化bug
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jsonSerial.setObjectMapper(om);
通过 objectMapper.enableDefaultTyping() 方法设置
即使使用 Object.class 作为 jcom.fasterxml.jackson.databind.JavaType 也可以实现相应类型的序列化和反序列化
好处:只定义一个序列化器就可以了(通用)
这里我们也做个测试,分别用不修改ObjectMapper的和修改了ObjectMapper的看看生成的value有啥子不一样
ob1: [“com.hcy.core.model.UserDO”,{“userid”:null,“openid”:null,“name”:“name”,“city”:“city”}]
ob2: {“userid”:null,“openid”:null,“name”:“name”,“city”:“city”}
这里结果很明显啦!!!
希望对大家有帮助!!!