springboot + rabbitmq 整合示例
几个概念说明:
Broker:简单来说就是消息队列服务器实体。
Exchange:消息交换机,它指定消息按什么规则,路由到哪个队列。
Queue:消息队列载体,每个消息都会被投入到一个或多个队列。
Binding:绑定,它的作用就是把exchange和queue按照路由规则绑定起来。
Routing Key:路由关键字,exchange根据这个关键字进行消息投递。
vhost:虚拟主机,一个broker里可以开设多个vhost,用作不同用户的权限分离。
producer:消息生产者,就是投递消息的程序。
consumer:消息消费者,就是接受消息的程序。
channel:消息通道,在客户端的每个连接里,可建立多个channel,每个channel代表一个会话任务。
交换机路由的几种类型:
Direct Exchange:直接匹配,通过Exchange名称+RountingKey来发送与接收消息.
Fanout Exchange:广播订阅,向所有的消费者发布消息,但是只有消费者将队列绑定到该路由器才能收到消息,忽略Routing Key.
Topic Exchange:主题匹配订阅,这里的主题指的是RoutingKey,RoutingKey可以采用通配符,如:*或#,RoutingKey命名采用.来分隔多个词,只有消息这将队列绑定到该路由器且指定RoutingKey符合匹配规则时才能收到消息;
Headers Exchange:消息头订阅,消息发布前,为消息定义一个或多个键值对的消息头,然后消费者接收消息同时需要定义类似的键值对请求头:(如:x-mactch=all或者x_match=any),只有请求头与消息头匹配,才能接收消息,忽略RoutingKey.
默认的exchange:如果用空字符串去声明一个exchange,那么系统就会使用”amq.direct”这个exchange,我们创建一个queue时,默认的都会有一个和新建queue同名的routingKey绑定到这个默认的exchange上去
安装Erland
http://www.erlang.org/downloads
安装RabbitMQ
https://www.rabbitmq.com/download.html
开启RabbitMQ服务
执行rabbitmq-plugins enable rabbitmq_management命令,开启Web管理插件
重启RabbitMQ服务
Web地址
http://localhost:15672/
默认用户名和密码:guest
一、引入springboot和rabbitmq的依赖
<!-- 添加springboot对amqp的支持 -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.0</version>
</dependency>
二、新增application.properties对rabbimq的配置信息
spring.application.name=springboot-rabbitmq
spring.rabbitmq.host=116.255.193.36
spring.rabbitmq.port=5672
spring.rabbitmq.username=scrm
spring.rabbitmq.password=scrm
spring.rabbitmq.publisher-confirms=true
spring.rabbitmq.publisher-returns=true
spring.rabbitmq.virtual-host=scrm
spring.rabbitmq.listener.simple.acknowledge-mode=manual
#最小消息监听线程数
spring.rabbitmq.listener.concurrency=2
#最大消息监听线程数
spring.rabbitmq.listener.max-concurrency=2
三、公共设置类
1、队列、消息交换机,路由关键字公共枚举类
package cloud.app.prod.home.rabbitmq; /**
* Author : YongBo Xie </br>
* File Name: RabbitMqEnum.java </br>
* Created Date: 2018年3月28日 上午10:32:02 </br>
* Modified Date: 2018年3月28日 上午10:32:02 </br>
* Version: 1.0 </br>
*/ public class RabbitMqEnum { /**
* describe: 定义队列名称
**/
public enum QueueName {
MARKETING_ACTIVITIE_QUEUE("marketingActivitieQueue", "营销活动队列"); private String code;
private String name; QueueName(String code, String name) {
this.code = code;
this.name = name;
} public String getCode() {
return code;
} public String getName() {
return name;
} } /**
* describe: 定义交换机
**/
public enum Exchange {
DIRECT_EXCHANGE("directExchange", "直连交换机"),
FANOUT_EXCHANGE("fanoutExchange", "扇形交换机"),
TOPIC_EXCHANGE("topicExchange", "主题交换机"),
HEADERS_EXCHANGE("headersExchange", "首部交换机"); private String code;
private String name; Exchange(String code, String name) {
this.code = code;
this.name = name;
} public String getCode() {
return code;
} public String getName() {
return name;
} } /**
* describe: 定义routing_key
**/
public enum QueueKey {
MARKETING_ACTIVITIE_DIRECT("marketingActivitie", "营销活动key"),
MARKETING_ACTIVITIE_TOPIC_01("*.marketingActivitie.*", "营销活动key"),
MARKETING_ACTIVITIE_TOPIC_02("marketingActivitie.#", "营销活动key"); private String code;
private String name; QueueKey(String code, String name) {
this.code = code;
this.name = name;
} public String getCode() {
return code;
} public String getName() {
return name;
}
} }
2、数据连接配置类
package cloud.app.prod.home.rabbitmq; import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; /**
* Author : YongBo Xie </br>
* File Name: RabbitConfig.java </br>
* Created Date: 2018年3月28日 下午6:41:17 </br>
* Modified Date: 2018年3月28日 下午6:41:17 </br>
* Version: 1.0 </br>
*/
@Configuration
@ConfigurationProperties(prefix = "spring.rabbitmq")
public class RabbitConfig { @Value("${spring.rabbitmq.host}")
private String addresses;
@Value("${spring.rabbitmq.port}")
private int port;
@Value("${spring.rabbitmq.username}")
private String username;
@Value("${spring.rabbitmq.password}")
private String password;
@Value("${spring.rabbitmq.publisher-confirms}")
private Boolean publisherConfirms;
@Value("${spring.rabbitmq.publisher-returns}")
private Boolean publisherReturns;
@Value("${spring.rabbitmq.virtual-host}")
private String virtualHost; // 构建mq实例工厂
@Bean
public ConnectionFactory connectionFactory() {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
connectionFactory.setAddresses(addresses);
connectionFactory.setPort(port);
connectionFactory.setUsername(username);
connectionFactory.setPassword(password);
connectionFactory.setPublisherConfirms(publisherConfirms);
connectionFactory.setVirtualHost(virtualHost);
connectionFactory.setPublisherReturns(publisherReturns);
return connectionFactory;
} }
3、生产者类
package cloud.app.prod.home.rabbitmq; import org.apache.log4j.Logger;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.core.RabbitTemplate.ConfirmCallback;
import org.springframework.amqp.rabbit.core.RabbitTemplate.ReturnCallback;
import org.springframework.amqp.rabbit.support.CorrelationData;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component; /**
* Author : YongBo Xie </br>
* File Name: RabbitMqSender.java </br>
* Created Date: 2018年3月30日 上午10:48:36 </br>
* Modified Date: 2018年3月30日 上午10:48:36 </br>
* Version: 1.0 </br>
*/
@Component
public class RabbitMqSender { private static Logger logger = Logger.getLogger(RabbitMqSender.class); @Bean
public RabbitTemplate messageRabbitTemplate(ConnectionFactory connectionFactory) {
final RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
rabbitTemplate.setConfirmCallback(new ConfirmCallback() { /**
* 回调
* @param correlationData 消息唯一标识
* @param ack 确认结果
* @param cause 失败原因
*/
@Override
public void confirm(CorrelationData correlationData, boolean ack, String cause) {
logger.info("消息唯一标识:"+correlationData);
logger.info("确认结果:"+ack);
logger.info("失败原因:"+cause);
}
}); rabbitTemplate.setReturnCallback(new ReturnCallback() { /**
* 用于实现消息发送到RabbitMQ交换器,但无相应队列与交换器绑定时的回调
*/
@Override
public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
logger.info(message.getMessageProperties().getCorrelationIdString() + " 发送失败");
}
}); return rabbitTemplate;
} }
四、个例
1、初始化队列、消息交换机,并把队列绑定到消息交换机
package cloud.app.prod.home.rabbitmq.mem; import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.FanoutExchange;
import org.springframework.amqp.core.HeadersExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import cloud.app.prod.home.rabbitmq.RabbitMqEnum; /**
* Author : YongBo Xie </br>
* File Name: RabbitConfig.java </br>
* Created Date: 2018年3月27日 下午3:13:57 </br>
* Modified Date: 2018年3月27日 下午3:13:57 </br>
* Version: 1.0 </br>
*/
@Configuration
public class MarketingActivitieRabbitConfig { // private static Logger logger = Logger.getLogger(MarketingActivitieRabbitConfig.class); /**
* 构建队列,名称,是否持久化之类
* @return
*/
@Bean
public Queue marketingActivitieQueue() {
return new Queue(RabbitMqEnum.QueueName.MARKETING_ACTIVITIE_QUEUE.getCode(), true);
} /**
* 直连交换机(模式)
* 用于实例间的任务分发
* 是一种带路由功能的交换机,一个队列会和一个交换机绑定,除此之外再绑定一个routing_key
*/
@Bean
public DirectExchange createDirectExchange() {
return new DirectExchange(RabbitMqEnum.Exchange.DIRECT_EXCHANGE.getCode());
} /**
* 扇形交换机(模式)
* 分发给所有绑定到该exchange上的队列,忽略routing key
* 速度是所有的交换机类型里面最快的
*/
@Bean
public FanoutExchange createFanoutExchange() {
return new FanoutExchange(RabbitMqEnum.Exchange.FANOUT_EXCHANGE.getCode());
} /**
* 主题交换机(模式)
* 通过可配置的规则分发给绑定在该exchange上的队列
* 发送到主题交换机上的消息需要携带指定规则的routing_key
* 交换机和队列的binding_key需要采用*.#.*.....的格式,每个部分用.分开
* *表示一个单词
* #表示任意数量(零个或多个)单词
*/
@Bean
public TopicExchange createTopicExchange() {
return new TopicExchange(RabbitMqEnum.Exchange.TOPIC_EXCHANGE.getCode());
} /**
* 首部交换机(模式)
* 适用规则复杂的分发,用headers里的参数表达规则,有点像HTTP的Headers
* 绑定交换机和队列的时候,Hash结构中要求携带一个键“x-match”,这个键的Value可以是any或者all,
* 这代表消息携带的Hash是需要全部匹配(all),还是仅匹配一个键(any)就可以了
*/
@Bean
public HeadersExchange createHeadersExchange() {
return new HeadersExchange(RabbitMqEnum.Exchange.HEADERS_EXCHANGE.getCode());
} /**
* 队列和直连交换机绑定
* @param queue
* @param routingKey
* @return
*/
@Bean
public Binding bindingQueueWithDirectExchange() {
return BindingBuilder.bind(marketingActivitieQueue()).to(createDirectExchange())
.with(RabbitMqEnum.QueueKey.MARKETING_ACTIVITIE_DIRECT.getCode());
} /**
* 队列和扇形交换机绑定
* @param queue
* @return
*/
@Bean
public Binding bindingQueueWithFanoutExchange() {
return BindingBuilder.bind(marketingActivitieQueue()).to(createFanoutExchange());
} /**
* 队列和主题交换机绑定
* @param queue
* @param routingKey
* @return
*/
@Bean
public Binding bindingQueueWithTopicExchange() {
return BindingBuilder.bind(marketingActivitieQueue()).to(createTopicExchange())
.with(RabbitMqEnum.QueueKey.MARKETING_ACTIVITIE_TOPIC_01.getCode());
} /**
* 队列和首部交换机绑定
* key和value匹配
* @param queue
* @param key
* @param value
* @return
*/
// @Bean
// public Binding bindingQueueWithHeadersExchange() {
// return BindingBuilder.bind(marketingActivitieQueue()).to(createHeadersExchange())
// .where(RabbitMqEnum.QueueKey.MARKETING_ACTIVITIE_HEADERS.getCode())
// .matches(RabbitMqEnum.QueueKey.MARKETING_ACTIVITIE_HEADERS.getName());
// } /**
* 队列和首部交换机绑定(x-match : all)
* 完全匹配
* @param queue
* @param headerValues
* @return
*/
// @Bean
// public Binding bindingQueueWithHeadersExchangeAll(Map<String, Object> headerValues) {
// return BindingBuilder.bind(marketingActivitieQueue()).to(createHeadersExchange()).whereAll(headerValues).match();
// } /**
* 队列和首部交换机绑定(x-match : all)
* 任一匹配
* @param queue
* @param headerValues
* @return
*/
// @Bean
// public Binding bindingQueueWithHeadersExchangeAny(Map<String, Object> headerValues) {
// return BindingBuilder.bind(marketingActivitieQueue()).to(createHeadersExchange()).whereAny(headerValues).match();
// }
}
2、生产者
package cloud.app.prod.home.rabbitmq.mem; import org.apache.log4j.Logger;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.support.CorrelationData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import cloud.app.prod.home.common.FailException;
import cloud.app.prod.home.mem.vo.MarketingActivitiesVO;
import cloud.app.prod.home.rabbitmq.RabbitMqEnum;
import cloud.app.prod.home.utils.DSHUtils; /**
* Author : YongBo Xie </br>
* File Name: MarketingActivitieRabbitMqSender.java </br>
* Created Date: 2018年3月28日 下午2:16:32 </br>
* Modified Date: 2018年3月28日 下午2:16:32 </br>
* Version: 1.0 </br>
*/
@Component
public class MarketingActivitieRabbitMqSender { private static Logger logger = Logger.getLogger(MarketingActivitieRabbitMqSender.class); @Autowired
private RabbitTemplate rabbitTemplate; /**
* 发送消息
* rabbitTemplate.send(message); //发消息,参数类型为org.springframework.amqp.core.Message
* rabbitTemplate.convertAndSend(object); //转换并发送消息。 将参数对象转换为org.springframework.amqp.core.Message后发送
* rabbitTemplate.convertSendAndReceive(message) //转换并发送消息,且等待消息者返回响应消息
* 针对业务场景选择合适的消息发送方式即可
* @param obj
* @throws FailException
*/
public void sendRabbitmqDirect(MarketingActivitiesVO marketingActivitiesVO) throws FailException {
CorrelationData correlationData = new CorrelationData(DSHUtils.generateUUID());
logger.info("send: " + correlationData.getId());
rabbitTemplate.convertAndSend(RabbitMqEnum.Exchange.DIRECT_EXCHANGE.getCode(), RabbitMqEnum.QueueKey.MARKETING_ACTIVITIE_DIRECT.getCode() , marketingActivitiesVO, correlationData);
} public void sendRabbitmqDirect(String exchange, String routingKey, Object obj) throws FailException {
CorrelationData correlationData = new CorrelationData(DSHUtils.generateUUID());
logger.info("send: " + correlationData.getId());
rabbitTemplate.convertAndSend(exchange, routingKey, obj);
} }
3、消费者
package cloud.app.prod.home.rabbitmq.mem; import org.apache.log4j.Logger;
import org.springframework.amqp.core.AcknowledgeMode;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.ChannelAwareMessageListener;
import org.springframework.amqp.rabbit.listener.MessageListenerContainer;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component; import com.rabbitmq.client.Channel; import cloud.app.prod.home.rabbitmq.RabbitMqEnum; /**
* Author : YongBo Xie </br>
* File Name: MarketingActivitieRabbitMqReceiver.java </br>
* Created Date: 2018年3月28日 下午3:14:58 </br>
* Modified Date: 2018年3月28日 下午3:14:58 </br>
* Version: 1.0 </br>
*/
@Component
public class MarketingActivitieRabbitMqReceiver { private static Logger logger = Logger.getLogger(MarketingActivitieRabbitMqReceiver.class); @Bean
public MessageListenerContainer messageListenerContainer(ConnectionFactory connectionFactory) {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
container.setQueueNames(RabbitMqEnum.QueueName.MARKETING_ACTIVITIE_QUEUE.getCode());
container.setMessageListener(messageListener());
container.setAcknowledgeMode(AcknowledgeMode.MANUAL); //设置为手动
return container;
} // @RabbitListener(queues = "marketingActivitieQueue")
// @RabbitHandler
// public void process(String msg) {
// logger.info(Thread.currentThread().getName() + " 接收到来自marketingActivitieQueue队列的消息:" + msg);
// } @Bean
public ChannelAwareMessageListener messageListener() {
return new ChannelAwareMessageListener() {
@Override
public void onMessage(Message message, Channel channel) throws Exception {
channel.confirmSelect();//在设置消息被消费的回调前需显示调用,否则回调函数无法调用
if (message.toString().indexOf("1") > 0){
logger.info(Thread.currentThread().getName() + " 接收到来自marketingActivitieQueue队列的消息1:" + message.toString());
channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
} if (message.toString().indexOf("2") > 0){
logger.info(Thread.currentThread().getName() + " 接收到来自marketingActivitieQueue队列的消息2:" + message.toString()); //被拒绝的是否重新入队列
//channel.basicNack 与 channel.basicReject 的区别在于basicNack可以拒绝多条消息,而basicReject一次只能拒绝一条消息
// channel.basicNack(message.getMessageProperties().getDeliveryTag(),false,true);
channel.basicReject(message.getMessageProperties().getDeliveryTag(),false);
}
logger.info(Thread.currentThread().getName() + " 接收到来自marketingActivitieQueue队列的消息3:" + message.toString());
}
};
} }
springboot + rabbitmq 整合示例的更多相关文章
- springboot+rabbitmq整合示例程
关于什么是rabbitmq,请看另一篇文: http://www.cnblogs.com/boshen-hzb/p/6840064.html 一.新建maven工程:springboot-rabbit ...
- SpringBoot RabbitMQ 整合使用
![](http://ww2.sinaimg.cn/large/006tNc79ly1g5jjb62t88j30u00gwdi2.jpg) ### 前提 上次写了篇文章,[<SpringBoot ...
- springboot rabbitmq整合
这一篇我们来把消息中间件整合到springboot中 ===================================================================== 首先在 ...
- SpringBoot与PageHelper的整合示例详解
SpringBoot与PageHelper的整合示例详解 1.PageHelper简介 PageHelper官网地址: https://pagehelper.github.io/ 摘要: com.gi ...
- 消息中间件——RabbitMQ(十)RabbitMQ整合SpringBoot实战!(全)
前言 1. SpringBoot整合配置详解 publisher-confirms,实现一个监听器用于监听Broker端给我们返回的确认请求:RabbitTemplate.ConfirmCallbac ...
- SpringBoot Kafka 整合集成 示例教程
1.使用IDEA新建工程,创建工程 springboot-kafka-producer 工程pom.xml文件添加如下依赖: <!-- 添加 kafka 依赖 --> <depend ...
- 带着新人学springboot的应用07(springboot+RabbitMQ 下)
说一两句废话,强烈推荐各位小伙伴空闲时候也可以写写自己的博客!不管水平高低,不管写的怎么样,不要觉得写不好或者水平不够就不写了(咳,我以前就是这样的想法...自我反省!). 但是开始写博客之后,你会发 ...
- 带着新人学springboot的应用06(springboot+RabbitMQ 中)
上一节说了这么多废话,看也看烦了,现在我们就来用鼠标点点点,来简单玩一下这个RabbitMQ. 注意:这一节还是不用敲什么代码,因为上一节我们设置了那个可视化工具,我们先用用可视化工具熟悉一下流程. ...
- SpringBoot之整合Mybatis(增,改,删)
一,在上一篇文章SpringBoot之整合Mybatis中,我们使用spring boot整合了Mybatis,并演示了查询操作.接下来我们将完善这个示例,增加增,删,改的功能. 二,改动代码 1.修 ...
随机推荐
- NHibernate系列学习(三)-条件查询Criteria
1.本笔记主要介绍Criteria的使用 2.效果界面 3.代码详情 namespace KimismeDemo { public partial class Form3 : Form { priva ...
- [Codeforces]Codeforces Round #489 (Div. 2)
Nastya and an Array 输出有几种不同的数字 #pragma comment(linker, "/STACK:102400000,102400000") #ifnd ...
- 元素属性的添加删除(原生js)
添加属性 odiv.setAttribute("title","hello div!"); odiv.setAttribute("class" ...
- [转]深入理解/proc目录
Linux系统上的/proc目录是一种文件系统,即proc文件系统.与其它常见的文件系统不同的是,/proc是一种伪文件系统(也即虚拟文件系统),存储的是当前内核运行状态的一系列特殊文件,用户可以通过 ...
- html5——盒子模式
box-sizing属性 box-sizing: border-box;/*内减模式*/ box-sizing: content-box;/*外加模式(默认值)*/ box-sizing: paddi ...
- [Windows Server 2012] PHPWind安全设置
★ 欢迎来到[护卫神·V课堂],网站地址:http://v.huweishen.com★[护卫神·V课堂]是护卫神旗下专业提供服务器教学视频的网站,每周更新视频. ★ 本节我们将带领大家:PHPWin ...
- AjaxDemo
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...
- c# winform中使用WebKit实现网页与winform的交互
1.工作 一年多了,一直没对自己在工作遇到的问题进行总结,每次遇到问题都要在网上找资料,导致完成项目之后,时间久了就会生疏.所以下定 决定总结自己在工作中遇到的各种问题. 进入正题:第一次写还请大神多 ...
- Codeforces Round #468 Div. 2题解
A. Friends Meeting time limit per test 1 second memory limit per test 256 megabytes input standard i ...
- 学习记录--如何将exec执行结果放入变量中?
declare @num int, ) set @sqls='select @a=count(*) from tb ' exec sp_executesql @sqls,N'@a int output ...