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