Spring Session基於Redis存儲的序列化問題


  Spring redis SESSION 是如何進行反序列化?

  Spring session針對Web的Request請求有一個org.springframework.session.web.http.SessionRepositoryFilter過濾器,根據SESSION ID獲取相應的SESSION對象。

@Order(SessionRepositoryFilter.DEFAULT_ORDER)
public class SessionRepositoryFilter<S extends Session> extends OncePerRequestFilter{
 
  ...
  private final SessionRepository<S> sessionRepository;
 ...
}

  SessionRepositoryFilter會調用sessionRepository.findById(sessionId)來查找SESSION對象,對於Redis,sessionRepository實現類為org.springframework.session.data.redis.RedisOperationsSessionRepository,該類默認的序列化類為org.springframework.data.redis.serializer.JdkSerializationRedisSerializer.   

public class RedisOperationsSessionRepository implements
        FindByIndexNameSessionRepository<RedisOperationsSessionRepository.RedisSession>,
        MessageListener {
    ...
    private RedisSerializer<Object> defaultSerializer = new JdkSerializationRedisSerializer();
    ...
}

  查詢JdkSerializationRedisSerializer源碼,發現該類在反序列化時如果異常會拋出SerializationException異常,而SessionRepositoryFilter又沒有處理異常,故如果序列化異常時就會導致請求異常。

public class JdkSerializationRedisSerializer implements RedisSerializer<Object> {
 
    private final Converter<Object, byte[]> serializer;
    private final Converter<byte[], Object> deserializer;
 
    /**
     * Creates a new {@link JdkSerializationRedisSerializer} using the default class loader.
     */
    public JdkSerializationRedisSerializer() {
        this(new SerializingConverter(), new DeserializingConverter());
    }
 
    /**
     * Creates a new {@link JdkSerializationRedisSerializer} using a {@link ClassLoader}.
     *
     * @param classLoader
     * @since 1.7
     */
    public JdkSerializationRedisSerializer(ClassLoader classLoader) {
        this(new SerializingConverter(), new DeserializingConverter(classLoader));
    }
 
    /**
     * Creates a new {@link JdkSerializationRedisSerializer} using a {@link Converter converters} to serialize and
     * deserialize objects.
     *
     * @param serializer must not be {@literal null}
     * @param deserializer must not be {@literal null}
     * @since 1.7
     */
    public JdkSerializationRedisSerializer(Converter<Object, byte[]> serializer, Converter<byte[], Object> deserializer) {
 
        Assert.notNull(serializer, "Serializer must not be null!");
        Assert.notNull(deserializer, "Deserializer must not be null!");
 
        this.serializer = serializer;
        this.deserializer = deserializer;
    }
 
    public Object deserialize(@Nullable byte[] bytes) {
 
        if (SerializationUtils.isEmpty(bytes)) {
            return null;
        }
 
        try {
            return deserializer.convert(bytes);
        } catch (Exception ex) {
            throw new SerializationException("Cannot deserialize", ex);
        }
    }
 
    @Override
    public byte[] serialize(@Nullable Object object) {
        if (object == null) {
            return SerializationUtils.EMPTY_ARRAY;
        }
        try {
            return serializer.convert(object);
        } catch (Exception ex) {
            throw new SerializationException("Cannot serialize", ex);
        }
    }
}

  如何解決這個異常呢?定制Spring redis session的序列化類,替代原有的默認的JdkSerializationRedisSerializer。

@Configuration
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 86400)
public class RedisConfig {

    @Bean
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();

        FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);
        redisTemplate.setValueSerializer(fastJsonRedisSerializer);
        redisTemplate.setHashValueSerializer(fastJsonRedisSerializer);

        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        redisTemplate.setDefaultSerializer(new StringRedisSerializer());
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

    @Bean
    RedisSerializer<Object> springSessionDefaultRedisSerializer() {
        return new GenericFastJsonRedisSerializer();
    }
}

  在原有序列化JdkSerializationRedisSerializer對象的基礎上,在反序列化異常時捕獲這個異常,僅記錄相關日志即可

@Component("springSessionDefaultRedisSerializer")
public class CustomSessionDefaultRedisSerializer extends JdkSerializationRedisSerializer {
    
    private static final Logger LOG = LoggerFactory.getLogger(CustomSessionDefaultRedisSerializer.class);
    
    public Object deserialize(@Nullable byte[] bytes) {
        Object deserialObj = null;
        try
        {
            deserialObj =  super.deserialize(bytes);
        }
        catch(Exception e)
        {
            LOG.warn("deserialize session Object error!", e);
        }
        return deserialObj;
    }
 
}

參考:

       https://blog.yl-online.top/posts/74b23c9e.html

   

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM