学习目标:
1、Java封装的发布和订阅
2、Java封装的List作为消息队列的使用
学习过程:
在ActiveMQ中可以分为广播模式和点对点模式,广播模式所有的监听者都可以收到消息,二点对点模式也可以有多个消费者,但是一条消息只能让一个消费者消费。使用redis也可以实现上面两种场景,前面也已经介绍过redis的发布订阅模式,和List数据类型的使用,这节课我们使用Java封装这两种方式以实现广播模式和点对点模式。
一、发布和订阅
1、定义订阅监听器
public class RedisMessageListener implements MessageListener {
@Autowired
RedisTemplate redisTemplate;
RedisSerializer serializer ;
@Override
public void onMessage(Message message, byte[] pattern) {
serializer = redisTemplate.getValueSerializer() ;
String messageStr = (String) serializer.deserialize(message.getBody());
System.out.println(messageStr);
}
}
可以同时启动两个监听器程序,写一个测试类发布消息
@Test
public void testPublish() {
template.convertAndSend("mytopic", "hello");
}
可以看到两个监听程序都可以同时收到消息了。
2、点对点模式
这里我们使用List数据格式就可以实现了,消息生产者不断push数据,而消费者不断pop数据就可以实现了。一般消费端都会使用死循环以不断的监控是否有新的消息到来,这就会产生一个问题,一旦消费端很多,那么在没有产生数据的时候就会不断的访问服务端,对redis产生很大压力,如果我们在消费端使用sleep,如果sleep的时长过长就会影响消息的实时性,有没有更好的解决方法呢?redis给我们提供了 blpop/brpop,也就是阻塞读。阻塞读在队列没有数据的时候,会立即进入休眠状态,一旦数据到来,则立刻醒过来。消息的延迟几乎为零。
消息消费端,注意这里我们使用rightPop的重载方法,该方法使用的就是brpop方式的。
@Test
public void testList1() {
while(true) {
String result= (String) template.opsForList().rightPop("students",20,TimeUnit.SECONDS);
System.out.println("testList1:"+result);
}
}
@Test
public void testList2() {
while(true) {
String result= (String) template.opsForList().rightPop("students",20,TimeUnit.SECONDS);
System.out.println("testList2:"+result);
}
}
我们也可以启动两个,然后再写一个消息生产者。
@Test
public void testPushList() throws InterruptedException {
for(int i=0;i<100;i++) {
Thread.sleep(1000);
long result=template.opsForList().leftPushAll("students", "a"+i,"b"+i);
}
}
留意一下输出的结果,每一条消息都只会消费一次。