工作队列
一个队列bind多个消费者
/**
* 生产者
*/
public class WorkQueueProvider {
private static final String QUEUE_NAME = "test_work_queue";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = RabbitMQUtil.getConnection();
Channel channel = connection.createChannel();
//队列声明
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
for (int i = 0; i < 50; i++){
StringBuffer buffer = new StringBuffer("Hello,");
buffer.append(i);
channel.basicPublish("",QUEUE_NAME,null,buffer.toString().getBytes());
//消息持久化
// channel.basicPublish("exchange.persistent", "persistent", MessageProperties.PERSISTENT_TEXT_PLAIN, "persistent_test_message".getBytes());
}
RabbitMQUtil.close(connection, channel);
}
}
/**
* 消费者1
*/
public class WorkQueueConsumerOne {
private static final String QUEUE_NAME = "test_work_queue";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = RabbitMQUtil.getConnection();
final Channel channel = connection.createChannel();
/**'
* 声明队列,虽然已经在生产者中声明过了,但这样写并不会有什么问题
* 之所以在这里再声明,是为了保证在生产者程序未运行的情况下,队列也被声明
* 这样消费者程序运行时不会报队列未声明的错误
*/
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
DefaultConsumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String msg = new String(body, "utf-8");
System.out.println("收到消息:"+msg);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
channel.basicAck(envelope.getDeliveryTag(),false);
}
}
};
//关闭消息自动ack
boolean autoAck = false;
channel.basicConsume(QUEUE_NAME,autoAck,consumer);
}
}
/**
* 消费者2
*/
public class WorkQueueConsumerTwo {
private static final String QUEUE_NAME = "test_work_queue";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = RabbitMQUtil.getConnection();
final Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
DefaultConsumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String msg = new String(body, "utf-8");
System.out.println("收到消息:"+msg);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
//手动确认消息
channel.basicAck(envelope.getDeliveryTag(),false);
}
}
};
boolean autoAck = false;
channel.basicConsume(QUEUE_NAME,autoAck,consumer);
}
}
上面的代码会出现问题,尽管消费者1消费一天消息需要等待2秒而消费者2消费一天消息仅需等待1秒。但RabbitMQ还是以消费者1一条消费者2一条的形式发送消息。所以引出如下公平分发代码。
public class WorkQueueConsumerOne {
private static final String QUEUE_NAME = "test_work_queue";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = RabbitMQUtil.getConnection();
final Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
/**
* 在所有消费者运行channel.basicQos()方法即可进入公平分发
* 每个消费者发送消息确认之前,队列不发送新的消息到消费者
* 消费者一次只处理一个消息
*/
channel.basicQos(1);
DefaultConsumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String msg = new String(body, "utf-8");
System.out.println("收到消息:"+msg);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
channel.basicAck(envelope.getDeliveryTag(),false);
}
}
};
boolean autoAck = false;
channel.basicConsume(QUEUE_NAME,autoAck,consumer);
}
这样性能优越的消费者就能消费掉更多的消息
发布/订阅模式
先请去如下网址阅读下交换机类型:
https://blog.csdn.net/rainday0310/article/details/22082503
简单的发布/订阅模式将队列bind到交换机上,一个交换机可bind多个队列。生产者发送消息时会将消息推送给所有bind它的队列。然后再由消费者消费。
public class ExchangeProvider {
private static final String EXCHANGE_NAME = "text_exchange_fanout";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = RabbitMQUtil.getConnection();
Channel channel = connection.createChannel();
//定义exchange 这里定义的exchange类型是'fanout'
channel.exchangeDeclare(EXCHANGE_NAME, ExchangeTypes.FANOUT);
String msg = "hello tzh";
//发送消息 第二个参数是路由 routingKey 这里定义的""
channel.basicPublish(EXCHANGE_NAME,"",null,msg.getBytes());
System.out.println("provide : " + msg);
RabbitMQUtil.close(connection,channel);
}
}
public class ExchangeConsumerOne {
private static final String QUEUE_NAME = "text_queue_email";
private static final String EXCHANGE_NAME = "text_exchange_fanout";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = RabbitMQUtil.getConnection();
final Channel channel = connection.createChannel();
//声明队列
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
//将队列与交换机绑定 并声明接收消息的路由
channel.queueBind(QUEUE_NAME, EXCHANGE_NAME,"");
channel.basicQos(1);
DefaultConsumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String msg = new String(body, "utf-8");
System.out.println("consumer two[] :"+msg);
//这个方法第二个Boolean类型的参数声明是否是多条消息
channel.basicAck(envelope.getDeliveryTag(),false);
}
};
boolean autoAck = false;
channel.basicConsume(QUEUE_NAME,autoAck,consumer);
}
}
public class ExchangerConsumerTwo {
private static final String QUEUE_NAME = "text_queue_sms";
private static final String EXCHANGE_NAME = "text_exchange_fanout";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = RabbitMQUtil.getConnection();
final Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
channel.queueBind(QUEUE_NAME, EXCHANGE_NAME,"");
channel.basicQos(1);
DefaultConsumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String msg = new String(body, "utf-8");
System.out.println("consumer one[] :"+msg);
channel.basicAck(envelope.getDeliveryTag(),false);
}
};
boolean autoAck = false;
channel.basicConsume(QUEUE_NAME,autoAck,consumer);
}
}
下次总结会做routing 模式和项目中使用较多的topic 模式