RabbitMQ多种模式:
- Work queues (工作模式):
代码实践:
public class Produce01 { // 工作模式 生产者
//队列名
private static final String QUEUE = "SERVER_A";
public static void main(String[] args) {
//生产者通过会话通道将信息发送至MQ服务然后由路由器将消息转发至队列中
//创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("127.0.0.1"); //连接地址
factory.setPort(5672); //端口
factory.setUsername("guest");
factory.setPassword("guest");
//设置虚拟机 每个虚拟机相当于独立的MQ
factory.setVirtualHost("/");
Connection connection = null;
Channel channel = null;
try {
//建立连接
connection = factory.newConnection();
//创建会话通道 生产者和MQ服务的通信都在通道中完成
channel = connection.createChannel();
/**
* 声明队列 如队列不存在则创建队列
* 队列参数
* String queue, 队列名
* boolean durable, 持久化
* boolean exclusive, 是否独占队列 队列只允许当前连接访问 连接关闭队列删除 true 代表临时队列
* boolean autoDelete, 是否自动删除 exclusive设置为临时队列(true) 那么连接关闭队列自动删除
* Map<String, Object> arguments 扩展参数 例如 队列存活时间
*/
channel.queueDeclare(QUEUE,true,false,false,null);
/**
* 发送消息
* String exchange, 交换机 如设定交换机则使用mq默认交换机
* String routingKey, 路由key 交换机根据路由key将消息转发到指定的队列中,默认交换机则设置队列的名
* BasicProperties props, 消息属性
* byte[] body 消息体
*/
String message = "Hello RabbitMQ"; //消息内容
channel.basicPublish("",QUEUE,null,message.getBytes());
System.out.println("produce send mq:" + message);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
channel.close(); //关闭会话通道
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
try {
connection.close(); //关闭连接
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public class Consumer01 { //消费者
private static final String QUEUE = "SERVER_A";
public static void main(String[] args) {
//创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("127.0.0.1"); //连接地址
factory.setPort(5672); //端口
factory.setUsername("guest");
factory.setPassword("guest");
factory.setVirtualHost("/"); //设置虚拟机
Connection connection = null;
try {
connection = factory.newConnection(); //建立连接
Channel channel = connection.createChannel(); //创建会话通道
/** 监听哪个队列
* 声明队列 如队列不存在则创建队列
* 队列参数
* String queue, 队列名
* boolean durable, 持久化
* boolean exclusive, 是否独占队列 队列只允许当前连接访问 连接关闭队列删除 true 代表临时队列
* boolean autoDelete, 是否自动删除 exclusive设置为临时队列(true) 那么连接关闭队列自动删除
* Map<String, Object> arguments 扩展参数 例如 队列存活时间
*/
channel.queueDeclare(QUEUE,true,false,false,null);
//实现消费方法
DefaultConsumer defaultConsumer = new DefaultConsumer(channel){
/**
* 当接受到消息此方法就会执行消费
* @param consumerTag 消费者标签 标识消费者
* @param envelope 信封
* @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(); //交换机
long deliveryTag = envelope.getDeliveryTag(); //消息ID
String message = new String(body,"UTF-8");
System.out.println("consumer :" + message);
}
};
/**
* 开始监听队列
* String queue, 队列名
* DeliverCallback deliverCallback, true 自动回复MQ消息已接收
* CancelCallback cancelCallback
*/
channel.basicConsume(QUEUE,true,defaultConsumer);
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}
一个生产者将消息发送给一个队列,多个消费者共同监听这个队列,rabbitmq采用轮询方式将消息平均发送给消费者。
- Publish/Subscribe(发布订阅模式):
代码实践:
public class Produce_publish { //广播模式 生产者
private static final String QUEUE_SMS = "queue_inform_sms"; //短信队列名
private static final String QUEUE_EMAIL = "queue_inform_email"; //邮件队列名
private static final String EXCHANGE_FANOUT_INFORM = "exchange_fanout_inform"; //交换机
public static void main(String[] args) {
//创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
factory.setPort(5672);
factory.setHost("127.0.0.1");
factory.setUsername("guest");
factory.setPassword("guest");
factory.setVirtualHost("/");
Connection connection = null;
Channel channel = null;
try {
//建立连接
connection = factory.newConnection();
channel = connection.createChannel();//创建会话通道
//短信队列
channel.queueDeclare(QUEUE_SMS,true,false,false,null);
//邮件队列
channel.queueDeclare(QUEUE_EMAIL,true,false,false,null);
/**
* 声明交换机
* String exchange,
* BuiltinExchangeType type:
* BuiltinExchangeType.FANOUT 对应发布订阅模式
* BuiltinExchangeType.DIRECT 对应路由模式
* BuiltinExchangeType.TOPIC 对应通配符模式
* BuiltinExchangeType.HEADERS 对应转发器模式
*/
channel.exchangeDeclare(EXCHANGE_FANOUT_INFORM, BuiltinExchangeType.FANOUT);
/**
* 交换机与队列进行绑定
* String queue, 队名名
* String exchange, 交换机名
* String routingKey 路由key 交换机根据路由key将消息转发到指定的队列中
*/
channel.queueBind(QUEUE_SMS,EXCHANGE_FANOUT_INFORM,"");
channel.queueBind(QUEUE_EMAIL,EXCHANGE_FANOUT_INFORM,"");
for (int i = 0;i<5;i++){
String message = "rabbitmq send 发布订阅模式...";
/**
* String exchange,
* String routingKey,
* BasicProperties props,
* byte[] body
*/
channel.basicPublish(EXCHANGE_FANOUT_INFORM,"",null,message.getBytes());
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
channel.close();
connection.close();
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}
}
public class Consumer_Email { //邮箱队列
private static final String QUEUE_EMAIL = "queue_inform_email"; //邮件队列名
private static final String EXCHANGE_FANOUT_INFORM = "exchange_fanout_inform"; //交换机
public static void main(String[] args) {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("127.0.0.1");
factory.setPort(5672);
factory.setUsername("guest");
factory.setPassword("guest");
factory.setVirtualHost("/");
Connection connection = null;
Channel channel = null;
try {
//建立连接
connection = factory.newConnection();
//建立通道
channel = connection.createChannel();
//监听通道
channel.queueDeclare(QUEUE_EMAIL,true,false,false,null);
//声明交换机
channel.exchangeDeclare(EXCHANGE_FANOUT_INFORM, BuiltinExchangeType.FANOUT);
//绑定队列与交换机
channel.queueBind(QUEUE_EMAIL,EXCHANGE_FANOUT_INFORM,"");
DefaultConsumer consumer = new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String exchange = envelope.getExchange(); //交换机
String routingKey = envelope.getRoutingKey(); //routingKey
long deliveryTag = envelope.getDeliveryTag(); //消息ID
String message = new String(body,"UTF-8");
System.out.println("Consumer Email message:" + message);
}
};
channel.basicConsume(QUEUE_EMAIL,true,consumer);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class Consumer_SMS { //短信队列
private static final String QUEUE_SMS = "queue_inform_sms"; //短信队列名
private static final String EXCHANGE_FANOUT_INFORM = "exchange_fanout_inform"; //交换机
public static void main(String[] args) {
//创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("127.0.0.1"); //连接地址
factory.setPort(5672); //端口
factory.setUsername("guest");
factory.setPassword("guest");
factory.setVirtualHost("/"); //设置虚拟机
Connection connection = null;
try {
connection = factory.newConnection(); //建立连接
Channel channel = connection.createChannel(); //创建会话通道
/** 监听哪个队列
* 声明队列 如队列不存在则创建队列
* 队列参数
* String queue, 队列名
* boolean durable, 持久化
* boolean exclusive, 是否独占队列 队列只允许当前连接访问 连接关闭队列删除 true 代表临时队列
* boolean autoDelete, 是否自动删除 exclusive设置为临时队列(true) 那么连接关闭队列自动删除
* Map<String, Object> arguments 扩展参数 例如 队列存活时间
*/
channel.queueDeclare(QUEUE_SMS,true,false,false,null);
channel.exchangeDeclare(EXCHANGE_FANOUT_INFORM,BuiltinExchangeType.FANOUT);
channel.queueBind(QUEUE_SMS,EXCHANGE_FANOUT_INFORM,"");
/**
* 开始监听队列
* String queue, 队列名
* DeliverCallback deliverCallback, true 自动回复MQ消息已接收
* CancelCallback cancelCallback
*/
Consumer defaultConsumer = new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String exchange = envelope.getExchange(); //交换机
long deliveryTag = envelope.getDeliveryTag(); //消息ID
String message = new String(body,"UTF-8");
System.out.println("consumer :" + message);
}
};
channel.basicConsume(QUEUE_SMS,true,defaultConsumer);
} catch (Exception e) {
e.printStackTrace();
}
}
}
生产者将消息发送给交换机,由交换机将消息转发到与交换机绑定的多个队列上,每个消费者监听自己的队列。
注意:如果生产者发送多条信息至队列,多个消费者同时监听一个队列就会出现消息重复消费问题!