如何配置RedisTemplate:ObjectNode&ArrayNode用Jackson序列化器,其余用Jdk序列化器?
动态选择序列化器:针对ObjectNode/ArrayNode用Jackson,其余用JDK序列化
刚好之前碰到过类似的需求,其实可以通过自定义RedisSerializer来完美解决——核心就是在序列化/反序列化时判断目标对象的类型,动态分发到对应的序列化器处理。下面是具体的实现步骤和代码示例:
第一步:实现自定义混合序列化器
我们需要创建一个实现RedisSerializer<Object>的自定义类,内部封装两个序列化器实例:GenericJackson2JsonRedisSerializer专门处理Jackson的ObjectNode和ArrayNode类型,JdkSerializationRedisSerializer处理其他所有Java对象。
重点要注意反序列化的逻辑:因为字节数组本身不带类型信息,所以我们需要在序列化时给数据加一个类型标识位,这样反序列化时才能知道该用哪个序列化器解析。
import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer; import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.data.redis.serializer.SerializationException; public class HybridRedisSerializer implements RedisSerializer<Object> { // 初始化两个序列化器实例 private final GenericJackson2JsonRedisSerializer jacksonSerializer = new GenericJackson2JsonRedisSerializer(); private final JdkSerializationRedisSerializer jdkSerializer = new JdkSerializationRedisSerializer(); @Override public byte[] serialize(Object obj) throws SerializationException { if (obj == null) { return new byte[0]; } // 给不同类型的序列化结果添加标识位 byte flag; byte[] data; if (obj instanceof ObjectNode || obj instanceof ArrayNode) { data = jacksonSerializer.serialize(obj); flag = 1; // 用1标记Jackson序列化的数据 } else { data = jdkSerializer.serialize(obj); flag = 0; // 用0标记JDK序列化的数据 } // 拼接标识位和实际数据 byte[] result = new byte[data.length + 1]; result[0] = flag; System.arraycopy(data, 0, result, 1, data.length); return result; } @Override public Object deserialize(byte[] bytes) throws SerializationException { if (bytes == null || bytes.length == 0) { return null; } // 先读取标识位,判断用哪个序列化器反序列化 byte flag = bytes[0]; byte[] data = new byte[bytes.length - 1]; System.arraycopy(bytes, 1, data, 0, data.length); if (flag == 1) { return jacksonSerializer.deserialize(data); } else { return jdkSerializer.deserialize(data); } } }
第二步:配置RedisTemplate使用自定义序列化器
在Spring的配置类中,把我们的自定义序列化器设置给RedisTemplate的value(或hashValue)序列化器即可。如果key不需要特殊处理,用StringRedisSerializer就足够了。
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.StringRedisSerializer; @Configuration public class RedisConfig { @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) { RedisTemplate<String, Object> template = new RedisTemplate<>(); template.setConnectionFactory(connectionFactory); HybridRedisSerializer hybridSerializer = new HybridRedisSerializer(); // 设置value和hashValue的序列化器为自定义混合序列化器 template.setValueSerializer(hybridSerializer); template.setHashValueSerializer(hybridSerializer); // key使用字符串序列化器,避免乱码 template.setKeySerializer(new StringRedisSerializer()); template.setHashKeySerializer(new StringRedisSerializer()); template.afterPropertiesSet(); return template; } }
一些注意事项
- 类型标识的扩展性:上面的例子用了一个字节作为标识位,如果你以后需要支持更多序列化策略,可以扩展标识位的长度(比如用两个字节或字符串前缀)。
- Jackson序列化的兼容性:如果你的
ObjectNode/ArrayNode是通过Jackson的ObjectMapper生成的,GenericJackson2JsonRedisSerializer可以直接兼容,不需要额外配置;如果有特殊的Jackson配置,可以在初始化GenericJackson2JsonRedisSerializer时传入自定义的ObjectMapper。 - 测试验证:一定要分别测试两种类型的序列化/反序列化:比如存入一个
ObjectNode后取出,检查是否还是原类型;存入一个普通POJO(比如User类),取出后验证属性是否正确。
内容的提问来源于stack exchange,提问作者J.mos
相关产品推荐
相关产品推荐

