RabbitMQ是由erlang语言开发,基于AMOP(Advanced Message Queue高级消息队列) 协议实现的消息队列,它是一种应用程序之间的通信发方法。
MQ的作用:
1把同步操作变成异步操作
2解耦合
AMOP协议:是一套专门公开的消息中间件的协议。
市场上还有哪些消息队列:
ActiveMQ RabbitMQ ZeroMQ Kalfaf MetaMQ RocketMQ Redis.
为什么使用RabbitMQ?
1 使用简单,文档完善
2 基于AMOP协议
3 社区活跃,文档完善
4 高并发性能好,这主要得益于Erlang语言
5 Spring Boot默认已经集成RabbitMQ
JMS:
java消息服务
java消息服务应用程序接口是一个java平台中关于面向消息中间件(MOM)的API,用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信。java消息服务与具体平台无关的API,绝大多数MOM厂商都对JMS提供支持。
RabbitMQ的工作原理:
大致流程:
由生产者Producer将消息通过交换机(Exchange)转发到Queue,消费者(Consumer)会监听队列(Queue)一旦有消息,就会去消费,如果消费者还没有能监听到Queue则Queue继续等待消费者(Consumer)来消费。
消息发布接受流程:
发送消息:
1 生产者和Broker建立TCP连接
2 生产者和Broker建立通道(会话通道)
3 生产者通过通道消息发送到Broler,有Exchange将消息进行转发
4 Exchange将消息发送到指定Queue(队列)
接受消息:
1 消费者和Broker建立TCP连接
2 消费者和Broker建立通道
3 消费者监听指定的Queue(队列)
4 当有消息到达Queue时Broker默认将消息推送给消费者
5 消费者接收到消息
安装RabbitMQ的下载:
1 先下载erlang语言环境
2 下载地址:http://www.rabbitmq.com/download.htl
下载安装与安装:
1 首先先安装erlang语言的环境:http://erlang.org/download/otp_win64_20.3.exe并配置环境变量。
2 安装RabbitMQ:https://github.com/rabbitmq/rabbitmq-server/releases/tag/v3.7.3
以管理员的方式在,sbin目录下安装管理插件:rabbitmq-plugins.bat enable rabbitmq_management
浏览器启动:http://localhost:15672
默认登录用户名和密码都是:guest
出现如下画面,则表示安装成功
注意事项:
当卸载RabbitMQ重新安装出现RabbitMQ服务注册失败,此时需要进入注册表清理erlang,搜索RabbitMQ. ErlSrv,将对应的项全部删除。
RabbitMQ入门程序:
1 生产者:
channel.queueDeclare()
这里面的参数的说明:
参数说明:
1 queue队列名称
2 durable 是否持久化,如果持久化,mq重启后队列
3 exclusive: 是否独占连接,队列只允许在连接访问,如果connection连接关闭队列自动删除,如果将此参数设置true可用于临时队列的创建
4 autoDelete自动删除,队列不再使用时是否自动删除此队列,如果将此参数和exclusive参数设置为true就可以实现临时队列(队列不用了就自动删除)
5 arguments参数,可以设置一个队列的扩展参数,比如:可设置存活时间.
//生产者代码:
public class Producer{
private static finally String quque="hello1" //队列的名称
public static void main(){
//通过连接工厂创建新的连接和mq建立连接
ConnectionFactory connectionFactory =new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort("5672");
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
//设置虚拟机,一个mq服务可以设置多个虚拟机,每个虚拟机就相当于一个独立的mq
connectionFactory.setVirtunaHost("/");
try{
connection=connectionFactory.newConnection();
//设置创建会话通道,生产者和mq服务所有的服务都在channel通道中完成
Channel channel=connection.createChannel();
//不用声明交换机默认有
//声明队列,如果队列在mq中没有就创建一个
channel.queueDeclare();
//发送消息
//参数说明:1 exchange:交换机设置为空(""),如果不指定将使用mq的默认交换机
2 //rountingKey, 路由key,交换机根据路由Key来将消息转发到指定的队列,如果使用默认交换机,rountingKey设置为队列的名称
3 //消息的属性
4//消息的信息
channel.basicPublish("",QUEUE,null,message.getBytes());
}catch(){
}finally{
//先关闭通道
channel.close();
//再关闭连接
connection.close();
}
}
}
大致流程总结:
1 发送端操纵流程:
1)创建连接
2)创建通道
3声明队列
4)发送消息.
消费者:
//消费者
private static finally String quque="hello1" //队列的名称
public static void main(){
//通过连接工厂创建新的连接和mq建立连接
ConnectionFactory connectionFactory =new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort("5672");
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
//设置虚拟机,一个mq服务可以设置多个虚拟机,每个虚拟机就相当于一个独立的mq
connectionFactory.setVirtunaHost("/");
try{
connection=connectionFactory.newConnection();
//设置创建会话通道,生产者和mq服务所有的服务都在channel通道中完成
Channel channel=connection.createChannel();
//不用声明交换机默认有
//声明队列,如果队列在mq中没有就创建一个
channel.queueDeclare(QUEUE,true,false,false,null);
//实现消费方法
DefaultConsumer defaultConsumer=new DefaultConfumer(channel){
//当接收到消息后此方法将被调用
@Param ConsumerTag: 消费者标签,用来标识消费者的,在监听队列时设置channel,basicConsume
@Param envelope: 信封,通过envelope,通过envelope可以在获取消息Id,mq在channel中用来标示消费的Id。
public void handleDeliver(String consumerTag,Envelope envelope,AMQP.BasicProperties properties,byte[] body)throw IOException{
//交换机
String exchange=envelope.getExchange();
//消息id,mq在channel中用来标识消费的Id,可用于确认消息已接收
long deliverTag=envelope.getDeliveryTag();
//消息内容
String message=new String(body,""utf-8");
System.out.println(message); //打印消息
}
}
//实现消费方
//监听队列
//参数:String queue, boolean autoAck,Consumer callback
//参数明细:
1 queue 队列名称
2 autoAck 自动回复,当消费方接受到消息后要告诉mq消息已接收,如果将此参数设置为true表示自动回复mq,如果设置为false要通过编程实现回复
3 callback:消费方法;当消费者接受到消息要执行的方法
channel.basiConsume(QUEUE,true,defaultConsumer)
消费者不能关闭:因为消费者要不停的监听。
接收端:
1)创建连接
2)创建通道
3)声明队列
4)监听队列
5 )接受消息
6) ack回复(自动回复,如果设置了fasle就使用编程的方式写一个回复)
RabbitMQ工作模式:
(Work queues) 工作队列模式:
一个生产者+一个队列+多个消费者
它的特点:
一个生产者将消息发给发给一个队列
多个消费者共同监听一个队列的消息
消息不能重复消费
rabbit采用轮询的方式将消息是平均发送给消费者
应用场景: 多个消费者协同来工作。
Publish/Subscribe:发布与订阅模式
特点:生产者发布一条消息,可以被多个消费者接收到。
案例:
用户通知,当用户充值成功或转账完成系统通知用户,通知方式有短信,邮件等多种方式.
//在之前的代码中,加入:
新的变化:
private static final String QUEUE_INFORM_EMAIL="queue_inform_email";
private static final String QUEUE_INFORM_SMS="queue_inform_sms";
private static final String EXCBANE_FANOUT_INFORM="exchange_fanout_inform"; //交换机的名字
//声明邮件队列
channel.queueDeclare(QUEUE_INFORM_EMAIL,true,false,false,null);
channel.queueDeclare(QUEUE_INFORM_SMS,true,fasle,false,null);
//声明交换机
交换机的工作模式有
参数:
1 交换机的名称
2 交换机的类型:
1 交换机的名称
2 交换机的类型
3 fanout:对应的rabbitmq的工作模式是 publish/subscribe
4 direct: 路由的工作模式
5 通配符工作模式
6 headers:对应的headers工作模式
6 rpc远程调用
channel.exchangeDeclare(EXBANE_FANOUT_INFORM,BuiltinExchangeType.FANOUT);
进行交换机和队列绑定
//参数的明细: String queue,String exchange,String routingKey
1 queue队列的名称 2 exchange 交换机名称 3 routingKey 路由key,作用是交换机根据路由key的值将消息转发到指定的队列中,在发布订阅模式中调协为空字符串
channel.queueBind(QUEUE_INFOREM_EMAIL,EXCHANGE_FANOUT_INFORM,"');
发布消息:
for(int i=0;i<5;i++){
//消息内容
String message="send inform message to user";
channel.basicPublish(EXCHANGE_FANOUT_INFORM,"",null,message.getBytes());
}
Routind路由模式:
可以通过指定路由的条件,来分发消息,它也可以实现发布与订阅模式。同时它的功能更加强大。
路由工作模式代码示例:
//由上面的代码加以修改即可,在声明上加上ROUTINGKEY(路由Key)
private static final String ROUTINGKEY_EMAIL="inform_eamail";
private static final String ROUNTINGKEY_SMS="inform_sms";
//队列在绑定交换机的时候要指定对应的ROUNTKEY:
channel.queueBind(QUEUE_INFORM_EMAIL,EXCHANGE_ROUNTING_INFORM,ROUTINGKE_EMAIL);
channel.queueBind(QUEUE_INFORM_SMS,EXCHANGE_ROUNTING_INFORM,ROUNTINGKEY_SMS);
//声明交换机时,交换机的类型要改成DIRECT类型
channel.excahngeDeclare(EXCHANGE_ROUTING_INFORM,BuiltinExchangeType.DIRECT);
//发消息:在发消息的时候,需要指定ROUNTINGKEY
channel.basicPublish(EXCHANGE_ROUTING_INFORM,ROUNTINGKEY_EMAIL,null,message.getBytes());
Topics通配符模式:
通配符交换机的类型要设置成type=topic ,
通配符有哪些:
符号#:匹配一个或多个词,比如inform.#可以匹配inform.sms,inform.email,inform.email.sms
符号*:只能匹配一个词,比如:inform.* 可以匹配inform.sms,inform.email
案例:根据用户的通知设置去通知用户,有的用户
实列代码:
//在路由模式的基础上稍微做改变
private static final String ROUTINGKEY_EMAIL="inform.#.email.#"; //这个路由key可以匹配inform.email,也可以匹配inform.email.sms
private static final String ROUTINGKEY_SMS="inform.#.sms.#"; //可以匹配inform.email.sms,也可以匹配inform.sms
//绑定交换机和队列
//声明交换机
channel.exchangeDeclare(EXCHANGE_TOPICS_INFORM,BuiltingExchangeType.TOPIC);
channel.queueBind(QUEUE_INFORM_EMAIL,EXCHANCE_TOPICS_INFORM,ROUTINGKEY_EMAIL);
channel.queueBind(QUEUE_INFORM_EMAIL,EXCHANCE_TOPICS_INFORM,ROUTINGKEY_SMS);
发消息:
Header模式:
header模式与rounting不同的地方在于,head模式取消rountingkey,使用header的key/value(键值对)匹配队列
发送消息:
RPC模式:
SpringBoot整合RabbitMQ:
首先导入依赖:
在生产者和消费者分别加上下面的依赖:
添加配置文件:日志的文件和application.yml
application.yml内容是:
在RabbitMQ工程下,创建一个配置类,用来声明交换机,声明队列,绑定交换机和队列
代码示例如下:
绑定emil队列和交换机
生产端的代码:
使用rabbitTemplate发送消息:
消费端代码示例:
首先和生产者一样,创建一配置类,来声明队列交换机,并绑定队列和交换机
创建一个ReceiveHandler用来接收消息并处理,使用@RabbitListener注解监听队列: