转自 https://blog.csdn.net/myNameIssls/article/details/75471012
参考 http://tramp.cincout.cn/2017/07/03/spring-nosql-2017-07-03-spring-boot-redis-pubsub/
SpringBoot集成Redis消息订阅发布
1. pom.xml文件添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
2. 创建一个Redis消息接收器
package cn.tyrone.springboot.redis.message;
import java.util.concurrent.CountDownLatch;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
public class Receiver {
private static final Logger LOGGER = LoggerFactory.getLogger(Receiver.class);
private CountDownLatch latch;
@Autowired
public Receiver(CountDownLatch latch) {
this.latch = latch;
}
public void receiveMessage(String message) {
LOGGER.info("Received <" + message + ">");
latch.countDown();
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
Receiver这是一个定义了一个接收消息的方法的类。当你把这个类作为一个消息监听器来注册后,你可以自定义消息接收的方法名。本例中采用“receiveMessage”作为接收消息的方法。
3. 注册一个监听器并发送消息
Spring Data Redis 提供了使用Redis发送和接收的消息的所有的组件。我们只需要做以下配置:
- 一个Redis连接工厂(A connection factory)
- 一个消息监听器的容器(A message listener container)
- 一个Redis模板(A redis template)
我们使用redis template发送消息,把Receiver类注册为一个消息监听器以使它可以接收消息。Connection factory是授权它们连接Redis服务的。
本例中采用的是SpringBoot默认的RedisConnectionFactory,这是一个基于jedis Redis库的JedisConnectionFactory的实例。它被注入到消息监听器和redis模板中。
编写SpringBoot启动类并注入本例需要的对象实例
package cn.tyrone.springboot.redis.message;
import java.util.concurrent.CountDownLatch;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
//https://spring.io/guides/gs/messaging-redis/
@SpringBootApplication
public class Application {
public static final Logger LOGGER = LoggerFactory.getLogger(Application.class);
/*
* Redis消息监听器容器
* 这个容器加载了RedisConnectionFactory和消息监听器
*/
@Bean
RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory,
MessageListenerAdapter listenerAdapter){
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
container.addMessageListener(listenerAdapter, new PatternTopic("sprinboot-redis-messaage"));
return container;
}
/*
* 将Receiver注册为一个消息监听器,并指定消息接收的方法(receiveMessage)
* 如果不指定消息接收的方法,消息监听器会默认的寻找Receiver中的handleMessage这个方法作为消息接收的方法
*/
@Bean
MessageListenerAdapter listenerAdapter(Receiver receiver){
return new MessageListenerAdapter(receiver, "receiveMessage");
}
/*
* Receiver实例
*/
@Bean
Receiver receiver(CountDownLatch latch){
return new Receiver(latch);
}
@Bean
CountDownLatch latch(){
return new CountDownLatch(1);
}
/*
* Redis Template 用来发送消息
*/
@Bean
StringRedisTemplate template(RedisConnectionFactory connectionFactory){
return new StringRedisTemplate(connectionFactory);
}
/*
* 测试用例
*/
public static void main(String[] args) throws Exception {
ApplicationContext ctx = SpringApplication.run(Application.class, args);
StringRedisTemplate template = ctx.getBean(StringRedisTemplate.class);
// CountDownLatch latch = ctx.getBean(CountDownLatch.class);
LOGGER.info("Sending message......");
template.convertAndSend("sprinboot-redis-messaage", "Hello, SpringBoot redis message!!!!");
// latch.wait();
System.exit(0);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
对于本例并不十分清楚CountDownLatch latch这个的目的,在测试的过程中,加上这句代码,会抛一个异常,但是发送和接收消息都是成功的。异常信息如下:
2017-07-20 10:14:50.909 INFO 7200 --- [ main] c.t.s.redis.message.Application : Sending message......
Exception in thread "main" java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:502)
at cn.tyrone.springboot.redis.message.Application.main(Application.java:77)
- 1
- 2
- 3
- 4
- 5
如果将此代码注释掉,该异常也将消息。同时,也并不影响消息的发布与接收。CountDownLatch 只是一个同步的辅助类,测试过程中,并没有发现这个类对测试结果的有什么帮助。