Maven写rabbitMQ教程
提示:如果有不知道rabbitMQ的朋友建议先去看看相关教程
先上一个RabbitMQ的工作原理图
组成部分说明如下:
Broker:消息队列服务进程,此进程包括两个部分:Exchange和Queue。
Exchange:消息队列交换机,按一定的规则将消息路由转发到某个队列,对消息进行过虑
Queue:消息队列,存储消息的队列,消息到达队列并转发给指定的消费方。
Producer:消息生产者,即生产方客户端,生产方客户端将消息发送到MQ。
Consumer:消息消费者,即消费方客户端,接收MQ转发的消息。
消息发布接收流程:
-----发送消息-----
1、生产者和Broker建立TCP连接。
2、生产者和Broker建立通道。
3、生产者通过通道消息发送给Broker,由Exchange将消息进行转发。
4、Exchange将消息转发到指定的Queue(队列)
----接收消息-----
1、消费者和Broker建立TCP连接
2、消费者和Broker建立通道
3、消费者监听指定的Queue(队列)
4、当有消息到达Queue时Broker默认将消息推送给消费者。
5、消费者接收到消息。
用maven项目书写rabbitMQ的思路:
一丶简单模式Hello World
功能:一个生产者P发送消息到队列Q,一个消费者C接收
1.先引入jar包导入相关的依赖;
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
</dependency>
2.创建两个项目,一个提供者和一个消费者
3.在测试类里面写代码
先上producer的代码
public class providucer01 {
private static final String QUEUE= "helloworld";
public static void main(String[] args) throws IOException, TimeoutException {
//创建connectionfactory
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("localhost");//设置
connectionFactory.setPort(5672);
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
connectionFactory.setVirtualHost("/");//rabbitmq默认虚拟机名称为“/”,虚拟机相当于一个独立的mq服务
//因为最后需要关闭连接所以定义到外面
Connection connection = null;
Channel channel = null;
try {
//通过connectionfactory获取connection
connection = connectionFactory.newConnection();
//获取Exchange通道
channel = connection.createChannel();
/**
*声明队列,如果Rabbit中没有此队列将自动创建
*param1:队列名称
*param2:是否持久化
*param3:队列是否独占此连接
*param4:队列不再使用时是否自动删除此队列
*param5:队列参数
*/
channel.queueDeclare(QUEUE,true,false,false,null);
//自定义消息
String massage = "helloMQ"+System.currentTimeMillis();
/**
*消息发布方法
*param1:Exchange的名称,如果没有指定,则使用Default Exchange
*param2:routingKey,消息的路由Key,是用于Exchange(交换机)将消息转发到指定的消息队列
*param3:消息包含的属性
*param4:消息体
*这里没有指定交换机,消息将发送给默认交换机,每个队列也会绑定那个默认的交换机,但是不能显 示绑定或解除绑定
*默认的交换机,routingKey等于队列名称
*/
channel.basicPublish("",QUEUE,null,massage.getBytes("utf-8"));
System.out.println("send massage: ----"+massage);
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}finally {
if(channel != null)
{
channel.close();
}
if(connection != null)
{
connection.close();
}
}
}
}
再上customer的代码
public class customer01 {
private static final String QUEUE = "helloworld";
public static void main(String[] args) throws IOException, TimeoutException {
//创建connectionfactory
ConnectionFactory factory = new ConnectionFactory();
//设置MabbitMQ所在服务器的ip和端口
factory.setHost("127.0.0.1");
factory.setPort(5672);
//获取connection
Connection connection = factory.newConnection();
//获取通道
Channel channel = connection.createChannel();
//声明队列
channel.queueDeclare(QUEUE, true, false, false, null);
//定义消费方法
DefaultConsumer consumer = new DefaultConsumer(channel) {
/**
*消费者接收消息调用此方法
*@param consumerTag 消费者的标签,在channel.basicConsume()去指定
*@param envelope 消息包的内容,可从中获取消息id,消息routingkey,交换机,消息和重传标志(收到消息失败后是否需要重新发送)
*@param properties
*@param body
*@throws IOException
**/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body)throws IOException {
//交换机
String exchange = envelope.getExchange();
//路由key
String routingKey = envelope.getRoutingKey();
//消息id
long deliveryTag = envelope.getDeliveryTag();
//消息内容
String msg = new String(body, "utf-8");
System.out.println("receive message:" + msg);
}
};
/**
*监听队列String queue, boolean autoAck,Consumer callback
*参数明细
*1、队列名称
*2、是否自动回复,设置为true为表示消息接收到自动向mq回复接收到了,mq接收到回复会删除消息,设置 为false则需要手动回复
*3、消费消息的方法,消费者接收到消息后调用此方法
*/
channel.basicConsume(QUEUE, false, consumer);
}}
总结:
1、发送端操作流程
1)创建连接
2)创建通道
3)声明队列
4)发送消息
2、接收端
1)创建连接
2)创建通道
3)声明队列
4)监听队列
5)接收消息
6)ack回复
二丶工作队列模式Work Queue
功能:一个生产者,多个消费者,每个消费者获取到的消息唯一,多个消费者只有一个队列
任务队列:避免立即做一个资源密集型任务,必须等待它完成,而是把这个任务安排到稍后再做。我们将任务封装为消息并将其发送给队列。后台运行的工作进程将弹出任务并最终执行作业。当有多个worker同时运行时,任务将在它们之间共享。应用场景:对于 任务过重或任务较多情况使用工作队列可以提高任务处理的速度。
思路:
work queues与入门程序相比,多了一个消费端,两个消费端共同消费同一个队列中的消息。
测试:
1、使用入门程序,把customer01copy一下启动多个消费者。
2、生产者发送多个消息。结果:
1、一条消息只会被一个消费者接收;
2、rabbit采用轮询的方式将消息是平均发送给消费者的;
3、消费者在处理完某条消息后,才会收到下一条消息。
三丶发布/订阅模式Publish/Subscribe
功能:一个生产者发送的消息会被多个消费者获取。一个生产者、一个交换机、多个队列、多个消费者
生产者:可以将消息发送到队列或者是交换机。
消费者:只能从队列中获取消息。
如果消息发送到没有队列绑定的交换机上,那么消息将丢失。
交换机不能存储消息,消息存储在队列中
代码可以想象成银行业务用户通知,当用户充值成功或转账完成系统通知用户,通知方式有短信、邮件多种方法 。
生产者:
声明Exchange_fanout_inform交换机。
声明两个队列并且绑定到此交换机,绑定时不需要指定routingkey 发送消息时不需要指定routingkey
代码如下:
public class providucer01 {
// private static final String QUEUE = "helloworld";
private static final String QUEUE_EMAIL = "queue_email";
private static final String QUEUE_SMS = "queue_sms";
private static final String EXCHANGEE_INFORM = "exchange_inform";
public static void main(String[] args) throws IOException, TimeoutException {
//创建connectionfactory
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("localhost");//设置
connectionFactory.setPort(5672);
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
connectionFactory.setVirtualHost("/");//rabbitmq默认虚拟机名称为“/”,虚拟机相当于一个独立的mq服务
//因为最后需要关闭连接所以定义到外面
Connection connection = null;
Channel channel = null;
try {
//通过connectionfactory获取connection
connection = connectionFactory.newConnection();
//获取Exchange通道
channel = connection.createChannel();
//声明交换机 String exchange, BuiltinExchangeType type
/**
*参数明细
*1、交换机名称
*2、交换机类型,fanout、topic、direct、headers
*/
channel.exchangeDeclare(EXCHANGEE_INFORM, BuiltinExchangeType.FANOUT);
/**
*声明队列,如果Rabbit中没有此队列将自动创建
*param1:队列名称
*param2:是否持久化
*param3:队列是否独占此连接
*param4:队列不再使用时是否自动删除此队列
*param5:队列参数
*/
channel.queueDeclare(QUEUE_EMAIL, true, false, false, null);
channel.queueDeclare(QUEUE_SMS, true, false, false, null);
//交换机和队列绑定String queue, String exchange, String routingKey
/**
*参数明细
*1、队列名称
*2、交换机名称
*3、路由key
*/
channel.queueBind(QUEUE_EMAIL,EXCHANGEE_INFORM,"");
channel.queueBind(QUEUE_SMS,EXCHANGEE_INFORM,"");
//自定义消息
/**
*消息发布方法
*param1:Exchange的名称,如果没有指定,则使用Default Exchange
*param2:routingKey,消息的路由Key,是用于Exchange(交换机)将消息转发到指定的消息队列
*param3:消息包含的属性
*param4:消息体
*/
for (int i = 0; i < 5; i++) {
String massage = "helloMQ!第"+i+"次";
channel.basicPublish(EXCHANGEE_INFORM, "", null, massage.getBytes("utf-8"));
System.out.println("send massage: ----" + massage);
}
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
} finally {
if (channel != null) {
channel.close();
}
if (connection != null) {
connection.close();
}
}
}
customer代码:
public class customer01 {
private static final String QUEUE_EMAIL = "queue_email";
private static final String EXCHANGEE_INFORM = "exchange_inform";
public static void main(String[] args) throws IOException, TimeoutException {
//创建connectionfactory
ConnectionFactory factory = new ConnectionFactory();
//设置MabbitMQ所在服务器的ip和端口
factory.setHost("127.0.0.1");
factory.setPort(5672);
//获取connection
Connection connection = factory.newConnection();
//获取通道
Channel channel = connection.createChannel();
//声明交换机 String exchange, BuiltinExchangeType type
/**
*参数明细
*1、交换机名称
*2、交换机类型,fanout、topic、direct、headers
*/
channel.exchangeDeclare(EXCHANGEE_INFORM,BuiltinExchangeType.FANOUT);
//声明队列
channel.queueDeclare(QUEUE_EMAIL, true, false, false, null);
//定义消费方法
DefaultConsumer consumer = new DefaultConsumer(channel) {
/**
*消费者接收消息调用此方法
*@param consumerTag 消费者的标签,在channel.basicConsume()去指定
*@param envelope 消息包的内容,可从中获取消息id,消息routingkey,交换机,消息和重传标志(收到消息失败后是否需要重新发送)
*@param properties
*@param body
*@throws IOException
**/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body)throws IOException {
//交换机
String exchange = envelope.getExchange();
//路由key
String routingKey = envelope.getRoutingKey();
//消息id
long deliveryTag = envelope.getDeliveryTag();
//消息内容
String msg = new String(body, "utf-8");
System.out.println("receive message:" + msg);
}
};
/**
*监听队列String queue, boolean autoAck,Consumer callback
*参数明细
*1、队列名称
*2、是否自动回复,设置为true为表示消息接收到自动向mq回复接收到了,mq接收到回复会删除消息,设置 为false则需要手动回复
*3、消费消息的方法,消费者接收到消息后调用此方法
*/
channel.basicConsume(QUEUE_EMAIL, false, consumer);
}
}
另一个消费者代码与这个基本一样,只需要改下参数即可,我就不在这里粘贴代码了。
接下来去rabbitMQ管理界面查看我们的交换机,点击刚创建的交换机
点击bindings查看绑定状况