In this article, we are going to see how to use Redis in a Spring Application. We will explore Redis, an open-source project that can be utilized with the Spring Framework.
What is Redis?
According to the official Redis website:
“Redis is an open-source (BSD licensed), in-memory data structure store used as a database, cache, and message broker.”
Redis.io
Essentially, Redis is an open-source project that can be utilized as a cache, database, or message broker, storing information in memory. Storing data in memory allows for fast data retrieval, resulting in excellent performance.
Why use Redis in a Spring Application?
Redis is often used in Spring applications for various reasons. Here are some key reasons why Redis is beneficial in the context of Spring:
- Caching: Redis is widely used as an in-memory data store and cache. By integrating Redis with Spring, you can easily cache frequently accessed data and improve the performance of your application. Redis provides fast read and write operations, making it suitable for caching.
- Session Management: Redis can be used to store and manage session data in a distributed environment. With Spring Session, you can configure Redis as the session store, allowing your application to scale horizontally while maintaining session state across multiple instances.
- Pub/Sub Messaging: Redis includes a pub/sub (publish/subscribe) feature that enables asynchronous communication between different components of your Spring application. This can be useful for implementing event-driven architectures, real-time messaging, and decoupled communication patterns.
- Data Structures and Analytics: Redis provides various data structures like lists, sets, sorted sets, and hashes, along with associated operations. These data structures can be leveraged within your Spring application for tasks such as leaderboard management, real-time analytics, and data manipulation.
- Distributed Locking: Redis supports distributed locks, which can be valuable in distributed systems to ensure mutual exclusion and prevent conflicts. With Redis distributed locks, you can coordinate concurrent access to resources across multiple instances of your Spring application.
Overall, using Redis in Spring applications brings benefits such as improved performance, scalability, real-time capabilities, and simplified data management. It enhances the functionality and efficiency of your Spring-based projects.
How to Use Redis in a Spring Application?
In this article, we will focus on using Redis in a Spring Cloud architecture. We will explore how to use Redis in the following ways:
- Database
- Message broker
- Cache
Required Maven Libraries
To use Redis in a Spring project, you will need to include the following dependencies in your Maven project:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
Redis as a Database
The primary purpose of Redis is to serve as an in-memory cache or key-value store. However, it can also function as a persistent database.
First, let’s start a Redis container:
$ docker run -d --name redis -p 6379:6379 redis redis-server --appendonly yes
@RedisHash("user") public class User { @Id String id; String firstname; String lastname; Address address; }
Using Spring Data makes the implementation straightforward. We can define a User class with annotations such as @RedisHash and @Id to persist the hash:
To enable Redis functionality, we need to add the @EnableRedisRepositories annotation to make use of Spring Repositories:
@Configuration @EnableRedisRepositories public class ManagementPeople { }
Thanks to Spring Data, we can avoid creating queries as Spring will handle them for us. We need to create a CrudRepository interface:
public interface UserRepository extends CrudRepository<User, String> { }
With these configurations, we can persist data with Redis using Spring.
Redis as a Message Broker
To implement an event-driven architecture, a messaging system is required. Redis can be used as an asynchronous messaging system for such scenarios.
To use Redis as a message broker, we first declare a bean called MessageConfiguration and a ChannelTopic that defines the topic. The TripPublisher bean sends messages to the defined topic:
@Configuration public class RedisMessageConfiguration { @Autowired RedisTemplate<?, ?> redisTemplate; @Bean MessageConfiguration messageConfiguration() { return new MessageConfiguration(redisTemplate, topic()); } @Bean ChannelTopic topic() { return new ChannelTopic("message"); } }
The MessageConfiguration class uses RedisTemplate to send messages to the defined topic. Before sending, it converts them to JSON format.
@Slf4j public class MessageConfiguration { RedisTemplate<?, ?> redisTemplate; ChannelTopic topic; public MessageConfiguration(RedisTemplate<?, ?> redisTemplate, ChannelTopic topic) { this.redisTemplate = redisTemplate; this.redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer(Message.class)); this.topic = topic; } public void publish(Message message) throws JsonProcessingException { log.info("Sending: {}", message); redisTemplate.convertAndSend(topic.getTopic(), message); } }
In the previous class, we used Jackson2JsonRedisSerializer to serialize the message into JSON and then sent it using redisTemplate. As an additional note, we used @Slf4j, which belongs to Lombok, to help eliminate Java boilerplate. With this annotation, we can make use of log.
Now we have everything defined for the producer part, and the next step is to implement the consumer part.
To consume messages, we need to define a RedisMessageListenerContainer bean to listen for messages and subscribe to the topic:
@Configuration public class MessageConfiguration { @Autowired RedisConnectionFactory redisConnectionFactory; @Bean RedisMessageListenerContainer container() { RedisMessageListenerContainer container = new RedisMessageListenerContainer(); container.addMessageListener(messageListener(), topic()); container.setConnectionFactory(redisConnectionFactory); return container; } @Bean MessageListenerAdapter messageListener() { return new MessageListenerAdapter(new MessageSubscriber()); } @Bean ChannelTopic topic() { return new ChannelTopic("message"); } }
Next, we will create a class that will be responsible for handling each incoming message. To do this, we will implement the MessageListener interface. Each message arrives serialized as JSON, so we need to convert it into the desired object.
@Service @Slf4j public class MessageSubscriber implements MessageListener { ObjectMapper mapper = new ObjectMapper(); @Override public void onMessage(Message message, byte[] bytes) { try { log.info("Message received {}", message.toString()); Message message = mapper.readValue(message.getBody(), Message.class); } } catch (IOException e) { log.error("Something went wrong {}", e.getMessage); } } }
In this last class, we have converted the incoming message in JSON format to the Message class.
Redis as Cache
As we have seen, Redis can have more uses than just being a cache. Now let’s see how to implement it to be used as a cache.
When adding the Redis dependency, auto-configuration for Redis and cache is provided.
If you want to modify the values of RedisCacheManager, you can do so by using the prefix spring.redis.* and the corresponding property:
spring.redis.host=my-redis spring.redis.timeout=1000
To modify the values of the cache, you can use the prefix spring.cache.redis.* and set the corresponding property.
spring.cache.redis.key-prefix=hellokoding:: spring.cache.redis.time-to-live=100000
The information is stored in the cache as key-value pairs. The GenericJackson2JsonRedisSerializer class can be used to serialize the objects.
@RequiredArgsConstructor @Slf4j @Service public class CentreService { private final CentreRepository centreRepository; @Override @Cacheable(value = "centres", unless = "#result.length()<1") public Set<Centre> getCentres() { log.debug("Getting centres {} "; return centreRepository.getCentres(); } }
With this, we would be caching a list of centers. The @Cacheable annotation allows us to cache a method, which must always be public. We have already discussed caching in Spring here. Within the @Cacheable annotation, we can define the key or a condition to prevent caching. In this case, if the list is empty, we don’t cache anything. As a side note, in this class, we have used Lombok again for dependency injection with the constructor.
Although we have the main components in place for the cache to work, the most important step is to activate it. To enable caching, simply add the @EnableCaching annotation.
@SpringBootApplication @EnableCaching public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
Conclusion
In this post about use Redis in a Spring Framework Application, we have seen how to configure Redis with Spring Boot for various purposes. Redis is a highly useful tool in a distributed architecture.
If you need more information, you can leave us a comment or send an email to refactorizando.web@gmail.com You can also contact us through our social media channels on Facebook or twitter and we will be happy to assist you!!