springboot实现MQ发布订阅模式.(内容来源于蚂蚁课堂)
实现代码:
新建java工程,编写生产者代码
1.引入amqp依赖,springboot版本是2.0.1.RELEASE
<!-- 添加springboot对amqp的支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
2.配置文件
spring:
rabbitmq:
host: 127.0.0.1
port: 5672
username: root
password: 1234
virtual-host: /wk_virtual_hosts
server:
port: 2100
# 关闭eureka注册发现
eureka.client.register-with-eureka: false
eureka.client.fetch-registry: false
3.MQ信息常量配置
package com.google.config;
/**
* @author wk
* @Description: 交换机 队列 routingKey名称配置
* @date 2019/12/16 15:42
**/
public class MQConfig {
public static final class EXCHANGE_NAMES {
//fanout类型交换机
public static final String FANOUT_EXCHANGE = "FANOUT_EXCHANGE";
}
public static final class QUEUE_NAMES {
//邮件队列
public static final String FANOUT_EMAIL_QUEUE = "FANOUT_EMAIL_QUEUE";
//短信队列
public static final String FANOUT_SMS_QUEUE = "FANOUT_SMS_QUEUE";
}
}
4.定义队列、定义交换机、队列
package com.google.config;
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
/**
* @author wk
* @Description:发布订阅模式配置的交换机类型 fanout
* @date 2019/12/12 15:37
**/
@Component
public class FanoutConfig {
/*
1.定义队列
2.定义交换机
3.队列绑定交换机
*/
/**
* 1.定义邮件队列
*
* @return
*/
@Bean
public Queue fanoutEmailQueue() {
//构造方法多态
return new Queue(MQConfig.QUEUE_NAMES.FANOUT_EMAIL_QUEUE);
}
/**
* 1.定义短信队列
*
* @return
*/
@Bean
public Queue fanoutSmsQueue() {
return new Queue(MQConfig.QUEUE_NAMES.FANOUT_SMS_QUEUE);
}
/**
* 2.定义交换机
* 主题交换机TopicExchange
*
* @return
*/
@Bean
public FanoutExchange fanoutExchange() {
//构造方法多态
return new FanoutExchange(MQConfig.EXCHANGE_NAMES.FANOUT_EXCHANGE);
}
/**
* 3.邮件队列与交换机绑定
* Queue fanoutEmailQueue, FanoutExchange fanoutExchange 此处参数名称要与方法名称一致,
* 通过spring bean id 去找对象
*/
@Bean
Binding bindingExchangeEamil(Queue fanoutEmailQueue, FanoutExchange fanoutExchange) {
return BindingBuilder.bind(fanoutEmailQueue).to(fanoutExchange);
}
/**
* 4.短信队列与交换机绑定
*/
@Bean
Binding bindingExchangeSms(Queue fanoutSmsQueue, FanoutExchange fanoutExchange) {
return BindingBuilder.bind(fanoutSmsQueue).to(fanoutExchange);
}
}
5.生产者
package com.google.producer;
import com.alibaba.fastjson.JSONObject;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.UUID;
/**
* @author wk
* @Description:SrpingBoot整合RabbitMQ发布订阅模式-生产者
* @date 2019/12/12 16:32
**/
@Service
public class FanoutProducer {
@Autowired
private AmqpTemplate amqpTemplate;
/**
* 生产者发送消息
*
* @param queueName
*/
public void send(String queueName) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("email", "1357760345@qq.com");
jsonObject.put("content", "SpringBoot整合RabbitMQ");
jsonObject.put("timestamp", System.currentTimeMillis());
amqpTemplate.convertAndSend(queueName, jsonObject.toJSONString());
}
/**
* 生产者发送短信
*
* @param queueName
*/
public void sendSms(String queueName, Integer i) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("sms", "1357760345@qq.com");
jsonObject.put("content", "SpringBoot整合RabbitMQ");
jsonObject.put("timestamp", System.currentTimeMillis());
jsonObject.put("number", i);
//生产者发送消息,需要设置消息ID
Message message = MessageBuilder.withBody(jsonObject.toJSONString().getBytes()).setContentType(MessageProperties.CONTENT_TYPE_JSON)
.setContentEncoding("UTF-8").setMessageId(UUID.randomUUID() + "").build();
amqpTemplate.convertAndSend(queueName, message);
}
}
调用Controller
package com.google.controller;
import com.google.producer.FanoutProducer;
import com.google.util.ParamUtil;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Date;
/**
* @author wk
* @Description:
* @date 2019/12/12 16:45
**/
@RestController
public class FanoutProducerController {
@Autowired
private FanoutProducer fanoutProducer;
@RequestMapping(value = "/sendMessage")
public String sendMessage(String queueName,Integer i) {
if (StringUtils.isBlank(queueName)) {
return "queueName参数非法";
}
if (queueName.contains("SMS")) {
fanoutProducer.sendSms(queueName,i);
} else {
fanoutProducer.send(queueName);
}
return "fanout发送成功!" + ParamUtil.dateConvertString(new Date(), "yyyyMMddHHmmssSSS");
}
}
(另建一个服务)消费者代码:
当前采用自动应答
配置文件:
spring:
rabbitmq:
host: 127.0.0.1
port: 5672
username: root
password: 1234
virtual-host: /wk_virtual_hosts
# 修改重试策略
listener:
simple:
retry:
####开启消费者重试 (程序出现异常的情况下会)进行重试
enabled: true
####最大重试次数
max-attempts: 5
####重试间隔次数
initial-interval: 10000
#(应答模式)开启手动ack manual auto
acknowledge-mode: auto
#数据库连接信息
datasource:
name: test
url: jdbc:mysql://127.0.0.1:3306/kzone?useUnicode=true&characterEncoding=utf8&autoReconnect=true&rewriteBatchedStatements=TRUE&useSSL=false
username: root
password: 1234
# 使用druid数据源
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.jdbc.Driver
server:
port: 2121
# 关闭eureka注册发现
eureka.client.register-with-eureka: false
eureka.client.fetch-registry: false
emailUrl: http://127.0.0.1:8888/sendEmail
smsUrl: http://127.0.0.1:8888/sendSms
package com.google.msg.email;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
/**
* @author wk
* @Description:
* @date 2019/12/12 17:02
**/
@Component
@RabbitListener(queues = "FANOUT_EMAIL_QUEUE")
public class FanoutEmailConsumer {
/**
* @RabbitHandler 自动接收应答
* @param msg
*/
@RabbitHandler
public void process(String msg) {
System.out.println("FanoutEmailConsumer获取消息:" + msg);
}
}
package com.google.msg.sms;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
/**
* @author wk
* @Description:
* @date 2019/12/12 17:03
**/
@Component
@RabbitListener(queues = "FANOUT_SMS_QUEUE")
public class FanoutSmsConsumer {
@RabbitHandler
public void process(String msg) {
System.out.println("FanoutSmsConsumer获取消息:" + msg);
}
}
springboot启动类就不写了。
注:若生产者服务,没有消费者对应的队列,消费者启动会报错
Total代表队列中的消息总条数,Ready代表消费者还可以读到的条数,Unacked:代表还有多少条没有被应答