在我前面有一篇博客说到了rabbitMq实现与zk类似的watch功能,但是那一篇博客没有代码实例,后面自己补了一个demo,便于理解。demo中主要利用spring boot的配置方式,

一、消费者(也就是watcher)配置

配置都采用spring的注解进行配置

1、创建连接

  @Bean
public ConnectionFactory createConnectionFactory() {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
     //设置rabbitMq的ip和端口
connectionFactory.setAddresses("127.0.0.1");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("/");
connectionFactory.setPublisherConfirms(true);
return connectionFactory;
}

2、创建交换机

    @Bean
public Exchange fanoutExchange() {
return new FanoutExchange("ex_rabbit_test");
}

创建一个名为ex_rabbit_test的交换机,交换机的类型为广播类型(为了实现消息的广播)

3、创建队列,并绑定到交换机上

    @Bean
public Queue queueOne() {
return new Queue("queue_one", false, false, true);
} @Bean
public Binding bindingOne(Queue queueOne, FanoutExchange fanoutExchange) {
return BindingBuilder.bind(queueOne)
.to(fanoutExchange);
}

每一个消费者有自己的队列,只消费自己队列的消息;将队列和交换机绑定之后,交换机会将生产者发出的消息放到所有绑定的队列中,但是仅限广播模式,其它模式会按照一定的路由规则进行消息路由,比如topic类型的交换机会按照routingKey路由消息。

注意:在广播模式中,为了实现消息监听,每个消费者需要各自起一个队列,而且队列名不相同,比如现在有另外一个消费者:

    @Bean
public Queue queueTwo() {
return new Queue("queue_two", false, false, true);
} @Bean
public Binding BingdingTwo(Queue queueTwo, FanoutExchange fanoutExchange) {
return BindingBuilder.bind(queueTwo)
.to(fanoutExchange);
}

如此一来,当生产者将消息发到交换机ex_rabbit_test中时,交换机就将消息发给queue_one和queue_two两个队列中,两个消费者分别取两个队列的消息进行消费。

4、消费消息

    @Bean
public SimpleMessageListenerContainer execMessageContainerOne() {
     //设置监听者“容器”
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(createConnectionFactory());
     //设置队列名
container.setQueueNames("queue_one");
     //设置监听者数量,即消费线程数
container.setConcurrentConsumers(1);
container.setMessageListener((ChannelAwareMessageListener) (message, channel) -> {
byte[] body = message.getBody();
if(null != body) {
try {
String msg = new String(body);
String usr = "Consumer one";
consumerService.doProcess(usr, msg);//消费消息
} catch(Exception e) {
e.printStackTrace();
}
}
});
return container;
} @Bean
public SimpleMessageListenerContainer execMessageContainerTwo() {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(createConnectionFactory());
container.setQueueNames("queue_two");
container.setConcurrentConsumers(1);
container.setMessageListener((ChannelAwareMessageListener) (message, channel) ->{
byte[] body = message.getBody();
if(null != body) {
try {
String msg = new String(body);
String usr = "Consumer two";
consumerService.doProcess(usr, msg);//消费消息
} catch (Exception e) {
e.printStackTrace();
}
}
});
return container;
}

consumerService提供消费消息的服务,执行如下方法

    public void doProcess(String usr, String msg) {
System.out.println(usr + " receive message from producer:" + msg);
}

二、生产者配置

1、与消费者相同的方式建立rabbitMq的连接

2、与消费者相同的方式设置交换机,交换机名称也为ex_rabbit_test(如果rabbitmq中已经存在这个交换机,可以不用创建)

3、关于是否建立队列以及将队列与交换机绑定,我的理解是这样的:

  如果在生产者的代码里面建立队列并将其与交换机绑定,那么就必须建立所有的消费者的队列,并将所有队列与交换机绑定,如果这样做,消费者中就可以省掉这个配置。事实上,这样做是有点得不偿失的,我不赞同这样做,这里只是说明这样做也可以达到目的。

4、创建rabbit模板(org.springframework.amqp.rabbit.core.RabbitTemplate)

    @Bean
public RabbitTemplate rabbitTemplateProducer() {
RabbitTemplate rabbitTemplate = new RabbitTemplate(this.createConnectionFactory());
rabbitTemplate.setExchange("ex_rabbit_test");
return rabbitTemplate;
}

5、实现消息发送

  demo中使用spring web的方式启动消息发送,下面是controller和service的代码

@Controller
@RequestMapping(value="/index")
public class ProducerController { @Autowired
private ProducerService producerService; @RequestMapping(value = "/send")
@ResponseBody
public String sendMsg(@RequestParam String msg) {
producerService.send(msg);
return "Success";
}
}
@Service
public class ProducerService { @Resource(name = "rabbitTemplateProducer")
private RabbitTemplate rabbitTemplate; public void send(String msg) {
String message = "Hello, consumer.Sending:" + msg;
rabbitTemplate.convertAndSend(message);
}
}

三、pom文件

在consumer中只需要引入spring ampq的依赖

    <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
<version>1.5.3.RELEASE</version>
</dependency>
</dependencies>

在prudocer中需要引入spring ampq的依赖,另外由于是启动了web 项目,所以需要spring web的依赖

    <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
<version>1.5.3.RELEASE</version>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>1.5.3.RELEASE</version>
</dependency>
</dependencies>

四、启动项目和测试结果

使用spring boot可以快速启动项目,首先,在8882端口上启动producer,然后启动consumer。通过在controller中定义的访问地址http://localhost:8882/index/send?msg=hello everybody(此处的msg必须有,因为@RequestParam注解),可以看到两个消费者都消费了这条消息

Consumer one receive message from producer:Hello, consumer.Sending:hello everybody
Consumer two receive message from producer:Hello, consumer.Sending:hello everybody

从rabbitMq的后台(http://localhost:15672  usrname:guest  pasword:guest)可以看到刚才创建的交换机和队列。

当消费者变多,或者为了代码的统一管理,每个消费者的代码需要相同,为了实现广播需求,需要为每个消费者设置不同的队列名。这种情况下,可以采用UUID的方式,每个消费者可以创建一个唯一的随机队列名。UUID方式创建队列名的代码可以在ampq的jar包中找到org.springframework.amqp.core.AnonymousQueue

     public String generateName() {
UUID uuid = UUID.randomUUID();
ByteBuffer bb = ByteBuffer.wrap(new byte[16]);
bb.putLong(uuid.getMostSignificantBits())
.putLong(uuid.getLeastSignificantBits());
// TODO: when Spring 4.2.4 is the minimum Spring Framework version, use encodeToUrlSafeString() SPR-13784.
return this.prefix + Base64Utils.encodeToString(bb.array())
.replaceAll("\\+", "-")
.replaceAll("/", "_")
// but this will remain
.replaceAll("=", "");
}

可以将UUID方法的返回值加在固定队列名的后面,这样就生成了一个唯一的随机队列名。关于UUID的描述可以自行百度。

ps:前段时间看了spring cloud,看到其中的一个工具,spring cloud bus也可以用作消息监听,细察之后发现,spring cloud bus也是封装了rabbitMq,实现了消息队列。

rabbitMq与spring boot搭配实现监听的更多相关文章

  1. Spring Boot实践——事件监听

    借鉴:https://blog.csdn.net/Harry_ZH_Wang/article/details/79691994 https://blog.csdn.net/ignorewho/arti ...

  2. Spring Boot实现一个监听用户请求的拦截器

    项目中需要监听用户具体的请求操作,便通过一个拦截器来监听,并继续相应的日志记录 项目构建与Spring Boot,Spring Boot实现一个拦截器很容易. Spring Boot的核心启动类继承W ...

  3. Spring Boot 事件和监听

    Application Events and Listeners 1.自定义事件和监听 1.1.定义事件 package com.cjs.boot.event; import lombok.Data; ...

  4. Spring boot设置启动监听端口

    一.通过配置 修改application.properties 在属性文件中添加server.port=8000 二.直接看代码: @Controller @EnableAutoConfigurati ...

  5. 【spring源码学习】spring的事件发布监听机制源码解析

    [一]相关源代码类 (1)spring的事件发布监听机制的核心管理类:org.springframework.context.event.SimpleApplicationEventMulticast ...

  6. RabbitMQ(三):RabbitMQ与Spring Boot简单整合

    RabbitMQ是目前非常热门的一款消息中间件,不管是互联网大厂还是中小企业都在大量使用.Spring Boot的兴起,极大地简化了Spring的开发,本文将使用Spring Boot与RabbitM ...

  7. Spring事件发布与监听机制

    我是陈皮,一个在互联网 Coding 的 ITer,微信搜索「陈皮的JavaLib」第一时间阅读最新文章,回复[资料],即可获得我精心整理的技术资料,电子书籍,一线大厂面试资料和优秀简历模板. 目录 ...

  8. 【Spring】关于SpringMvc监听的知识点

    一,在使用Spring系列框架时,我们需要在Web.xml配置Spring的监听:ContextLoaderListener ContextLoaderListener的作用就是,在Web容器初始化时 ...

  9. spring源码-事件&监听3.6

    一.spring中的发布与监听模式,是我们最常用的一种观察者模式.spring在其中做了很多优化,目的就是让用户更好的使用事件与监听的过程. 二.常用的事件与监听中涉及到的接口和类为:Applicat ...

随机推荐

  1. nginx、tomcat调优方向及压测网站步骤

    nginx调优方向: 1.所用事件处理模型 2.进程数 3.每个进程的连接数 4.压缩 5.缓存 tomcat调优方向: 1.内存 2.总内存 3.初始申请内存 4.线程内存 5.GC方面 tomca ...

  2. C#中类为什么要实例化

    在使用C#语言时,发现一下有关类实例化的问题,在此之前先复习一下类和对象的概念,类是一个抽象体,是对一类事物的抽象体:而对象就是一个具体的事物,对象的抽象就是类.车就是一个类,而车包括面包车,小汽车, ...

  3. emacs org-mode文件转html文件

    Table of Contents 1. 发布站点 by emacs org-mode 1.1 org-mode 自带的导出方法 1.2 批量导出 1.3 css 美化 1.4 导出html 1. 发 ...

  4. Java中BufferedReader到底是一个什么类?

    1.java.io.BufferedReader 和 java.io.BufferedWriter 类各拥有8192字符的缓冲区.当BufferedReader在读取文本文件时,会先尽量从文件中读入字 ...

  5. Highcharts属性与Y轴数据值刻度显示Y轴最小最大值

    Highcharts 官网:https://www.hcharts.cn/demo/highcharts Highcharts API文档:https://api.hcharts.cn/highcha ...

  6. 基于jquery的从一个页面跳转到另一个页面的指定位置的实现代码

    比如 想跳到 mao.aspx 的页面 的div id="s" 的位置 那么 只用<a href="mao.aspx#s"> 就可实现跳转到指定位置 ...

  7. 深入分析escape()、encodeURI()、encodeURIComponent()的区别及示例

    JavaScript中有三个可以对字符串编码的函数,分别是: escape,encodeURI,encodeURIComponent,相应3个解码函数:unescape,decodeURI,decod ...

  8. UCML JS函数说明

    UCML JS函数说明1.调用父窗体函数 window.openerWindow.函数名 2.公用JS存放位置 BPObject\Model\Rule\initvalue.js 3.弹窗JS var ...

  9. linux 基础 用户操作

    命令: 1. whoami 2.su 用户名 3.useradd 用户名 4.passwd 用户名

  10. 看进程的启动时间长度 + vmstat + jstack 应用

    1.显示进程已运行的时间 $ ps -e -o pid,comm,etime 2.dd不断的向磁盘写入数据,所以bo的值会骤然提高,而cpu的wait数值也变高,说明由于大量的IO操作,系统的瓶径出现 ...