In this tutorial, I will show you how to add Redis Cache into your Spring Boot Application (CRUD example) using spring-boot-starter-data-redis and Lettuce Connector.
You can also apply this tutorial on following Projects:
– Spring Boot 3 Rest API example
– Spring Boot Rest API with H2
– Spring Boot Rest API with MySQL
– Spring Boot Rest API with PostgreSQL
– Spring Boot Rest API with MongoDB
– Spring Boot Rest API with SQL Server
– Spring Boot Rest API with Cassandra
– Spring Boot Rest API with Oracle
More Practice:
– Spring @CacheEvict example
– Spring Boot WebFlux Rest API example
– Spring Boot Security and JWT tutorial with example
– Spring Boot @ControllerAdvice & @ExceptionHandler example
– @RestControllerAdvice example in Spring Boot
– Spring Boot Unit Test for Rest Controller
– Documentation: Spring Boot Swagger 3 example
Contents
- Why Redis Cache?
- Spring Boot Redis Cache example Overview
- Install Redis
- Import Redis into Spring Boot
- Configure Redis connection
- RedisCacheManager in Spring Boot
- Create Service for Redis Cache abstraction
- Enable Caching Annotations
- Customize Redis Cache Configuration
- Run and Check
- Conclusion
- Source Code
- Further Reading
Why Redis Cache?
When a service experiences a high volume of requests and the requested data remains static, a caching solution can significantly reduce response times and lighten the load on the service.
Cache is a type of auxiliary memory that is specifically designed to hold data and instructions that are frequently accessed by applications or websites. Its fast and easy accessibility makes it a valuable tool in helping these applications and websites work faster.
There are several types of caching, including:
- Memory Cache: Primary Cache L1, Secondary Cache L2, Main Memory L3 Cache
- Web Cache: Site Cache, Browser Cache, Micro Cache, Server Cache
- Application/Software Cache
- Data Caching
- Application/Output Cache
- Distributed Caching
For more details, please visit: What is a Cache? 6 Types You Need to Know
We will build the Spring Boot Redis Cache example for Data Caching purpose.
Spring Boot Redis Cache example Overview
Assume that we’ve already had a Spring Boot Application that exposes Rest APIs for a Tutorial application:
Methods | Urls | Actions |
---|---|---|
POST | /api/tutorials | create new Tutorial |
GET | /api/tutorials | retrieve all Tutorials |
GET | /api/tutorials/:id | retrieve a Tutorial by :id |
PUT | /api/tutorials/:id | update a Tutorial by :id |
DELETE | /api/tutorials/:id | delete a Tutorial by :id |
DELETE | /api/tutorials | delete all Tutorials |
GET | /api/tutorials/published | find all published Tutorials |
GET | /api/tutorials?title=[keyword] | find all Tutorials which title contains keyword |
You can find how to implement this Rest API server in one of following tutorials (with Github):
– Spring Boot 3 Rest API example
– Spring Boot Rest API with H2
– Spring Boot Rest API with MySQL
– Spring Boot Rest API with PostgreSQL
– Spring Boot Rest API with MongoDB
– Spring Boot Rest API with SQL Server
– Spring Boot Rest API with Cassandra
– Spring Boot Rest API with Oracle
We will add Redis Cache for the Spring Boot CRUD example above by storing the query result (GET requests) with Redis.
That means, the response for following queries will be cached:
Methods | Urls | Actions |
---|---|---|
GET | /api/tutorials | retrieve all Tutorials |
GET | /api/tutorials/:id | retrieve a Tutorial by :id |
GET | /api/tutorials/published | find all published Tutorials |
GET | /api/tutorials?title=[keyword] | find all Tutorials which title contains keyword |
What we need is to add config package and a service for caching abstraction.
Install Redis
Follow this instruction for setup Redis on your Machine.
Import Redis into Spring Boot
To use Redis Cache in your Maven project, you need to add the spring-boot-starter-data-redis dependency to your project’s pom.xml file:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
To use Redis Cache in your Gradle project, you need to add the spring-boot-starter-data-redis
dependency to your project’s build.gradle file:
implementation 'org.springframework.boot:spring-boot-starter-data-redis:[version]'
This will support Java Redis client to interact with Redis server. In this tutorial, we use Lettuce Connector along with Spring Data.
Configure Redis connection
We configure the credentials to connect to the Redis instance from the Spring Boot app in application.properties.
redis.host=localhost
redis.port=6379
Then we continue to configure our Spring Boot Redis Lettuce by creating a new Lettuce connection factory.
config/RedisConfig.java
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
@Configuration
public class RedisConfig {
@Value("${redis.host}")
private String redisHost;
@Value("${redis.port}")
private int redisPort;
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration(redisHost, redisPort);
return new LettuceConnectionFactory(configuration);
}
}
RedisCacheManager in Spring Boot
With the org.springframework.data.redis.cache
package, Spring Redis offers a built-in implementation for the Spring cache abstraction. The beauty of the caching abstraction is that it allows for the use of multiple caching solutions with minimal changes to your codebase.
It’s important to note that the caching service is merely an abstraction and not a cache implementation, meaning that it still requires an actual storage solution to store the cached data. This concept is realized through the use of the org.springframework.cache.Cache
and org.springframework.cache.CacheManager
interfaces.
Add RedisCacheManager
to above configuration to use Redis as a backing implementation.
config/RedisConfig.java
import org.springframework.data.redis.cache.RedisCacheManager;
@Configuration
public class RedisConfig {
// ...
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {
return RedisCacheManager.create(connectionFactory);
}
}
Create Service for Redis Cache abstraction
To enable caching for specific methods, we will use @Cacheable
annotation, which designates methods as cacheable. This means that the result of the method is stored in the cache, so that subsequent invocations with the same arguments can return the cached value without invoking the method itself. The annotation simply requires the name of the cache associated with the method, as shown in the following example.
service/TutorialService.java
@Service
public class TutorialService {
@Autowired
TutorialRepository tutorialRepository;
@Cacheable("tutorials")
public List<Tutorial> findAll() {
doLongRunningTask();
return tutorialRepository.findAll();
}
@Cacheable("tutorials")
public List<Tutorial> findByTitleContaining(String title) {
doLongRunningTask();
return tutorialRepository.findByTitleContaining(title);
}
@Cacheable("tutorial")
public Optional<Tutorial> findById(long id) {
doLongRunningTask();
return tutorialRepository.findById(id);
}
@Cacheable("published_tutorials")
public List<Tutorial> findByPublished(boolean isPublished) {
doLongRunningTask();
return tutorialRepository.findByPublished(isPublished);
}
// other methods...
private void doLongRunningTask() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
The method is annotated with @Cacheable("tutorials")
or @Cacheable(value="tutorials")
, which tells Spring to cache the result of this method in a cache named “tutorials”. The value
(alias for cacheNames
) is name of the cache used to store the results of method invocations.
When the findAll()
method is called, it is associated with the 'tutorials'
cache name, and the cache is checked to see if the method has already been executed, preventing it from being executed again. While typically only a single cache is specified, the annotation enables multiple names to be supplied, allowing for the use of multiple caches. In this situation, each of the caches is evaluated before the method is executed, and if any of them contains the desired value, it is returned.
Enable Caching Annotations
To enable caching annotations, we use the annotation @EnableCaching
annotation:
service/TutorialService.java
@Service
@EnableCaching
public class TutorialService {
}
Customize Redis Cache Configuration
RedisCacheManager
behavior can be customized with RedisCacheManagerBuilder
.
The RedisCache created via RedisCacheManager
is governed by the RedisCacheConfiguration
, which enables you to specify key expiration times (TTL), RedisSerializer
implementations to convert between the binary storage format and other formats. The example below illustrates how this can be achieved:
config/RedisConfig.java
@Configuration
public class RedisConfig {
// ...
@Bean
public RedisCacheManager cacheManager() {
RedisCacheConfiguration cacheConfig = myDefaultCacheConfig(Duration.ofMinutes(10)).disableCachingNullValues();
return RedisCacheManager.builder(redisConnectionFactory())
.cacheDefaults(cacheConfig)
.withCacheConfiguration("tutorials", myDefaultCacheConfig(Duration.ofMinutes(5)))
.withCacheConfiguration("tutorial", myDefaultCacheConfig(Duration.ofMinutes(1)))
.build();
}
private RedisCacheConfiguration myDefaultCacheConfig(Duration duration) {
return RedisCacheConfiguration
.defaultCacheConfig()
.entryTtl(duration)
.serializeValuesWith(SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
}
}
Run and Check
– Run Redis first.
– Run Spring Boot application with Maven command: mvn spring-boot:run
.
Create some Tutorials – POST http://localhost:8080/api/tutorials
.
This is the Database table after that:
Let’s check our Spring Boot Redis Cache example.
In the first time we run GET http://localhost:8080/api/tutorials
, you can see that it takes more than 3 seconds.
We call the method again, Spring will check if the result is already present in the cache, and return it from the cache instead of executing the method again. Now the response time is only 16 milliseconds.
We continue to make another query: search by title:
GET http://localhost:8080/api/tutorials?title=edi
.
And the second request causes the cache hit.
It’s similar for the next example when we retrieve a specific Tutorial object.
GET http://localhost:8080/api/tutorials/3
.
Cache HIT for newer request:
If you continue to query other Tutorial objects (id=1 and id=5 for example). Redis Cache will store them.
Check the Redis Cache using Redis-CLI with KEYS *
command:
Use GET [key]
command for checking the value:
Conclusion
Today you’ve known the reason why we need Caching, then added Redis Cache into our Spring Boot application for CRUD example using spring-boot-starter-data-redis, we also configured Redis Lettuce connector for Spring Boot project.
In the tutorial, we use @Cacheable
annotation to tell Spring to cache the result of a method in a cache.
You also need to know way to evict cache with the tutorial:
Spring @CacheEvict example
Source Code
The complete source code for this tutorial is on Github.
You can also apply the code easily on following Projects:
– Spring Boot 3 Rest API example
– Spring Boot Rest API with H2
– Spring Boot Rest API with MySQL
– Spring Boot Rest API with PostgreSQL
– Spring Boot Rest API with MongoDB
– Spring Boot Rest API with SQL Server
– Spring Boot Rest API with Cassandra
– Spring Boot Rest API with Oracle
Further Reading
Fullstack CRUD App:
– Spring Boot Thymeleaf example
– Vue + Spring Boot example
– Angular 8 + Spring Boot example
– Angular 10 + Spring Boot example
– Angular 11 + Spring Boot example
– Angular 12 + Spring Boot example
– Angular 13 + Spring Boot example
– Angular 14 + Spring Boot example
– Angular 15 + Spring Boot example
– React + Spring Boot example
More Practice:
– Spring Boot WebFlux Rest API example
– Secure Spring Boot with Spring Security & JWT Authentication
– Spring Boot Rest XML example – Web service with XML Response
– Spring Boot + GraphQL example
– Spring Boot File upload example
– Spring Boot Pagination and Sorting example
– Documentation: Spring Boot Swagger 3 example