Implementation of Spring-Boot Data Redis for caching in my application
By: Kumar Shivam
Tags: Cache, Spring Boot Data Redis, Spring Boot, Redis

Redis, which stands for Remote Dictionary Server, is a fast, open-source (BSD licensed), NoSQL, in-memory key-value data store use as a database, cache, message broker, and queue.

Redis supports the following features:-

· Replication

· Lua scripting

· LRU eviction of keys

· Transactions and different level of on-disk persistence

· Provides high availability using Redis Sentinel

· Automatic partitioning with Redis Cluster.

· Automatic failover

Why Redis cache over Memcached?

Redis cache provides Snapshots, Replication, Transactions, Pub/Sub, Lua scripting, Geospatial support features which are not provided by Memcached. Memcached could be preferable when caching relatively small and static data, such as HTML code, images and small metadata sets.

How to implement Redis cache in our project?

Step 1:- Project initialization

We need to initialize a spring project with below maven dependencies:-

· Navigate to site “https://start.spring.io/”

· We will fill the below detail and include spring web and Redis dependencies then we will click on GENERATE CTRL button

· Open this project in your favourite spring boot or java editor

· Open pom.xml file and add the below jedis dependency

Jedis is the client library in java for Redis. It is light-weight and easy to use. But, there are other popular client libraries(i.e. lettuce and Redisson) are also available to connect with Redis which offers some unique features like thread safety, transparent reconnection handling and async API calls.

Step 2:- Maven Dependencies to use Redis

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-data-redis</artifactId>

<exclusions>

<exclusion>

<groupId>io.lettuce</groupId>

<artifactId>lettuce-core</artifactId>

</exclusion>

</exclusions>

</dependency>

<dependency>

<groupId>redis.clients</groupId>

<artifactId>jedis</artifactId>

</dependency>

Project Structure:-

Step 4:- Open file “SpringBootRedisCacheApplication.java”

Step 5:- we need to create a connection factory bean to connect to Redis client using JedisConnectionFactory. This connection factory class comes under package “org.springframework.data.redis.connection.jedis”

@Bean

JedisConnectionFactory jedisConnectionFactory() { RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration("localhost", 6379); return new JedisConnectionFactory(redisStandaloneConfiguration); }

Here we need to provide the Redis server configurational detail. In my case, I’m using default local configuration and default port(i.e. 6379).

Step 6:- Create an instance of RedisTemplate class and pass the jedisConnectionFactory bean. RedisTemplate can be used for querying data with a custom repository. This class is under package : org.springframework.data.redis.core.

@Bean

RedisTemplate<String, User> redisTemplate() {

RedisTemplate<String, User> redisTemplate = new RedisTemplate<>();

redisTemplate.setConnectionFactory(jedisConnectionFactory());

return redisTemplate;

}

Here I’m using User detail to keep in the Redis cache. This class expect two type parameter

K — the Redis key type against which the template works (i.e. String)

V — the Redis value type against which the template works(i.e. User)

Step 7:- Create a User class with below data members

package com.example.springbootrediscache.models; import java.io.Serializable; public class User implements Serializable { private String id;

private String name;

private Long salary; public User(String id, String name, Long salary) {

this.id = id;

this.name = name;

this.salary = salary;

} public String getId() {

return id;

} public void setId(String id) {

this.id = id;

} public String getName() {

return name;

} public void setName(String name) {

this.name = name;

} public Long getSalary() {

return salary;

} public void setSalary(Long salary) {

this.salary = salary;

}

}

Step 8:- Create Spring data repository for this class

· Create a UserRepository interface

public interface UserRepository {

void save(User user);

Map<String,User> findAll();

User findById(String id);

void update(User user);

void delete(String id);

}

· Create UserRepositoryImpl class

@Repository

public class UserRepositoryImpl implements UserRepository { private RedisTemplate<String, User> redisTemplate;

private HashOperations hashOperations; //to access Redis cache public UserRepositoryImpl(RedisTemplate<String, User> redisTemplate) {

this.redisTemplate = redisTemplate;

hashOperations = redisTemplate.opsForHash();

} @Override

public void save(User user) {

hashOperations.put("USER",user.getId(),user);

} @Override

public Map<String,User> findAll() {

return hashOperations.entries("USER");

} @Override

public User findById(String id) {

return (User)hashOperations.get("USER",id);

} @Override

public void update(User user) {

save(user);

} @Override

public void delete(String id) {

hashOperations.delete("USER",id);

}

}

Step 9:- Create a UserController API controller to expose the endpoint

public class UserController { @Autowired

private UserRepository _userRepository; public UserController(UserRepository userRepository){

_userRepository = userRepository;

} @GetMapping("/all")

public Map<String, User> GetAll(){

return _userRepository.findAll();

} @GetMapping("/all/{id}")

public User GetAll(@PathVariable("id") final String id){

return _userRepository.findById(id);

} @PostMapping("/add")

public User add(@RequestBody User user){

_userRepository.save(new User(user.getId(),user.getName(),80000L)); return _userRepository.findById(user.getId());

} @PostMapping("/update")

public User update(@RequestBody User user){

_userRepository.update(new User(user.getId(),user.getName(),1000L)); return _userRepository.findById(user.getId());

}

}

Here I’m using @Autowiring annotation to inject dependency of UserRepository.So that I can be able to access all the methods which I’ve declared inside the UserRepository interface.

Step 10:- Start Redis server:-

· We need to navigate to the folder location where we have a Redis server

c:\redis-server\windows\Redis-x64–3.2.100

· Click on the “redis-server” then the server will start, we will see below screen

Step 11:- Start this application

Step 12:- Since in this project I’ve configured swagger and I’m using port: 8083, so my API endpoint will be something like this

http://localhost:8083/swagger-ui.html

Step 13:- After accessing the API links we will see below four endpoints

You can download the code from my Github repository: spring-boot-redis-cache-demo-project

Usecases:-

· Caching — It provides an in-memory cache facility to decrease latency, increase the throughput of the application.

· Chat system or massaging system — It supports a pub-sub model with pattern matching.

· Gaming leaderboards — It has implemented Sorted sets to handle time-series data by using timestamps as the score.

· Session stores — It has in-memory data stores with high availability and persistence.

· Media- streaming — Redis can be used to store metadata about users’ profiles and viewing histories, authentication information/tokens for millions of users, and manifest files to enable CDNs to stream videos to millions of mobile and desktop users at a time.

· Geospatial — It is used to log location-based features such as drive distance, drive time etc.

· ML — It provides fast in-memory data store to build, train and deploy machine learning model.

Redis cache limits

It has no limit on storing data on a 64-bit system but, on the 32-bit system, it can only store 3 GB. So, once cache reaches its memory limit, we should remove the old data to make some space for the new one.

Conclusion, in this section we understood what is Redis cache, its capabilities and implementation using Spring-boot data Redis