As a Java professional, when designing applications that demand high performance and responsiveness, implementing caching can significantly improve efficiency. Redis is a powerful in-memory key-value store, and Spring Boot seamlessly integrates with it. While the Spring Cache abstraction (@Cacheable) is convenient, there are cases where full control is essential. In such cases, manually interacting with Redis using RedisTemplate offers the precision needed.
This article explores how to build a custom Redis caching layer in a Spring Boot application using the Jedis client. We will also cover how Redis templates work, when to use multiple templates, and how Redis keys are managed.
Why Manual Redis Cache Management?
While annotations like @Cacheable offer simplicity, manual cache handling gives you:
Full control over key structure
Fine-grained TTL (time-to-live) management
Custom serialization
Domain-specific cache logic
Redis Configuration with Jedis and RedisTemplate
@Configuration
public class RedisConfig {
@Bean
public JedisConnectionFactory jedisConnectionFactory() {
return new JedisConnectionFactory();
}
@Bean
public RedisTemplate<String, User> userRedisTemplate() {
RedisTemplate<String, User> template = new RedisTemplate<>();
template.setConnectionFactory(jedisConnectionFactory());
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new Jackson2JsonRedisSerializer<>(User.class));
return template;
}
}
The RedisTemplate<String, User> allows interaction with Redis using String keys and User object values. We use Jackson for JSON serialization.
RedisTemplate and opsForValue()
The method redisTemplate.opsForValue() returns ValueOperations<K, V> which provides operations for handling simple key-value pairs:
redisTemplate.opsForValue().set("user:123", user); // Save
User user = redisTemplate.opsForValue().get("user:123"); // Retrieve
@Service
public class UserCacheService {
private static final String PREFIX = "user:";
@Autowired
private RedisTemplate<String, User> userRedisTemplate;
public void saveUserToCache(User user) {
userRedisTemplate.opsForValue().set(PREFIX + user.getId(), user);
}
public User getUserFromCache(String id) {
return userRedisTemplate.opsForValue().get(PREFIX + id);
}
public void deleteUserFromCache(String id) {
userRedisTemplate.delete(PREFIX + id);
}
public boolean existsInCache(String id) {
return Boolean.TRUE.equals(userRedisTemplate.hasKey(PREFIX + id));
}
}
REST Controller for Testing
@RestController
@RequestMapping("/custom-cache/users")
public class UserController {
@Autowired
private UserCacheService userCacheService;
@PostMapping
public ResponseEntity<String> cacheUser(@RequestBody User user) {
userCacheService.saveUserToCache(user);
return ResponseEntity.ok("User cached");
}
@GetMapping("/{id}")
public ResponseEntity<User> getCachedUser(@PathVariable String id) {
User user = userCacheService.getUserFromCache(id);
return user != null ? ResponseEntity.ok(user) : ResponseEntity.notFound().build();
}
@DeleteMapping("/{id}")
public ResponseEntity<String> removeCachedUser(@PathVariable String id) {
userCacheService.deleteUserFromCache(id);
return ResponseEntity.ok("User cache entry deleted");
}
@GetMapping("/{id}/exists")
public ResponseEntity<Boolean> checkCache(@PathVariable String id) {
return ResponseEntity.ok(userCacheService.existsInCache(id));
}
}
Key Management: Should You Use Multiple Templates?
You do not need separate RedisTemplate instances for each domain object (e.g., User, Company, Role) if you use a universal serializer like GenericJackson2JsonRedisSerializer. However, if you want type safety, strict serialization, or domain-specific settings, separate templates can be useful.
Best Practice
Use key prefixes like user:123, company:123 to avoid key collisions.
Spring Cache abstraction already prefixes keys using cache names (users::123 vs companies::123).
Only define multiple templates if different serializers or behaviors are needed.
Summary
Using Redis manually in Spring Boot gives you powerful control for caching domain data. RedisTemplate and opsForValue() let you perform raw Redis operations such as set, get, and delete, while preserving type safety and structure with JSON serialization. Whether you want full CRUD on cache or domain-specific logic, this approach offers flexibility beyond the limits of @Cacheable.
As a Java professional, when designing applications that demand high performance and responsiveness, implementing caching can significantly improve efficiency. Redis is a powerful in-memory key-value store, and Spring Boot seamlessly integrates with it. While the Spring Cache abstraction (
@Cacheable
) is convenient, there are cases where full control is essential. In such cases, manually interacting with Redis usingRedisTemplate
offers the precision needed.This article explores how to build a custom Redis caching layer in a Spring Boot application using the Jedis client. We will also cover how Redis templates work, when to use multiple templates, and how Redis keys are managed.
Why Manual Redis Cache Management?
While annotations like
@Cacheable
offer simplicity, manual cache handling gives you:Redis Configuration with Jedis and RedisTemplate
The
RedisTemplate<String, User>
allows interaction with Redis usingString
keys andUser
object values. We use Jackson for JSON serialization.RedisTemplate and
opsForValue()
The method
redisTemplate.opsForValue()
returnsValueOperations<K, V>
which provides operations for handling simple key-value pairs:You can also set TTL:
Custom User Cache Service
REST Controller for Testing
Key Management: Should You Use Multiple Templates?
You do not need separate RedisTemplate instances for each domain object (e.g.,
User
,Company
,Role
) if you use a universal serializer likeGenericJackson2JsonRedisSerializer
. However, if you want type safety, strict serialization, or domain-specific settings, separate templates can be useful.Best Practice
user:123
,company:123
to avoid key collisions.users::123
vscompanies::123
).Summary
Using Redis manually in Spring Boot gives you powerful control for caching domain data.
RedisTemplate
andopsForValue()
let you perform raw Redis operations such as set, get, and delete, while preserving type safety and structure with JSON serialization. Whether you want full CRUD on cache or domain-specific logic, this approach offers flexibility beyond the limits of@Cacheable
.Credits: Babar Shahzad
Recent Posts
Recent Posts
Custom Redis Caching in Spring Boot Using
Red Hat OpenShift: The Enterprise Kubernetes Platform
🔒 How to Secure JAR Files from
Archives