目录
开发步骤
引入client
生产者
消费者
应用场景
简单队列
工作队列
发布/订阅
路由模式
topic模式
rpc模式
发布确认
com.rabbitmq
amqp-client
5.2.0
1、引入类
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.Channel;
2、创建Connection
ConnectionFactory factory = new ConnectionFactory();
// 设置服务地址
factory.setHost("127.0.0.1");
// 端口
factory.setPort(5672);
// vhost
factory.setVirtualHost("/vhost_test");
// 用户名
factory.setUsername("admin");
// 密码
factory.setPassword("123456");
Connection connection = factory.newConnection();
3、创建Channel
Channel channel = connection.createChannel()
channel设置:
4、声明交换器、队列
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
exchange声明:
DeclareOk exchangeDeclare(String exchange, String type) throws IOException;
DeclareOk exchangeDeclare(String exchange, BuiltinExchangeType type) throws IOException;
DeclareOk exchangeDeclare(String exchange, String type, boolean durable) throws IOException;
DeclareOk exchangeDeclare(String exchange, BuiltinExchangeType type, boolean durable) throws IOException;
DeclareOk exchangeDeclare(String exchange, String type, boolean durable, boolean autoDelete, Map arguments) throws IOException;
DeclareOk exchangeDeclare(String exchange, BuiltinExchangeType type, boolean durable, boolean autoDelete, Map arguments) throws IOException;
DeclareOk exchangeDeclare(String exchange, String type, boolean durable, boolean autoDelete, boolean internal, Map arguments) throws IOException;
DeclareOk exchangeDeclare(String exchange, BuiltinExchangeType type, boolean durable, boolean autoDelete, boolean internal, Map arguments) throws IOException;
参数说明:
exchange:exchange名称
type:exchange类型,BuiltinExchangeType 枚举类型包括:fanout,direct,topic,header。
durable:是否持久化
internal:是否内部exchange,生产者不能直接发布到内部exchange。
arguments:其他参数,用于构造exchange。
队列声明:
DeclareOk queueDeclare() throws IOException;
DeclareOk queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map arguments) throws IOException;
参数说明:
5、发送消息
String message = "Hello World!";
channel.basicPublish("", QUEUE_NAME, null, message.getBytes());
void basicPublish(String exchange, String routingKey, AMQP.BasicProperties props, byte[] body) throws IOException;
void basicPublish(String exchange, String routingKey, boolean mandatory, AMQP.BasicProperties props, byte[] body) throws IOException;
void basicPublish(String exchange, String routingKey, boolean mandatory, boolean immediate, AMQP.BasicProperties props, byte[] body) throws IOException;
参数说明:
mandatory标志告诉服务器至少将该消息route到一个队列中,否则将消息返还给生产者;immediate标志告诉服务器如果该消息关联的queue上有消费者,则马上将消息投递给它,如果所有queue都没有消费者,直接把消息返还给生产者,不用将消息入队列等待消费者了。
在RabbitMQ3.0以后的版本里,去掉了immediate参数的支持,发送带immediate标记的publish会返回如下错误:
“{amqp_error,not_implemented,“immediate=true”,‘basic.publish’}”,immediate标记会影响镜像队列性能,增加代码复杂性,并建议采用“TTL”和“DLX”等方式替代。
1、引入类
同生产者
2、创建Connection
同生产者
3、创建Channel
同生产者
4、声明交换器,队列
同生产者
5、构造Consumer
// 创建消费者
Consumer consumer = new DefaultConsumer(channel) {
// 获取消息
@Override
public void handleDelivery(String consumerTag, Envelope envelope, BasicProperties properties, byte[] body)
throws IOException {
String msg = new String(body, "utf-8");
System.out.println("接收到消息——" + msg);
}
};
6、接收消息并处理
// 监听队列
channel.basicConsume(QUEUE, true, consumer);
String basicConsume(String queue, Consumer callback) throws IOException
String basicConsume(String queue, DeliverCallback deliverCallback, CancelCallback cancelCallback) throws IOException
String basicConsume(String queue, DeliverCallback deliverCallback, ConsumerShutdownSignalCallback shutdownSignalCallback) throws IOException
String basicConsume(String queue, DeliverCallback deliverCallback, CancelCallback cancelCallback, ConsumerShutdownSignalCallback shutdownSignalCallback) throws IOException
String basicConsume(String queue, boolean autoAck, Consumer callback) throws IOException
String basicConsume(String queue, boolean autoAck, DeliverCallback deliverCallback, CancelCallback cancelCallback) throws IOException
String basicConsume(String queue, boolean autoAck, DeliverCallback deliverCallback, ConsumerShutdownSignalCallback shutdownSignalCallback) throws IOException
String basicConsume(String queue, boolean autoAck, DeliverCallback deliverCallback, CancelCallback cancelCallback, ConsumerShutdownSignalCallback shutdownSignalCallback) throws IOException
String basicConsume(String queue, boolean autoAck, Map arguments, Consumer callback) throws IOException
String basicConsume(String queue, boolean autoAck, Map arguments, DeliverCallback deliverCallback, CancelCallback cancelCallback) throws IOException
String basicConsume(String queue, boolean autoAck, Map arguments, DeliverCallback deliverCallback, ConsumerShutdownSignalCallback shutdownSignalCallback) throws IOException
String basicConsume(String queue, boolean autoAck, Map arguments, DeliverCallback deliverCallback, CancelCallback cancelCallback, ConsumerShutdownSignalCallback shutdownSignalCallback) throws IOException
String basicConsume(String queue, boolean autoAck, String consumerTag, Consumer callback) throws IOException
String basicConsume(String queue, boolean autoAck, String consumerTag, DeliverCallback deliverCallback, CancelCallback cancelCallback) throws IOException
String basicConsume(String queue, boolean autoAck, String consumerTag, DeliverCallback deliverCallback, ConsumerShutdownSignalCallback shutdownSignalCallback) throws IOException
String basicConsume(String queue, boolean autoAck, String consumerTag, DeliverCallback deliverCallback, CancelCallback cancelCallback, ConsumerShutdownSignalCallback shutdownSignalCallback) throws IOException
String basicConsume(String queue, boolean autoAck, String consumerTag, boolean noLocal, boolean exclusive, Map arguments, Consumer callback) throws IOException
String basicConsume(String queue, boolean autoAck, String consumerTag, boolean noLocal, boolean exclusive, Map arguments, DeliverCallback deliverCallback, CancelCallback cancelCallback) throws IOException
String basicConsume(String queue, boolean autoAck, String consumerTag, boolean noLocal, boolean exclusive, Map arguments, DeliverCallback deliverCallback, ConsumerShutdownSignalCallback shutdownSignalCallback) throws IOException
String basicConsume(String queue, boolean autoAck, String consumerTag, boolean noLocal, boolean exclusive, Map arguments, DeliverCallback deliverCallback, CancelCallback cancelCallback, ConsumerShutdownSignalCallback shutdownSignalCallback) throws IOException
参数说明:
public interface Consumer {
//Called when the consumer is cancelled for reasons other than by a call to Channel.basicCancel(java.lang.String).
void handleCancel(String consumerTag)
// Called when the consumer is cancelled by a call to Channel.basicCancel(java.lang.String).
void handleCancelOk(String consumerTag)
//Called when the consumer is registered by a call to any of the Channel.basicConsume(java.lang.String, com.rabbitmq.client.Consumer) methods.
void handleConsumeOk(String consumerTag)
//Called when a basic.deliver is received for this consumer.
void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body)
//Called when a basic.recover-ok is received in reply to a basic.recover.
void handleRecoverOk(String consumerTag)
// Called when either the channel or the underlying connection has been shut down.
void handleShutdownSignal(String consumerTag, ShutdownSignalException sig)
}
应用场景 | exchange | 队列 | 生产者端 | 消费者端 |
简单队列 | 无 | 单个队列 | 发送到指定队列 | 自动应答 |
工作队列 | 无 | 多个队列 | 发送到指定队列 | 自动应答/ 手动应答,公平分发 |
发布/订阅 | fanout | 多个队列 | 发送到指定exchange,不设置routing key | 消费指定队列。 |
路由模式 | direct | 多个队列 | 发送到指定exchange,设置routing key | 消费指定队列。指定1个或者多个binging key |
topic模式 | topic | 多个队列 | 发送到指定exchange,设置routing key。key中包含点号(.)。 | 消费指定队列。指定1个或者多个binging key,key中包含点号(.)。 |
rpc | ||||
发布确认 |
生产者直接发送消息到队列,消费者直接消费队列消息。
/*生产者代码 */
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
String message = "Hello World!";
//直接发送消息到队列。exchange参数为""
channel.basicPublish("", QUEUE_NAME, null, message.getBytes());
System.out.println(" [x] Sent '" + message + "'");
/* 消费者代码 */
//声明队列
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
//定义消息消费
DeliverCallback deliverCallback = (consumerTag, delivery) -> {
String message = new String(delivery.getBody(), "UTF-8");
System.out.println(" [x] Received '" + message + "'");
};
//开始消费
channel.basicConsume(QUEUE_NAME, true, deliverCallback, consumerTag -> { });
一般在实际应用中,生产者发送消息耗时较少,反应较快,反而是消费者因为要处理业务逻辑,处理时间可能会很慢,这样队列中会积压很多消息,所以需要多个消费者分摊压力,这个时候可以使用工作队列。
生产者消费者代码与简单队列一样,差别为运行多个消费者代码实例。
消费者默认采用Round-robin方式轮询分发,每个消费者接收到的消息数基本一样。如果消费者处理消息速度不一致,会导致一个空闲,一个繁忙。
可以采用公平模式,如果消费者未处理完消息,则队列不会再发送消息给此消费者,只到上一条消息处理完。
修改:
int prefetchCount = 1;
//设置每次仅接收1条消息。
channel.basicQos(prefetchCount);
try {
doWork(message);
} finally {
System.out.println(" [x] Done");
//手动确认消息
channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
}
channel.basicConsume(TASK_QUEUE_NAME, false, deliverCallback, consumerTag -> { });
生产者没有把消费发送给队列,而是发送给exchange,由exchange进行路由到绑定的队列,消费者仅消费对应队列,例如事件通知通过邮件和短信进行通知。
exchange的类型为fanout。
private static final String EXCHANGE_NAME = "logs";
//声明一个exchange:logs
channel.exchangeDeclare(EXCHANGE_NAME, "fanout");
//发送消息到exchange:logs
channel.basicPublish( "logs", "", null, message.getBytes());
private static final String EXCHANGE_NAME = "logs";
//声明exchange:logs
channel.exchangeDeclare(EXCHANGE_NAME, "fanout");
//声明一个随机名称的临时队列
String queueName = channel.queueDeclare().getQueue();
//绑定队列与exchange
channel.queueBind(queueName, EXCHANGE_NAME, "");
DeliverCallback deliverCallback = (consumerTag, delivery) -> {
String message = new String(delivery.getBody(), "UTF-8");
System.out.println(" [x] Received '" + message + "'");
};
//开始消费临时队列:
channel.basicConsume(queueName, true, deliverCallback, consumerTag -> { });
exchange类型为direct。
private static final String EXCHANGE_NAME = "direct_logs";
//指定exchange为direct
channel.exchangeDeclare(EXCHANGE_NAME, "direct");
String severity = getSeverity(argv);
String message = getMessage(argv);
//指定routing key:severity
channel.basicPublish(EXCHANGE_NAME, severity, null, message.getBytes("UTF-8"));
//声明exchange:类型为:direct
channel.exchangeDeclare(EXCHANGE_NAME, "direct");
String queueName = channel.queueDeclare().getQueue();
//绑定队列与exchange,routing key:severity
for (String severity : argv) {
channel.queueBind(queueName, EXCHANGE_NAME, severity);
}
DeliverCallback deliverCallback = (consumerTag, delivery) -> {
String message = new String(delivery.getBody(), "UTF-8");
System.out.println(" [x] Received '" +
delivery.getEnvelope().getRoutingKey() + "':'" + message + "'");
};
//消费消息
channel.basicConsume(queueName, true, deliverCallback, consumerTag -> { });
}
exchange类型为topic。
topic模式与direct模式代码一样,区别为binding key与routing key 必须包含点号(.)。
channel.exchangeDeclare(EXCHANGE_NAME, "topic");
String routingKey = getRouting(argv);
String message = getMessage(argv);
channel.basicPublish(EXCHANGE_NAME, routingKey, null, message.getBytes("UTF-8"));
channel.exchangeDeclare(EXCHANGE_NAME, "topic");
String queueName = channel.queueDeclare().getQueue();
for (String bindingKey : argv) {
channel.queueBind(queueName, EXCHANGE_NAME, bindingKey);
}
System.out.println(" [*] Waiting for messages. To exit press CTRL+C");
DeliverCallback deliverCallback = (consumerTag, delivery) -> {
String message = new String(delivery.getBody(), "UTF-8");
System.out.println(" [x] Received '" +
delivery.getEnvelope().getRoutingKey() + "':'" + message + "'");
};
channel.basicConsume(queueName, true, deliverCallback, consumerTag -> { });