How to connect to multiple redis server when using spring boot?
Purpose
In this article , I will demo how to connect to multiple(for example 2) redis server using spring boot app. Just as following picture shows.
Environment
- Spring boot 1.x+
- Jdk 8+
- Redis
The Project Layout
The layout of this demo project is as follows, all the example code can be found here:
➜ spring-boot-multiredis git:(master) tree ..├── pom.xml├── src│ ├── main│ │ ├── java│ │ │ └── com│ │ │ └── bswen│ │ │ └── sbmr│ │ │ ├── MultiRedisApplication.java│ │ │ ├── config│ │ │ │ ├── Redis1Configuration.java│ │ │ │ ├── Redis1Property.java│ │ │ │ ├── Redis2Configuration.java│ │ │ │ ├── Redis2Property.java│ │ │ │ └── RedisCommonProperty.java│ │ │ └── service│ │ │ ├── MultiRedisTestRunner.java│ │ │ └── MyMessageReceiver.java│ │ └── resources│ │ └── application.properties
The Pom
We use maven to define the dependencies:
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <java.version>1.8</java.version> <start-class>Application</start-class> </properties>
<dependencyManagement> <dependencies> <dependency> <!-- Import dependency management from Spring Boot --> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>1.4.3.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
<artifactId>spring-boot-multiredis</artifactId>
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> </dependency> </dependencies>
The code
1. Config file: src/main/resources/application.properties
spring.redis.host=localhostspring.redis.port=6379spring.redis.database=0
spring.redis2.host=localhostspring.redis2.port=26379spring.redis2.database=0
Here we define two redis connection, one is localhost:6379, the other is localhost:26379
2. Property config classes: src/main/java/com.bswen.sbmr/config/
To read the above properties file into spring boot, we must define configuration classes:
At first, we define a common class as the base class of redis configuration classes:
public class RedisCommonProperty { private String host; private int port; private int database; //getters setters}
Then, we define Redis1Property and Redis2Property class to denote the different redis configurations
Redis1Property.java
@Configuration@ConfigurationProperties(prefix = "spring.redis")public class Redis1Property extends RedisCommonProperty {}
Redis2Property.java
@Configuration@ConfigurationProperties(prefix = "spring.redis2")public class Redis2Property extends RedisCommonProperty {}
Pay attention to the ConfigurationProperties annotation, we use it to load different properties from the application.properties file.
Thirdly, we should define how to get the RedisTemplate and RedisConnectionFactory from above properties:
For redis server1, we define Redis1Configuration:
@Configurationpublic class Redis1Configuration {
@Autowired private Redis1Property redis1Property;
@Primary @Bean(name = "redis1ConnectionFactory") public RedisConnectionFactory userRedisConnectionFactory() { JedisConnectionFactory redisConnectionFactory = new JedisConnectionFactory(); redisConnectionFactory.setHostName(redis1Property.getHost()); redisConnectionFactory.setPort(redis1Property.getPort()); redisConnectionFactory.setDatabase(redis1Property.getDatabase()); redisConnectionFactory.setPoolConfig(getPoolConfig()); return redisConnectionFactory; }
private JedisPoolConfig getPoolConfig() { JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); jedisPoolConfig.setMaxIdle(8); jedisPoolConfig.setMinIdle(1); jedisPoolConfig.setMaxTotal(8); return jedisPoolConfig; }
@Bean(name = "redis1StringRedisTemplate") public StringRedisTemplate userStringRedisTemplate(@Qualifier("redis1ConnectionFactory") RedisConnectionFactory cf) { StringRedisTemplate stringRedisTemplate = new StringRedisTemplate(); stringRedisTemplate.setConnectionFactory(cf); return stringRedisTemplate; }
@Bean(name = "redis1RedisTemplate") public RedisTemplate userRedisTemplate(@Qualifier("redis1ConnectionFactory") RedisConnectionFactory cf) { StringRedisTemplate stringRedisTemplate = new StringRedisTemplate(); stringRedisTemplate.setConnectionFactory(cf); //setSerializer(stringRedisTemplate); return stringRedisTemplate; }
}
For redis server2, we define Redis2Configuration:
@Configurationpublic class Redis2Configuration { @Autowired private Redis2Property redis2Property;
private JedisPoolConfig getPoolConfig() { JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); jedisPoolConfig.setMaxIdle(8); jedisPoolConfig.setMinIdle(1); jedisPoolConfig.setMaxTotal(8); return jedisPoolConfig; }
@Bean(name = "redis2ConnectionFactory") public RedisConnectionFactory roleRedisConnectionFactory() { JedisConnectionFactory redisConnectionFactory = new JedisConnectionFactory(); redisConnectionFactory.setHostName(redis2Property.getHost()); redisConnectionFactory.setPort(redis2Property.getPort()); redisConnectionFactory.setDatabase(redis2Property.getDatabase()); redisConnectionFactory.setPoolConfig(getPoolConfig()); return redisConnectionFactory; }
@Bean(name = "redis2StringRedisTemplate") public StringRedisTemplate roleStringRedisTemplate(@Qualifier("redis2ConnectionFactory") RedisConnectionFactory cf) { StringRedisTemplate stringRedisTemplate = new StringRedisTemplate(); stringRedisTemplate.setConnectionFactory(cf); return stringRedisTemplate; }
@Bean(name = "redis2RedisTemplate") public RedisTemplate roleRedisTemplate(@Qualifier("redis2ConnectionFactory") RedisConnectionFactory cf) { StringRedisTemplate stringRedisTemplate = new StringRedisTemplate(); stringRedisTemplate.setConnectionFactory(cf); //setSerializer(stringRedisTemplate); return stringRedisTemplate; }
}
Now we have setup the properties and the configurations , we have beans of RedisTemplate , we can test it as follows:
@Componentpublic class MultiRedisTestRunner implements CommandLineRunner { private final static Logger logger = LoggerFactory.getLogger(MultiRedisApplication.class);
@Autowired @Qualifier("redis1StringRedisTemplate") private StringRedisTemplate userStringRedisTemplate; @Autowired @Qualifier("redis2StringRedisTemplate") private StringRedisTemplate roleStringRedisTemplate;
@Override public void run(String... strings) throws Exception { try { for (int i = 0; i < 10; i++) { logger.info("====================================================================="); logger.info("start loop " + i); String key = "key" + i; userStringRedisTemplate.opsForValue().set(key, "value" + i); roleStringRedisTemplate.opsForValue().set(key, "value" + (i + 1));
String primaryKeyValue = userStringRedisTemplate.opsForValue().get(key); String secondaryKeyValue = roleStringRedisTemplate.opsForValue().get(key);
logger.info("====================================================================="); logger.info(String.format("read from the redis1, key %s value is %s", key, primaryKeyValue)); logger.info(String.format("read from the redis2, key %s value is %s", key, secondaryKeyValue)); } }catch(Exception ex) { throw ex; } }}
Run it, we get this result:
3-05 17:26:49.352 INFO 13130 --- [ main] o.s.c.support.DefaultLifecycleProcessor : Starting beans in phase 21474836472021-03-05 17:26:49.481 INFO 13130 --- [ main] com.bswen.sbmr.MultiRedisApplication : =====================================================================2021-03-05 17:26:49.482 INFO 13130 --- [ main] com.bswen.sbmr.MultiRedisApplication : start loop 02021-03-05 17:26:49.507 INFO 13130 --- [ main] com.bswen.sbmr.MultiRedisApplication : =====================================================================2021-03-05 17:26:49.507 INFO 13130 --- [ main] com.bswen.sbmr.MultiRedisApplication : read from the redis1, key key0 value is value02021-03-05 17:26:49.507 INFO 13130 --- [ main] com.bswen.sbmr.MultiRedisApplication : read from the redis2, key key0 value is value12021-03-05 17:26:49.507 INFO 13130 --- [ main] com.bswen.sbmr.MultiRedisApplication : =====================================================================2021-03-05 17:26:49.507 INFO 13130 --- [ main] com.bswen.sbmr.MultiRedisApplication : start loop 12021-03-05 17:26:49.511 INFO 13130 --- [ main] com.bswen.sbmr.MultiRedisApplication : =====================================================================2021-03-05 17:26:49.511 INFO 13130 --- [ main] com.bswen.sbmr.MultiRedisApplication : read from the redis1, key key1 value is value12021-03-05 17:26:49.511 INFO 13130 --- [ main] com.bswen.sbmr.MultiRedisApplication : read from the redis2, key key1 value is value22021-03-05 17:26:49.511 INFO 13130 --- [ main] com.bswen.sbmr.MultiRedisApplication : =====================================================================2021-03-05 17:26:49.512 INFO 13130 --- [ main] com.bswen.sbmr.MultiRedisApplication : start loop 22021-03-05 17:26:49.515 INFO 13130 --- [ main] com.bswen.sbmr.MultiRedisApplication : =====================================================================2021-03-05 17:26:49.516 INFO 13130 --- [ main] com.bswen.sbmr.MultiRedisApplication : read from the redis1, key key2 value is value22021-03-05 17:26:49.516 INFO 13130 --- [ main] com.bswen.sbmr.MultiRedisApplication : read from the redis2, key key2 value is value32021-03-05 17:26:49.516 INFO 13130 --- [ main] com.bswen.sbmr.MultiRedisApplication : =====================================================================2021-03-05 17:26:49.516 INFO 13130 --- [ main] com.bswen.sbmr.MultiRedisApplication : start loop 32021-03-05 17:26:49.520 INFO 13130 --- [ main] com.bswen.sbmr.MultiRedisApplication : =====================================================================2021-03-05 17:26:49.520 INFO 13130 --- [ main] com.bswen.sbmr.MultiRedisApplication : read from the redis1, key key3 value is value32021-03-05 17:26:49.520 INFO 13130 --- [ main] com.bswen.sbmr.MultiRedisApplication : read from the redis2, key key3 value is value42021-03-05 17:26:49.520 INFO 13130 --- [ main] com.bswen.sbmr.MultiRedisApplication : =====================================================================2021-03-05 17:26:49.520 INFO 13130 --- [ main] com.bswen.sbmr.MultiRedisApplication : start loop 42021-03-05 17:26:49.524 INFO 13130 --- [ main] com.bswen.sbmr.MultiRedisApplication : =====================================================================2021-03-05 17:26:49.524 INFO 13130 --- [ main] com.bswen.sbmr.MultiRedisApplication : read from the redis1, key key4 value is value42021-03-05 17:26:49.524 INFO 13130 --- [ main] com.bswen.sbmr.MultiRedisApplication : read from the redis2, key key4 value is value52021-03-05 17:26:49.524 INFO 13130 --- [ main] com.bswen.sbmr.MultiRedisApplication : =====================================================================2021-03-05 17:26:49.524 INFO 13130 --- [ main] com.bswen.sbmr.MultiRedisApplication : start loop 52021-03-05 17:26:49.528 INFO 13130 --- [ main] com.bswen.sbmr.MultiRedisApplication : =====================================================================2021-03-05 17:26:49.529 INFO 13130 --- [ main] com.bswen.sbmr.MultiRedisApplication : read from the redis1, key key5 value is value52021-03-05 17:26:49.529 INFO 13130 --- [ main] com.bswen.sbmr.MultiRedisApplication : read from the redis2, key key5 value is value62021-03-05 17:26:49.529 INFO 13130 --- [ main] com.bswen.sbmr.MultiRedisApplication : =====================================================================2021-03-05 17:26:49.529 INFO 13130 --- [ main] com.bswen.sbmr.MultiRedisApplication : start loop 62021-03-05 17:26:49.533 INFO 13130 --- [ main] com.bswen.sbmr.MultiRedisApplication : =====================================================================2021-03-05 17:26:49.533 INFO 13130 --- [ main] com.bswen.sbmr.MultiRedisApplication : read from the redis1, key key6 value is value62021-03-05 17:26:49.533 INFO 13130 --- [ main] com.bswen.sbmr.MultiRedisApplication : read from the redis2, key key6 value is value72021-03-05 17:26:49.533 INFO 13130 --- [ main] com.bswen.sbmr.MultiRedisApplication : =====================================================================2021-03-05 17:26:49.533 INFO 13130 --- [ main] com.bswen.sbmr.MultiRedisApplication : start loop 72021-03-05 17:26:49.538 INFO 13130 --- [ main] com.bswen.sbmr.MultiRedisApplication : =====================================================================2021-03-05 17:26:49.538 INFO 13130 --- [ main] com.bswen.sbmr.MultiRedisApplication : read from the redis1, key key7 value is value72021-03-05 17:26:49.538 INFO 13130 --- [ main] com.bswen.sbmr.MultiRedisApplication : read from the redis2, key key7 value is value82021-03-05 17:26:49.538 INFO 13130 --- [ main] com.bswen.sbmr.MultiRedisApplication : =====================================================================2021-03-05 17:26:49.538 INFO 13130 --- [ main] com.bswen.sbmr.MultiRedisApplication : start loop 82021-03-05 17:26:49.542 INFO 13130 --- [ main] com.bswen.sbmr.MultiRedisApplication : =====================================================================2021-03-05 17:26:49.542 INFO 13130 --- [ main] com.bswen.sbmr.MultiRedisApplication : read from the redis1, key key8 value is value82021-03-05 17:26:49.542 INFO 13130 --- [ main] com.bswen.sbmr.MultiRedisApplication : read from the redis2, key key8 value is value92021-03-05 17:26:49.542 INFO 13130 --- [ main] com.bswen.sbmr.MultiRedisApplication : =====================================================================2021-03-05 17:26:49.542 INFO 13130 --- [ main] com.bswen.sbmr.MultiRedisApplication : start loop 92021-03-05 17:26:49.546 INFO 13130 --- [ main] com.bswen.sbmr.MultiRedisApplication : =====================================================================2021-03-05 17:26:49.546 INFO 13130 --- [ main] com.bswen.sbmr.MultiRedisApplication : read from the redis1, key key9 value is value92021-03-05 17:26:49.546 INFO 13130 --- [ main] com.bswen.sbmr.MultiRedisApplication : read from the redis2, key key9 value is value10
It works!
By the way: How to subscribe to two redis server simultaneously?
Now we can connect two redis server , send command (get/set/…) to them and get response, but how can we use the pub/sub functions to listen to redis channels?
As the above picture shown, the process is as follows:
- You should have two redis server running
- Your spring boot application connects to the two redis servers
- Then you can subscribe to topics on the two redis servers by using spring boot RedisMessageListener
- At last, the messages would be forwarded to a RedisReceiver to process
So the key point is how to setup two redis servers’ RedisMessageListener, let’s check the code:
@Componentpublic class MultiRedisListenerTester { @Bean RedisMessageListenerContainer container1(@Qualifier("redis1ConnectionFactory") RedisConnectionFactory connectionFactory,
MessageListenerAdapter listenerAdapter) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer(); container.setConnectionFactory(connectionFactory); container.addMessageListener(listenerAdapter, new PatternTopic("tasks1"));
return container; }
@Bean RedisMessageListenerContainer container2(@Qualifier("redis2ConnectionFactory") RedisConnectionFactory connectionFactory,
MessageListenerAdapter listenerAdapter) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer(); container.setConnectionFactory(connectionFactory); container.addMessageListener(listenerAdapter, new PatternTopic("tasks2"));
return container; }
@Bean MessageListenerAdapter listenerAdapter(MyMessageReceiver receiver) { return new MessageListenerAdapter(receiver, "receiveMessage"); }}
Let’s analyze the above code:
- We create a class named MultiRedisListenerTester with the annotation @Component, which indicate that the class is a spring bean.
- The method named container1 and container2 has two parameters, one is connectionFactory, which is injected with specified redisConnectionFactory with @Qualifer annotation, the redisConnectionFactory beans are defined in Redis1Configuration and Redis2Configuration, the other is a listenerAdapter, which is supplied by listenerAdapter method defined below.
- We subscribed with topic name tasks1 on redis server1 and tasks2 on redis server2.
- The method named listenerAdapter indicates that when redis get a message, it would push the message the the receiver’s receiveMessage method.
Now let’s check the reciever’s code:
@Componentpublic class MyMessageReceiver { private static Log log = LogFactory.getLog(MyMessageReceiver.class);
public void receiveMessage(String message) { log.info("got message "+message); }}
Let’s test the multiple redis server’s pub/sub feature on redis server1:
//publish on redis server1 with redis-cli consolelocalhost-6379:0>publish tasks1 hello11//got message from spring boot message receiver:2021-03-06 11:22:31.465 INFO 17414 --- [ container1-2] c.bswen.sbmr.service.MyMessageReceiver : got message hello1
Let’s test the multiple redis server’s pub/sub feature on redis server2:
//publish on redis server2 with redis-cli consolelocalhost-6379:0>publish tasks2 hello21//got message from spring boot message receiver:2021-03-06 11:22:32.465 INFO 17414 --- [ container1-2] c.bswen.sbmr.service.MyMessageReceiver : got message hello2
If you want to tell from which redis server pushed the message, e.g. the source of the message, you can inject different named MessageListenerAdapter instances by using @Qualifier injection in method container1 and container2.
For example:
@Bean RedisMessageListenerContainer container2(@Qualifier("redis2ConnectionFactory") RedisConnectionFactory connectionFactory,
@Qualifier("redis2Listener") MessageListenerAdapter listenerAdapter) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer(); container.setConnectionFactory(connectionFactory); container.addMessageListener(listenerAdapter, new PatternTopic("tasks2"));
return container; }
@Bean(name="redis2Listener") MessageListenerAdapter listenerAdapter(MyMessageReceiver receiver) { return new MessageListenerAdapter(receiver, "receiveMessage"); }
Summary
In this post, I demonstrated how to connect to multiple redis server instances with spring boot, the key point is that you should setup specific configuration for each redis server connection. And I also showed how to use the pub/sub function of springboot in the multiple redis server environment, thanks for your reading. All code of the project is uploaded to github.com, you can download at this link.
Final Words + More Resources
My intention with this article was to help others who might be considering solving such a problem. So I hope that’s been the case here. If you still have any questions, don’t hesitate to ask me by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
- 👨💻 spring boot and redis
- 👨💻 github project
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!