shiro继承redis序列化失败-----坑

时间:2025-03-27 20:09:15

shiro继承redis进行session的管理:

package ;

import ;
import org.;
import org.;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import .GenericJackson2JsonRedisSerializer;
import .Jackson2JsonRedisSerializer;
import ;
import ;


@Configuration
@EnableCaching
@Data
public class RedisConfiguration extends CachingConfigurerSupport {
    private Logger logger = (());

   
    /**
     * 配置redis 连接
     */
    @Bean
    @ConditionalOnMissingBean(name = "redisTemplate")
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        // 1.创建 redisTemplate 模版
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        // 2.关联 redisConnectionFactory
        (factory);
        // 3.创建 自定义序列化类
        MyRedisSerializer myRedisSerializer = new MyRedisSerializer();
        // 7.设置 value 的转化格式和 key 的转化格式 默认使用的是JdkSerializationRedisSerializer
        (myRedisSerializer);
        (myRedisSerializer);
        // 设置键(key)的序列化采用StringRedisSerializer。
        (new StringRedisSerializer());
        (new StringRedisSerializer());
        (myRedisSerializer);
        ();
        return template;
    }

    @Bean
    @ConditionalOnMissingBean()
    public RedisTemplate<String, String> stringRedisTemplate(RedisConnectionFactory factory) {
        return new StringRedisTemplate(factory);
    }
}

    默认使用JdkSerializationRedisSerializer,这个序列化模式会将value序列化成字节码,这样缓存shiro的session就没有什么问题,当是redis数据库的数据将是字节码,不方便观察。

   如果改用GenericJackson2JsonRedisSerializer或者Jackson2JsonRedisSerializer,项目启动运行没有任何问题,但是在在访问过程中,突然性的报错:

      : Unrecognized field "valid" (class ), not marked as ignorable (10 known properties: "attributeKeys", "timeout", "startTimestamp", "expired", "lastAccessTime", "host", "id", "stopTimestamp", "attributes", "attributesLazy"])

这是由于是反序列化报错的原因。无法反序列化接口的动态代理类,原因应该是动态代理类没有缺省构造函数。

处理方式:     

  1. 解决session序列化问题方法也很简单,setValueSerializer不配置就可以了。
    如果想要redis数据库的数据为json字符串,那么可以在其他用到缓存的地方使用StringRedisTemplate,或者再定义一个template。

    2. 自定义序列化和反序列化方法。

MyRedisSerializer 序列化成字节数组
import ;
import ;

import .*;

/**
 * 重写序列化 序列化为字节码
 * zhw
 */
public class MyRedisSerializer implements RedisSerializer {


    @Override
    public byte[] serialize(Object o) throws SerializationException {
        ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
        ObjectOutputStream objOut;
        try {
            objOut = new ObjectOutputStream(byteOut);
            (o);
        } catch (IOException e) {
            ();
        }
        return ();
    }

    @Override
    public Object deserialize(byte[] bytes) throws SerializationException {
        if(bytes == null) return null;
        ByteArrayInputStream byteIn = new ByteArrayInputStream(bytes);
        ObjectInputStream objIn;
        Object obj;
        try {
            objIn = new ObjectInputStream(byteIn);
            obj =();
        } catch (IOException | ClassNotFoundException e) {
            ();
            return null;
        }
        return obj;
    }

}
FastJsonRedisSerializer:序列化成json字符串
import ;
import ;
import ;
import ;
import ;

import ;

/**
 * 重写序列化 序列化为json字符串
 * zhw
 */
public class FastJsonRedisSerializer implements RedisSerializer {


    public static final Charset DEFAULT_CHARSET = ("UTF-8");

    private Class<T> clazz;

    public FastJsonRedisSerializer(Class<T> clazz) {
        super();
         = clazz;
    }

    @Override
    public byte[] serialize(Object o) throws SerializationException {
        if (o == null) {
            return new byte[0];
        }
        return (o, ).getBytes(DEFAULT_CHARSET);
    }
    @Override
    public T deserialize(byte[] bytes) throws SerializationException {
        if (bytes == null ||  <= 0) {
            return null;
        }
        String str = new String(bytes, DEFAULT_CHARSET);
        return (str, clazz);
    }
}

      多个项目彼此之间需使用同一个redis,一个项目往redis存入数据,另一个项目从redis中获取数据,如果使用的不是同一个redis的序列化方式,这样导致,另一个项目是无法从redis中获取到该key所对应的数据。