Essential Configuration Changes When Upgrading to Spring Boot 2.x
Redis Connection Factory Configuration
Spring Boot 2.x introduces significant changes to Redis auto-configuration. The Jedis client setup requires explicit bean definitions with updated APIs.
Required Dependency
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
Configuration Implementation
package com.example.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisPassword;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
@Configuration
@EnableCaching
public class RedisConnectionSetup extends CachingConfigurerSupport {
private static final Logger log = LoggerFactory.getLogger(RedisConnectionSetup.class);
@Value("${spring.redis.database}")
private int dbIndex;
@Value("${spring.redis.host}")
private String redisHost;
@Value("${spring.redis.port}")
private int redisPort;
@Value("${spring.redis.timeout}")
private int connectionTimeout;
@Value("${spring.redis.pool.max-active}")
private int poolMaxActive;
@Value("${spring.redis.pool.max-idle}")
private int poolMaxIdle;
@Value("${spring.redis.pool.min-idle}")
private int poolMinIdle;
@Value("${spring.redis.pool.max-wait}")
private long poolMaxWait;
@Value("${spring.redis.password}")
private String redisPassword;
@Bean
public RedisConnectionFactory redisConnectionFactory() {
RedisStandaloneConfiguration standaloneConfig = new RedisStandaloneConfiguration();
standaloneConfig.setHostName(redisHost);
standaloneConfig.setPort(redisPort);
standaloneConfig.setDatabase(dbIndex);
standaloneConfig.setPassword(RedisPassword.of(redisPassword));
JedisConnectionFactory factory = new JedisConnectionFactory(standaloneConfig);
return factory;
}
@Bean
public JedisPool jedisPoolConfig() {
log.info("Initializing JedisPool for {}:{}", redisHost, redisPort);
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxIdle(poolMaxIdle);
poolConfig.setMaxWaitMillis(poolMaxWait);
poolConfig.setMaxTotal(poolMaxActive);
poolConfig.setMinIdle(poolMinIdle);
return new JedisPool(poolConfig, redisHost, redisPort, connectionTimeout, redisPassword, dbIndex);
}
@Bean
public RedisTemplate<String, Object> cacheRedisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
Jackson2JsonRedisSerializer<Object> jsonSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.ALL, Visibility.ANY);
mapper.activateDefaultTyping(mapper.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL);
jsonSerializer.setObjectMapper(mapper);
RedisSerializer<String> stringSerializer = new StringRedisSerializer();
template.setKeySerializer(stringSerializer);
template.setValueSerializer(jsonSerializer);
template.setHashKeySerializer(stringSerializer);
template.setHashValueSerializer(jsonSerializer);
return template;
}
@Bean
public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
return RedisCacheManager.builder(RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory))
.cacheDefaults(buildDefaultCacheConfig(600))
.withInitialCacheConfigurations(buildCustomCacheConfigs())
.build();
}
private Map<String, RedisCacheConfiguration> buildCustomCacheConfigs() {
Map<String, RedisCacheConfiguration> customConfigs = new HashMap<>();
customConfigs.put("VendorItemCache", buildDefaultCacheConfig(30));
customConfigs.put("CustomerDataStore", buildDefaultCacheConfig(180));
return customConfigs;
}
private RedisCacheConfiguration buildDefaultCacheConfig(int ttlSeconds) {
Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, Visibility.ANY);
objectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL);
serializer.setObjectMapper(objectMapper);
return RedisCacheConfiguration.defaultCacheConfig()
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer))
.entryTtl(Duration.ofSeconds(ttlSeconds));
}
}
WebMvcConfigurationSupport Adjustments
The Web MVC configuration approach has been refined in Spring Boot 2.x. Extend WebMvcConfigurationSupport and override specific methods to customize behavior.
package com.example.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import java.nio.charset.StandardCharsets;
import java.util.List;
@Configuration
public class WebMvcSetupAdapter extends WebMvcConfigurationSupport {
@Autowired
private Environment environment;
@Bean
public HttpMessageConverter<String> stringMessageConverter() {
return new StringHttpMessageConverter(StandardCharsets.UTF_8);
}
@Override
protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(stringMessageConverter());
super.configureMessageConverters(converters);
}
@Override
protected void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new AuthCheckInterceptor()).addPathPatterns("/api/**");
super.addInterceptors(registry);
}
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
String uploadPath = environment.getProperty("file.upload.directory");
registry.addResourceHandler("/uploads/**").addResourceLocations("file:" + uploadPath);
super.addResourceHandlers(registry);
}
@Override
protected void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("*")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedHeaders("*");
}
}
Jackson ClassMate Dependency
Spring Boot 2.x requires explicit inclusion of the ClassMate library for advanced JSON processing capabilities.
<dependency>
<groupId>com.fasterxml</groupId>
<artifactId>classmate</artifactId>
<version>1.4.0</version>
</dependency>