多项目共用redis导致反序列化出错:Failed to deserialize object type; nested exception is java.lang.ClassNotFoundExc

  • Post author:
  • Post category:java



问题背景:

有同事反应,她修改了架构的名称做项目,本地没有问题,丢到服务器上出现反序列失败的问题。


报错显示该不存在的类是该服务器上另一个项目的。


问题根源:

多项目共用一个redis,若存在相同的key时,会被覆盖,导致反序列化获取该key时,存在找不到该类的情况。


解决方案:

1. 每个项目给key值增加前缀,这样在共用redis时,不存在key值冲突。

1)重写key值处理的类

import org.springframework.data.redis.serializer.RedisSerializer;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

/**
 * 为redis key 统一加上前缀
 */
public class RedisKeySerializer implements RedisSerializer<String> {

    /**
     * 编码格式
     */
    private final Charset charset;

    /**
     * 前缀
     */
    private final String PREFIX_KEY = "gsi:";

    public RedisKeySerializer() {
        this(StandardCharsets.UTF_8);
    }

    public RedisKeySerializer(Charset charset) {
        this.charset = charset;
    }

    /**
     * 反序列化
     */
    @Override
    public String deserialize(byte[] bytes) {
        String key = new String(bytes, charset);
        return key.replace(PREFIX_KEY, "");
    }

    /**
     * 序列化
     */
    @Override
    public byte[] serialize(String key) {
        key = PREFIX_KEY + key;
        return key.getBytes(charset);
    }
}

2) 调整RedisConfig类

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
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.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 * redis配置类
 */
@Configuration
public class RedisConfig {
    @Bean
    @SuppressWarnings("all")
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        // key采用String的序列化方式
        template.setKeySerializer(stringRedisSerializer);
        // hash的key也采用String的序列化方式
        template.setHashKeySerializer(stringRedisSerializer);
        // value序列化方式采用jackson
        template.setValueSerializer(jackson2JsonRedisSerializer);
        // hash的value序列化方式采用jackson
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }

}

2. 在Redis中默认有16个库,利用redis可以分库的特性,各个项目使用不同的redis库database,这样也可以避免key值冲突的问题。

#redis配置
redis:
  database: 1
  host: 127.0.0.1
  port: 6379
  password:
  jedis:
    pool:
      max-active: 8
      max-wait: -1
      max-idle: 8
      min-idle: 0
  timeout: 5000

结束!



版权声明:本文为xhuiting原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。