基本消息模型
生产者发送一条消息给消息队列,消费者被动接收消息
代码:
生产者
public class Producer {
public static void main(String[] args) {
/***
* 1 创建连接工程
* 2 创建连接Connection
* 3 通过连接获取通道
* 4 通过连接创建交换机,申明队列,绑定关系,路由可以,发送消息和接收消息
* 5 准备消息
* 6 发送消息
* 7 关闭连接
* 8 关闭通道
*/
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("192.168.0.172");
connectionFactory.setPort(5672);
connectionFactory.setUsername("admin");
connectionFactory.setPassword("admin");
connectionFactory.setVirtualHost("/");
Connection connection = null;
Channel channel = null;
try {
connection = connectionFactory.newConnection("生产者");
channel = connection.createChannel();
String queueName = "queue";
/***
* @param1 队列名称
* @param2 是否持久化(false 非持久化,true 持久化)
* @param3 排他性 是否是独占
* @param4 是否自动删除 随着最后一个消费者消息完毕以后是否吧队列自动删除
* @param5 携带附属参数
*/
channel.queueDeclare(queueName, false, false, false, null);
String message = "Hello world";
channel.basicPublish("", queueName, null, message.getBytes());
System.out.println("message has been send");
} catch (Exception e) {
e.printStackTrace();
} finally {
if(channel!=null && channel.isOpen()){
try {
channel.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if(connection!=null && connection.isOpen()){
try {
connection.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
消费者
public class Recv {
public static void main(String[] args) {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("192.168.0.172");
connectionFactory.setPort(5672);
connectionFactory.setUsername("admin");
connectionFactory.setPassword("admin");
connectionFactory.setVirtualHost("/");
Connection recvConnection=null;
Channel channel=null;
try {
recvConnection = connectionFactory.newConnection("recv");
channel=recvConnection.createChannel();
channel.queueDeclare("queue",false,false,false,null);
System.out.println("接收消息");
channel.basicConsume("queue",true,( s, delivery)->{
String message = new String(delivery.getBody(), "UTF-8");
System.out.println("接收到消息"+message);
},consumerTag->{});
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}
执行结果
work消息模型
将密集任务发送到消息队列,由多个消费者进行监听消费,每个消息只能由一个消费者接收
代码
生产者,生产50条消息
public class Producer {
public static void main(String[] args) {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("192.168.0.172");
connectionFactory.setUsername("admin");
connectionFactory.setPassword("admin");
try(Connection connection = connectionFactory.newConnection();
Channel channel = connection.createChannel()) {
String queueName="work_queue";
String exchangeName="work_exchange";
channel.exchangeDeclare(exchangeName,"direct");
channel.queueDeclare(queueName,false,false,false,null);
for(int i=0;i<50;i++){
String msg="hello workQueue_tianya_"+i;
channel.basicPublish("",queueName,false,false,null,msg.getBytes());
}
System.out.println("msg has been send!");
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}finally {
}
}
}
消费者1,消费者2
public class Recv {
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("192.168.0.172");
connectionFactory.setUsername("admin");
connectionFactory.setPassword("admin");
String queueName = "work_queue";
Connection connection = connectionFactory.newConnection();
final Channel channel = connection.createChannel();
channel.queueDeclare(queueName, false, false, false, null);
/* final DeliverCallback deliverCallback = new DeliverCallback() {
@Override
public void handle(String s, Delivery delivery) throws IOException {
final String message = new String(delivery.getBody(), "UTF-8");
System.out.println("[1] Received " + message);
doWork(message);
//手动确认
channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false);
}
};*/
DefaultConsumer consumer = new DefaultConsumer(channel) {
// 获取消息,并且处理,这个方法类似事件监听,如果有消息的时候,会被自动调用
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
// body 即消息体
String msg = new String(body);
System.out.println(" [消费者1] received : " + msg + "!");
doWork(msg);
// 手动ACK
// channel.basicAck(envelope.getDeliveryTag(), false);
}
};
channel.basicConsume(queueName, true, consumer);
}
public static void doWork(String msg) {
final String[] msgs = msg.split("_");
int time = Integer.parseInt(msgs[2]);
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
先启动两个消费者,在启动生产者,结果如下
可以看到两个消费者交替执行。
可以看出以上为轮训模式,当消费者之间执行的效率不一样时,则应当按照“消费者的消费水平”进行分发消息
公平模式
int prefetchCount =1
channel.basicQos(prefetchCount);
表示mq不要像消费端发送多于prefetchCount条消息,直到消息确认全部处理完毕在重新发送
订阅模式
示意图
生产者不直接将消息发送到指定的队列中,而是将消息发送的交换机,有交换机根据当前交换机类型将消息发送到特定的队列中。
订阅模式–Fanout
广播模式,该模式下,交换机会将消息转发到所有与交换机绑定的队列中
代码:
生产者
public class Producer {
public static void main(String[] args) throws Exception {
final Connection connection = RabbitmqUtil.getConnection();
final Channel channel = RabbitmqUtil.getChannel();
String exchangeName="logs";
//声明交换机
channel.exchangeDeclare(exchangeName,"fanout");
String message="info: Hello world";
channel.basicPublish(exchangeName,"",null,message.getBytes());
channel.close();
connection.close();
}
}
消费者1,2
public class Recv1 {
public static void main(String[] args) throws Exception {
final Connection connection = RabbitmqUtil.getConnection();
final Channel channel = RabbitmqUtil.getChannel();
String exchangeName = "logs";
String queueName = "logs_queue1";
//声明队列
channel.queueDeclare(queueName, false, false, false, null);
//绑定队列和交换机
channel.queueBind(queueName,exchangeName,"");
channel.basicConsume(queueName,false,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String message=new String(body);
System.out.println("消费者[1] 接收消息:"+message);
}
});
}
}
执行结果
通过管理页面查看,队列已于交换机绑定
订阅模式–Topic
主题模式,通过通配符(*,#)进行模糊匹配,根据routingKey将消息路由到不同的队列中
‘#’ 0个或多个单词
‘*’ 只有一个单词
代码:
生产者
public class Producer {
public static void main(String[] args) throws Exception {
final Connection connection = RabbitmqUtil.getConnection();
final Channel channel = RabbitmqUtil.getChannel();
String exchangeName="topic_logs";
channel.exchangeDeclare(exchangeName,"topic");
String message1="勇敢牛牛,不怕困难";
String message2="牛奶真好喝";
channel.basicPublish(exchangeName,"brave.cow",null,message1.getBytes());
channel.basicPublish(exchangeName,"brave.cow.milk",null,message2.getBytes());
channel.close();
connection.close();
}
}
消费者
public class Recv1 {
public static void main(String[] args) throws Exception {
final Connection connection = RabbitmqUtil.getConnection();
final Channel channel = RabbitmqUtil.getChannel();
String exchangeName = "topic_logs";
String queueName = "logs_queue1";
channel.queueDeclare(queueName, false, false, false, null);
channel.queueBind(queueName,exchangeName,"#.cow");
channel.basicConsume(queueName,false,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String message=new String(body);
System.out.println("消费者[1] 接收消息:"+message);
channel.basicAck(envelope.getDeliveryTag(),false);
}
});
}
}
public class Recv2 {
public static void main(String[] args) throws Exception {
final Connection connection = RabbitmqUtil.getConnection();
final Channel channel = RabbitmqUtil.getChannel();
String exchangeName = "topic_logs";
String queueName = "logs_queue2";
channel.queueDeclare(queueName, false, false, false, null);
channel.queueBind(queueName,exchangeName,"#.cow.*");
channel.basicConsume(queueName,false,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String message=new String(body);
System.out.println("消费者[2] 接收消息:"+message);
channel.basicAck(envelope.getDeliveryTag(),false);
}
});
/* channel.close();
connection.close();*/
}
}
执行结果
订阅模式–Direct
当使用
fanout
模式时,发布者发布消息,所有的消费者都能获取到消息,而在此模式下,消费者只能获取某种特定的消息,如示意图所示,C1只能获取routingKey为error的日志,C2只能获取routingKey为info,error和warning的日志。
代码:
生产者
public class Producer {
public static void main(String[] args) throws Exception {
final Connection connection = RabbitmqUtil.getConnection();
final Channel channel = RabbitmqUtil.getChannel();
String exchangeName="direct_logs";
channel.exchangeDeclare(exchangeName,"direct");
String message="info: Hello world";
String message1="warn: Hello world";
String message2="error: Hello world";
String message3="info: Hello world=============";
channel.basicPublish(exchangeName,"info",null,message.getBytes());
channel.basicPublish(exchangeName,"warn",null,message1.getBytes());
channel.basicPublish(exchangeName,"error",null,message2.getBytes());
channel.basicPublish(exchangeName,"info",null,message3.getBytes());
channel.close();
connection.close();
}
}
public class Recv1 {
public static void main(String[] args) throws Exception {
final Connection connection = RabbitmqUtil.getConnection();
final Channel channel = RabbitmqUtil.getChannel();
String exchangeName = "direct_logs";
String queueName = "logs_queue1";
channel.queueDeclare(queueName, false, false, false, null);
channel.queueBind(queueName,exchangeName,"info");
channel.basicConsume(queueName,false,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String message=new String(body);
System.out.println("消费者[1] 接收消息:"+message);
}
});
}
}
public class Recv2 {
public static void main(String[] args) throws Exception {
final Connection connection = RabbitmqUtil.getConnection();
final Channel channel = RabbitmqUtil.getChannel();
String exchangeName = "direct_logs";
String queueName = "logs_queue2";
channel.queueDeclare(queueName, false, false, false, null);
channel.queueBind(queueName,exchangeName,"info");
channel.queueBind(queueName,exchangeName,"warn");
channel.queueBind(queueName,exchangeName,"error");
channel.basicConsume(queueName,false,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String message=new String(body);
System.out.println("消费者[2] 接收消息:"+message);
}
});
/* channel.close();
connection.close();*/
}
}
执行结果