在我前面有一篇博客说到了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. January 11th, 2018 Week 02nd Thursday

    Live, travel, adventure, bless, and don't be sorry. 精彩地活着,不停地前行,大胆冒险,心怀感激,不留遗憾. Everything we do is ...

  2. JSON语法规则

    JSON 语法规则 JSON 语法是 JavaScript 对象表示法语法的子集. 数据在名称/值对中 数据由逗号分隔 花括号保存对象 方括号保存数组 JSON 名称/值对 JSON 数据的书写格式是 ...

  3. 一道题引发的self和super

    这个是那道题目,让写出输出的结果: 刚看到这一道题目的时候我的第一反应就是输出Son     Father.但是输出的结果是Son Son. 下面是解析:      我首先建立了两个类,一个Fathe ...

  4. 查询css相关属性的网站

    mozalla developer netwoke https://developer.mozilla.org/zh-CN/docs/Web/CSS/background 布局,div+css:htt ...

  5. linux的压缩解压命令全解

    .tar 解包:tar xvf FileName.tar打包:tar cvf FileName.tar DirName(注:tar是打包,不是压缩!)——————————————— .zip解压:un ...

  6. 数位dp小练

    最近刷题的同时还得填填坑,说来你们也不信,我还不会数位dp. 照例推几篇博客: 数位DP讲解 数位dp 的简单入门 这两篇博客讲的都很好,不过代码推荐记搜的形式,不仅易于理解,还短. 数位dp的式子一 ...

  7. A - Divisors POJ - 2992 (组合数C的因子数)数学—大数

    题意:就是求组合数C的因子的个数! 先说一下自己THL的算法,先把组合数求出来,然后将这个大数分解,得到各个素数的个数,再利用公式!用最快的大数分解算法 分析一下时间复杂度!   n1/4但是分析一下 ...

  8. python +百度语音识别+图灵对话

    https://github.com/Dongvdong/python_Smartvoice 上电后,只要周围声音超过 2000,开始录音5S 录音上传百度识别,并返回结果文字输出 继续等待,周围声音 ...

  9. 使用js切割URL的参数

    对于一些开发场景,不使用Jsp或freemarker及其其他的模板引擎时,通常通过切割url获得对应的参数,然后通过AJAX与后台交互得到对应的数据 下面是演示实例: test.html <!D ...

  10. docker常用命令汇总

    生成镜像docker build -t="eureka" .打标记docker tag eureka:latest 172.16.120.194:5000/eureka:lates ...