RabbitMQ工作模式
Work queues工作队列模式
-
Work Queues:与入门程序的简单模式相比,多了一个或一些消费端,多个消费端共同消费同一个队列的消息
-
应用场景:对于任务过重或任务较多情况使用工作队列可以提高任务处理的速度
-
在一个队列中如果有多个消费者,那么消费者之间对于同一个消息的关系是竞争的关系
Pub/Sub订阅模式
在订阅模式中,多了一个Exchange角色,而且过程略有变化:
-
P:生产者,也就是要发送消息的程序,但是不在发送到队列中,而是发给X(交换机)
-
C:消费者,消息的接收者,等待消息
-
Queues:消息队列,接收消息、缓存消息
-
Exchange:交换机(X)。一方面,接收生产者发送的消息。另一方面,知道如何处理消息。例如递交给某个特别队列、递交给所有队列、或是将消息丢弃。到底如何操作,取决于Exchange的类型。Exchange有常见一下三种类型:
- Fanout:广播,将消息交给所有绑定到交换机的队列
- Direct:定向,将消息交给符合指定routing key队列
- Topic:通配符,把消息交给符合routing patterm(路由模式)的队列
-
Exchange(交换机)只负责转发消息,不具备消息存储的能力,因此如果没有任何队列与Exchange绑定,或者没有符合路由规则的队列,那么消息会丢失
生产者发送消息
/**
* 生产者,发送消息
*/
public class Producer_PubSub {
public static void main(String[] args) throws IOException, TimeoutException {
//1.连接工厂
ConnectionFactory factory = new ConnectionFactory();
//2.设置参数
//2.1设置IP地址,默认值为localhost
factory.setHost("192.168.23.129");
//2.2设置端口,默认值5672
factory.setPort(5672);
//2.3设置虚拟机,默认值为/
factory.setVirtualHost("/zhenbao");
//2.4设置账号密码
factory.setUsername("qiyun");//默认guest
factory.setPassword("qiyun");//默认guest
//3.获取连接 Connection
Connection connection = factory.newConnection();
//4.创建Channel
Channel channel = connection.createChannel();
//5.创建交换机
/*
* exchangeDeclare(String exchange, BuiltinExchangeType type, boolean durable, boolean autoDelete, boolean internal, Map<String, Object> arguments)
* 参数:
* 1.exchange:交换机名称
* 2.type:交换机的类型
* DIRECT("direct"):定向
* FANOUT("fanout"):扇形(广播),发送消息到每一个与之绑定的队列
* TOPIC("topic"):通配符的方式
* HEADERS("headers"):参数匹配
* 3.durable:是否持久化
* 4.autoDelete:是否自动删除
* 5.internal:内部使用,一般false
* 6.arguments:参数列表
*/
String exchangeName = "test_fanout";
channel.exchangeDeclare(exchangeName, BuiltinExchangeType.FANOUT,true,false,false,null);
//6.创建队列
/**
*
* queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)
* 参数:
* 1.queue:队列名称
* 2.durable:是否持久化,当mq重启之后还在
* 3.exclusive:
* *是否独占,只能有一个消费者监听这队列
* *当Connection关闭时,是否删除队列
* 4.autoDelete:是否自动删除,当没有Consumer时,自动删除掉
* 5.arguments:参数
*/
String queue1Name = "test_fanout_queue1";
String queue2Name = "test_fanout_queue2";
channel.queueDeclare(queue1Name,true,false,false,null);
channel.queueDeclare(queue2Name,true,false,false,null);
//7.绑定队列和交换机
/**
* queueBind(String queue, String exchange, String routingKey)
* 参数:
* 1.queue:要绑定的队列名称
* 2.exchange:交换机名称
* 3.routingKey:路由键,绑定规则
* 如果交换机的类型为fanout,routingKey设置为""
*/
channel.queueBind(queue1Name,exchangeName,"");
channel.queueBind(queue2Name,exchangeName,"");
//8.发送消息
/**
* basicPublish(String exchange, String routingKey,BasicProperties props, byte[] body)
* 参数:
* 1.exchange:交换机名称,简单模式下交换机会使用默认的
* 2.routingKey:路由名称
* 3.props:配置信息
* 4.body:发送消息数据
*/
String body = "日志信息:李四调用了findById的方法......日志级别为:info......";
channel.basicPublish(exchangeName,"",null,body.getBytes());
//9.释放资源
channel.close();
connection.close();
}
}
消费者接收消息并打印到控制台
/**
* 消费者,接收消息
*/
public class Consumer_PubSub1 {
public static void main(String[] args) throws IOException, TimeoutException {
//1.连接工厂
ConnectionFactory factory = new ConnectionFactory();
//2.设置参数
//2.1设置IP地址,默认值为localhost
factory.setHost("192.168.23.129");
//2.2设置端口,默认值5672
factory.setPort(5672);
//2.3设置虚拟机,默认值为/
factory.setVirtualHost("/zhenbao");
//2.4设置账号密码
factory.setUsername("qiyun");//默认guest
factory.setPassword("qiyun");//默认guest
//3.获取连接 Connection
Connection connection = factory.newConnection();
//4.创建Channel
Channel channel = connection.createChannel();
//5.创建队列Queue
/**
*
* queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)
* 参数:
* 1.queue:队列名称
* 2.durable:是否持久化,当mq重启之后还在
* 3.exclusive:
* *是否独占,只能有一个消费者监听这队列
* *当Connection关闭时,是否删除队列
* 4.autoDelete:是否自动删除,当没有Consumer时,自动删除掉
* 5.arguments:参数
*/
String queue1Name = "test_fanout_queue1";
String queue2Name = "test_fanout_queue2";
//6.接收消息
/**
* public String basicConsume(String queue, boolean autoAck, Consumer callback)
* 参数:
* 1.queue:队列名称
* 2.autoAck:是否自动确认
* 3.callback:回调对象
*/
Consumer consumer = new DefaultConsumer(channel){
/*
* 这是一个回调方法,当收到消息过后,会自动执行该方法
* 参数:
* 1.consumerTag:标识
* 2.envelope:获取对应的信息(交换机、路由Key......)
* 3.properties:配置信息
* 4.body:数据
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("body:"+new String(body));
System.out.println("将日志信息打印到控制台......");
}
};
channel.basicConsume(queue1Name,true,consumer);
//消费者不能关闭资源
}
}
消费者接收消息并保存到数据库
/**
* 消费者,接收消息
*/
public class Consumer_PubSub2 {
public static void main(String[] args) throws IOException, TimeoutException {
//1.连接工厂
ConnectionFactory factory = new ConnectionFactory();
//2.设置参数
//2.1设置IP地址,默认值为localhost
factory.setHost("192.168.23.129");
//2.2设置端口,默认值5672
factory.setPort(5672);
//2.3设置虚拟机,默认值为/
factory.setVirtualHost("/zhenbao");
//2.4设置账号密码
factory.setUsername("qiyun");//默认guest
factory.setPassword("qiyun");//默认guest
//3.获取连接 Connection
Connection connection = factory.newConnection();
//4.创建Channel
Channel channel = connection.createChannel();
//5.创建队列Queue
/**
*
* queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)
* 参数:
* 1.queue:队列名称
* 2.durable:是否持久化,当mq重启之后还在
* 3.exclusive:
* *是否独占,只能有一个消费者监听这队列
* *当Connection关闭时,是否删除队列
* 4.autoDelete:是否自动删除,当没有Consumer时,自动删除掉
* 5.arguments:参数
*/
String queue1Name = "test_fanout_queue1";
String queue2Name = "test_fanout_queue2";
//6.接收消息
/**
* public String basicConsume(String queue, boolean autoAck, Consumer callback)
* 参数:
* 1.queue:队列名称
* 2.autoAck:是否自动确认
* 3.callback:回调对象
*/
Consumer consumer = new DefaultConsumer(channel){
/*
* 这是一个回调方法,当收到消息过后,会自动执行该方法
* 参数:
* 1.consumerTag:标识
* 2.envelope:获取对应的信息(交换机、路由Key......)
* 3.properties:配置信息
* 4.body:数据
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("body:"+new String(body));
System.out.println("将日志信息保存到数据库......");
}
};
channel.basicConsume(queue2Name,true,consumer);
//消费者不能关闭资源
}
}
Routing路由工作模式
模式说明:
- 队列与交换机的绑定,不能任意绑定了,而是要指定一个Routing Key(路由Key)
- 消息的发送方在向Exchange发送消息时,也必须指定消息的Routing Key
- Exchange不再把消息交给每一个绑定的队列,而是根据消息的Routing Key进行判断,只有队列的Routing Key与消息的Routing Key完全一致时才会接收消息
生产者发送消息
级别设置为info,队列1无法接收消息
/**
* 生产者,发送消息
*/
public class Producer_Routing {
public static void main(String[] args) throws IOException, TimeoutException {
//1.连接工厂
ConnectionFactory factory = new ConnectionFactory();
//2.设置参数
//2.1设置IP地址,默认值为localhost
factory.setHost("192.168.23.129");
//2.2设置端口,默认值5672
factory.setPort(5672);
//2.3设置虚拟机,默认值为/
factory.setVirtualHost("/zhenbao");
//2.4设置账号密码
factory.setUsername("qiyun");//默认guest
factory.setPassword("qiyun");//默认guest
//3.获取连接 Connection
Connection connection = factory.newConnection();
//4.创建Channel
Channel channel = connection.createChannel();
//5.创建交换机
/*
* exchangeDeclare(String exchange, BuiltinExchangeType type, boolean durable, boolean autoDelete, boolean internal, Map<String, Object> arguments)
* 参数:
* 1.exchange:交换机名称
* 2.type:交换机的类型
* DIRECT("direct"):定向
* FANOUT("fanout"):扇形(广播),发送消息到每一个与之绑定的队列
* TOPIC("topic"):通配符的方式
* HEADERS("headers"):参数匹配
* 3.durable:是否持久化
* 4.autoDelete:是否自动删除
* 5.internal:内部使用,一般false
* 6.arguments:参数列表
*/
String exchangeName = "test_direct";
channel.exchangeDeclare(exchangeName, BuiltinExchangeType.DIRECT,true,false,false,null);
//6.创建队列
/**
*
* queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)
* 参数:
* 1.queue:队列名称
* 2.durable:是否持久化,当mq重启之后还在
* 3.exclusive:
* *是否独占,只能有一个消费者监听这队列
* *当Connection关闭时,是否删除队列
* 4.autoDelete:是否自动删除,当没有Consumer时,自动删除掉
* 5.arguments:参数
*/
String queue1Name = "test_direct_queue1";
String queue2Name = "test_direct_queue2";
channel.queueDeclare(queue1Name,true,false,false,null);
channel.queueDeclare(queue2Name,true,false,false,null);
//7.绑定队列和交换机
/**
* queueBind(String queue, String exchange, String routingKey)
* 参数:
* 1.queue:要绑定的队列名称
* 2.exchange:交换机名称
* 3.routingKey:路由键,绑定规则
* 如果交换机的类型为fanout,routingKey设置为""
*/
//队列1的绑定,绑定的是error
channel.queueBind(queue1Name,exchangeName,"error");
//队列2的绑定,绑定的是info、error、warning
channel.queueBind(queue2Name,exchangeName,"info");
channel.queueBind(queue2Name,exchangeName,"error");
channel.queueBind(queue2Name,exchangeName,"warning");
//8.发送消息
String body = "日志信息:李四调用了findById的方法......日志级别为:info......";
channel.basicPublish(exchangeName,"info",null,body.getBytes());
//9.释放资源
channel.close();
connection.close();
}
}
消费者(队列1)接收消息保存数据库
/**
* 消费者,接收消息保存至数据库
*/
public class Consumer_Routing1 {
public static void main(String[] args) throws IOException, TimeoutException {
//1.连接工厂
ConnectionFactory factory = new ConnectionFactory();
//2.设置参数
//2.1设置IP地址,默认值为localhost
factory.setHost("192.168.23.129");
//2.2设置端口,默认值5672
factory.setPort(5672);
//2.3设置虚拟机,默认值为/
factory.setVirtualHost("/zhenbao");
//2.4设置账号密码
factory.setUsername("qiyun");//默认guest
factory.setPassword("qiyun");//默认guest
//3.获取连接 Connection
Connection connection = factory.newConnection();
//4.创建Channel
Channel channel = connection.createChannel();
//5.创建队列Queue
/**
*
* queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)
* 参数:
* 1.queue:队列名称
* 2.durable:是否持久化,当mq重启之后还在
* 3.exclusive:
* *是否独占,只能有一个消费者监听这队列
* *当Connection关闭时,是否删除队列
* 4.autoDelete:是否自动删除,当没有Consumer时,自动删除掉
* 5.arguments:参数
*/
String queue1Name = "test_direct_queue1";
String queue2Name = "test_direct_queue2";
//6.接收消息
/**
* public String basicConsume(String queue, boolean autoAck, Consumer callback)
* 参数:
* 1.queue:队列名称
* 2.autoAck:是否自动确认
* 3.callback:回调对象
*/
Consumer consumer = new DefaultConsumer(channel){
/*
* 这是一个回调方法,当收到消息过后,会自动执行该方法
* 参数:
* 1.consumerTag:标识
* 2.envelope:获取对应的信息(交换机、路由Key......)
* 3.properties:配置信息
* 4.body:数据
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("body:"+new String(body));
System.out.println("将日志信息存储到数据库......");
}
};
channel.basicConsume(queue1Name,true,consumer);
//消费者不能关闭资源
}
}
消费者(队列2)接收消息把日志信息打印到控制台
/**
* 消费者,接收消息把日志信息打印到控制台
*/
public class Consumer_Routing2 {
public static void main(String[] args) throws IOException, TimeoutException {
//1.连接工厂
ConnectionFactory factory = new ConnectionFactory();
//2.设置参数
//2.1设置IP地址,默认值为localhost
factory.setHost("192.168.23.129");
//2.2设置端口,默认值5672
factory.setPort(5672);
//2.3设置虚拟机,默认值为/
factory.setVirtualHost("/zhenbao");
//2.4设置账号密码
factory.setUsername("qiyun");//默认guest
factory.setPassword("qiyun");//默认guest
//3.获取连接 Connection
Connection connection = factory.newConnection();
//4.创建Channel
Channel channel = connection.createChannel();
//5.创建队列Queue
/**
*
* queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)
* 参数:
* 1.queue:队列名称
* 2.durable:是否持久化,当mq重启之后还在
* 3.exclusive:
* *是否独占,只能有一个消费者监听这队列
* *当Connection关闭时,是否删除队列
* 4.autoDelete:是否自动删除,当没有Consumer时,自动删除掉
* 5.arguments:参数
*/
String queue1Name = "test_direct_queue1";
String queue2Name = "test_direct_queue2";
//6.接收消息
/**
* public String basicConsume(String queue, boolean autoAck, Consumer callback)
* 参数:
* 1.queue:队列名称
* 2.autoAck:是否自动确认
* 3.callback:回调对象
*/
Consumer consumer = new DefaultConsumer(channel){
/*
* 这是一个回调方法,当收到消息过后,会自动执行该方法
* 参数:
* 1.consumerTag:标识
* 2.envelope:获取对应的信息(交换机、路由Key......)
* 3.properties:配置信息
* 4.body:数据
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("body:"+new String(body));
System.out.println("将日志信息打印到控制台.....");
}
};
channel.basicConsume(queue2Name,true,consumer);
//消费者不能关闭资源
}
}
Topics通配符模式
模式说明:
- Topic主题模式可以实现Pub/Sub发布订阅模式和Routing路由模式的功能,只是Topic在配置routing key的时候可以使用通配符,显得更加灵活
- Topics通配符模式是通过*和#表达式来进行消息的分发
- *代表一个单词,而#代表0个单词或者多个单词
生产者发送消息
/**
* 生产者,发送消息
*/
public class Producer_Topics {
public static void main(String[] args) throws IOException, TimeoutException {
//1.连接工厂
ConnectionFactory factory = new ConnectionFactory();
//2.设置参数
//2.1设置IP地址,默认值为localhost
factory.setHost("192.168.23.129");
//2.2设置端口,默认值5672
factory.setPort(5672);
//2.3设置虚拟机,默认值为/
factory.setVirtualHost("/zhenbao");
//2.4设置账号密码
factory.setUsername("qiyun");//默认guest
factory.setPassword("qiyun");//默认guest
//3.获取连接 Connection
Connection connection = factory.newConnection();
//4.创建Channel
Channel channel = connection.createChannel();
//5.创建交换机
/*
* exchangeDeclare(String exchange, BuiltinExchangeType type, boolean durable, boolean autoDelete, boolean internal, Map<String, Object> arguments)
* 参数:
* 1.exchange:交换机名称
* 2.type:交换机的类型
* DIRECT("direct"):定向
* FANOUT("fanout"):扇形(广播),发送消息到每一个与之绑定的队列
* TOPIC("topic"):通配符的方式
* HEADERS("headers"):参数匹配
* 3.durable:是否持久化
* 4.autoDelete:是否自动删除
* 5.internal:内部使用,一般false
* 6.arguments:参数列表
*/
String exchangeName = "test_topic";
channel.exchangeDeclare(exchangeName, BuiltinExchangeType.TOPIC,true,false,false,null);
//6.创建队列
/**
*
* queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)
* 参数:
* 1.queue:队列名称
* 2.durable:是否持久化,当mq重启之后还在
* 3.exclusive:
* *是否独占,只能有一个消费者监听这队列
* *当Connection关闭时,是否删除队列
* 4.autoDelete:是否自动删除,当没有Consumer时,自动删除掉
* 5.arguments:参数
*/
String queue1Name = "test_topic_queue1";
String queue2Name = "test_topic_queue2";
channel.queueDeclare(queue1Name,true,false,false,null);
channel.queueDeclare(queue2Name,true,false,false,null);
//7.绑定队列和交换机
/**
* queueBind(String queue, String exchange, String routingKey)
* 参数:
* 1.queue:要绑定的队列名称
* 2.exchange:交换机名称
* 3.routingKey:路由键,绑定规则
* 如果交换机的类型为fanout,routingKey设置为""
*/
//routing key:系统的名称.日志的级别
//需求:所有error级别的日志存入数据库,所有order系统的日志存入数据库
channel.queueBind(queue1Name,exchangeName,"#.error");
channel.queueBind(queue1Name,exchangeName,"order.*");
//需求:希望所有的日志信息都打印到控制台上
channel.queueBind(queue2Name,exchangeName,"*.*");
//8.发送消息
String body = "日志信息:李四调用了findById的方法......日志级别为:info......";
channel.basicPublish(exchangeName,"www.info",null,body.getBytes());
//9.释放资源
channel.close();
connection.close();
}
}
消费者(队列1)接收消息后存入数据库
/**
* 消费者,接收消息后存入数据库
*/
public class Consumer_Topic1 {
public static void main(String[] args) throws IOException, TimeoutException {
//1.连接工厂
ConnectionFactory factory = new ConnectionFactory();
//2.设置参数
//2.1设置IP地址,默认值为localhost
factory.setHost("192.168.23.129");
//2.2设置端口,默认值5672
factory.setPort(5672);
//2.3设置虚拟机,默认值为/
factory.setVirtualHost("/zhenbao");
//2.4设置账号密码
factory.setUsername("qiyun");//默认guest
factory.setPassword("qiyun");//默认guest
//3.获取连接 Connection
Connection connection = factory.newConnection();
//4.创建Channel
Channel channel = connection.createChannel();
//5.创建队列Queue
/**
*
* queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)
* 参数:
* 1.queue:队列名称
* 2.durable:是否持久化,当mq重启之后还在
* 3.exclusive:
* *是否独占,只能有一个消费者监听这队列
* *当Connection关闭时,是否删除队列
* 4.autoDelete:是否自动删除,当没有Consumer时,自动删除掉
* 5.arguments:参数
*/
String queue1Name = "test_topic_queue1";
String queue2Name = "test_topic_queue2";
//6.接收消息
/**
* public String basicConsume(String queue, boolean autoAck, Consumer callback)
* 参数:
* 1.queue:队列名称
* 2.autoAck:是否自动确认
* 3.callback:回调对象
*/
Consumer consumer = new DefaultConsumer(channel){
/*
* 这是一个回调方法,当收到消息过后,会自动执行该方法
* 参数:
* 1.consumerTag:标识
* 2.envelope:获取对应的信息(交换机、路由Key......)
* 3.properties:配置信息
* 4.body:数据
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("body:"+new String(body));
System.out.println("将日志信息存储到数据库......");
}
};
channel.basicConsume(queue1Name,true,consumer);
//消费者不能关闭资源
}
}
消费者(队列2)接收消息后将日志信息打印到控制台
/**
* 消费者,接收消息后将日志信息打印到控制台
*/
public class Consumer_Topic2 {
public static void main(String[] args) throws IOException, TimeoutException {
//1.连接工厂
ConnectionFactory factory = new ConnectionFactory();
//2.设置参数
//2.1设置IP地址,默认值为localhost
factory.setHost("192.168.23.129");
//2.2设置端口,默认值5672
factory.setPort(5672);
//2.3设置虚拟机,默认值为/
factory.setVirtualHost("/zhenbao");
//2.4设置账号密码
factory.setUsername("qiyun");//默认guest
factory.setPassword("qiyun");//默认guest
//3.获取连接 Connection
Connection connection = factory.newConnection();
//4.创建Channel
Channel channel = connection.createChannel();
//5.创建队列Queue
/**
*
* queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)
* 参数:
* 1.queue:队列名称
* 2.durable:是否持久化,当mq重启之后还在
* 3.exclusive:
* *是否独占,只能有一个消费者监听这队列
* *当Connection关闭时,是否删除队列
* 4.autoDelete:是否自动删除,当没有Consumer时,自动删除掉
* 5.arguments:参数
*/
String queue1Name = "test_topic_queue1";
String queue2Name = "test_topic_queue2";
//6.接收消息
/**
* public String basicConsume(String queue, boolean autoAck, Consumer callback)
* 参数:
* 1.queue:队列名称
* 2.autoAck:是否自动确认
* 3.callback:回调对象
*/
Consumer consumer = new DefaultConsumer(channel){
/*
* 这是一个回调方法,当收到消息过后,会自动执行该方法
* 参数:
* 1.consumerTag:标识
* 2.envelope:获取对应的信息(交换机、路由Key......)
* 3.properties:配置信息
* 4.body:数据
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("body:"+new String(body));
System.out.println("将日志信息打印到控制台......");
}
};
channel.basicConsume(queue2Name,true,consumer);
//消费者不能关闭资源
}
}