Commit d839e1ec authored by Andy Wilkinson's avatar Andy Wilkinson

Remove redundant restart-compatible Redis serializer

Previously, Spring Data Redis assumed that the class loader that loaded
its classes would also be able to load the application’s classes. This
assumption is faulty when there are multiple class loaders involved
such as when using dev tools or when Spring Data Redis is installed as
a shared library in a servlet container.

DATAREDIS-427 and DATAREDIS-501 removed this assumption by making the
default serialiser use the bean class loader. DevTools configures this
class loader to be the restart class loader which can load the
application’s classes. As a result of moving to Hopper SR2 snapshots,
these fixes are now available and we can remove our custom serialised.

Closes gh-5760
parent 1b252c3e
......@@ -21,9 +21,7 @@ import java.net.URL;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
......@@ -42,7 +40,6 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.StringUtils;
/**
......@@ -164,21 +161,6 @@ public class LocalDevToolsAutoConfiguration {
return watcher;
}
@Configuration
@ConditionalOnBean(name = RedisRestartConfiguration.SESSION_REDIS_TEMPLATE_BEAN_NAME)
static class RedisRestartConfiguration {
static final String SESSION_REDIS_TEMPLATE_BEAN_NAME = "sessionRedisTemplate";
@Bean
public RestartCompatibleRedisSerializerConfigurer restartCompatibleRedisSerializerConfigurer(
@Qualifier(SESSION_REDIS_TEMPLATE_BEAN_NAME) RedisTemplate<?, ?> sessionRedisTemplate) {
return new RestartCompatibleRedisSerializerConfigurer(
sessionRedisTemplate);
}
}
}
}
/*
* Copyright 2012-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.devtools.autoconfigure;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.serializer.DefaultDeserializer;
import org.springframework.core.serializer.support.DeserializingConverter;
import org.springframework.core.serializer.support.SerializingConverter;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import org.springframework.util.ObjectUtils;
/**
* Configures a {@link RedisTemplate} with a serializer for keys, values, hash keys, and
* hash values that is compatible with the split classloader used for restarts.
*
* @author Andy Wilkinson
* @author Rob Winch
* @see RedisTemplate#setHashKeySerializer(RedisSerializer)
* @see RedisTemplate#setHashValueSerializer(RedisSerializer)
* @see RedisTemplate#setKeySerializer(RedisSerializer)
* @see RedisTemplate#setValueSerializer(RedisSerializer)
*/
class RestartCompatibleRedisSerializerConfigurer implements BeanClassLoaderAware {
private final RedisTemplate<?, ?> redisTemplate;
private volatile ClassLoader classLoader;
RestartCompatibleRedisSerializerConfigurer(RedisTemplate<?, ?> redisTemplate) {
this.redisTemplate = redisTemplate;
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
@PostConstruct
void configureTemplateSerializers() {
RestartCompatibleRedisSerializer serializer = new RestartCompatibleRedisSerializer(
this.classLoader);
this.redisTemplate.setHashKeySerializer(serializer);
this.redisTemplate.setHashValueSerializer(serializer);
this.redisTemplate.setKeySerializer(serializer);
this.redisTemplate.setValueSerializer(serializer);
}
static class RestartCompatibleRedisSerializer implements RedisSerializer<Object> {
private static final byte[] NO_BYTES = new byte[0];
private final Converter<Object, byte[]> serializer = new SerializingConverter();
private final Converter<byte[], Object> deserializer;
RestartCompatibleRedisSerializer(ClassLoader classLoader) {
this.deserializer = new DeserializingConverter(
new DefaultDeserializer(classLoader));
}
@Override
public Object deserialize(byte[] bytes) {
try {
return (ObjectUtils.isEmpty(bytes) ? null
: this.deserializer.convert(bytes));
}
catch (Exception ex) {
throw new SerializationException("Cannot deserialize", ex);
}
}
@Override
public byte[] serialize(Object object) {
try {
return (object == null ? NO_BYTES : this.serializer.convert(object));
}
catch (Exception ex) {
throw new SerializationException("Cannot serialize", ex);
}
}
}
}
......@@ -31,7 +31,6 @@ import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration;
import org.springframework.boot.autoconfigure.web.ResourceProperties;
import org.springframework.boot.devtools.autoconfigure.RestartCompatibleRedisSerializerConfigurer.RestartCompatibleRedisSerializer;
import org.springframework.boot.devtools.classpath.ClassPathChangedEvent;
import org.springframework.boot.devtools.classpath.ClassPathFileSystemWatcher;
import org.springframework.boot.devtools.filewatch.ChangedFiles;
......@@ -235,31 +234,6 @@ public class LocalDevToolsAutoConfigurationTests {
.containsKey(new File("src/test/java").getAbsoluteFile());
}
@Test
public void sessionRedisTemplateIsConfiguredWithCustomDeserializers()
throws Exception {
sessionRedisTemplateIsConfiguredWithCustomDeserializers(
SessionRedisTemplateConfig.class);
}
private void sessionRedisTemplateIsConfiguredWithCustomDeserializers(
Object sessionConfig) throws Exception {
SpringApplication application = new SpringApplication(sessionConfig,
LocalDevToolsAutoConfiguration.class);
application.setWebEnvironment(false);
this.context = application.run();
RedisTemplate<?, ?> redisTemplate = this.context.getBean("sessionRedisTemplate",
RedisTemplate.class);
assertThat(redisTemplate.getHashKeySerializer())
.isInstanceOf(RestartCompatibleRedisSerializer.class);
assertThat(redisTemplate.getHashValueSerializer())
.isInstanceOf(RestartCompatibleRedisSerializer.class);
assertThat(redisTemplate.getKeySerializer())
.isInstanceOf(RestartCompatibleRedisSerializer.class);
assertThat(redisTemplate.getValueSerializer())
.isInstanceOf(RestartCompatibleRedisSerializer.class);
}
private ConfigurableApplicationContext initializeAndRun(Class<?> config,
String... args) {
return initializeAndRun(config, Collections.<String, Object>emptyMap(), args);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment