<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.14.2</version>
</dependency>
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeoutException;
/**
* @Description 生产者
* @Author chanyu
* @Date 2022/5/25 19:08
* @Version 1.0
**/
public class Producer {
private final static String QUEUE_NAME = "测试队列";
public static void main(String[] args) throws IOException, TimeoutException {
// 1.创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
factory.setUsername("admin");
factory.setPassword("admin");
factory.setVirtualHost("/");
Connection connection = null;
Channel channel = null;
try{
// 2.创建连接
connection = factory.newConnection("生产者");
// 3.获取通道
channel = connection.createChannel();
/**
* 队列名
* 是否持久化
* 是否排他,是否是独占独立
* 是否自动删除,随最后一个消息消费完毕后是否自动删除队列
* 携带其他参数
*/
// 4.通过通道声明队列
channel.queueDeclare(QUEUE_NAME,false,false,false,null);
// 5.发布消息
String msg = "一条消息";
channel.basicPublish("",QUEUE_NAME,null,msg.getBytes(StandardCharsets.UTF_8));
}finally {
// 6.关闭通道
if (channel!=null && channel.isOpen()){
channel.close();
}
// 7.关闭连接
if (connection!=null && connection.isOpen()){
connection.close();
}
}
}
}
import com.rabbitmq.client.*;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @Description 消费者
* @Author chanyu
* @Date 2022/5/25 19:08
* @Version 1.0
**/
@Slf4j
public class Comsumer {
private final static String QUEUE_NAME = "测试队列";
public static void main(String[] args) throws IOException, TimeoutException {
// 1.创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
factory.setUsername("admin");
factory.setPassword("admin");
factory.setVirtualHost("/");
Connection connection = null;
Channel channel = null;
try{
// 2.创建连接
connection = factory.newConnection("生产者");
// 3.获取通道
channel = connection.createChannel();
// 4.消费消息
channel.basicConsume(QUEUE_NAME, true, new DeliverCallback() {
@Override
public void handle(String consumerTag, Delivery message) throws IOException {
log.info("consumerTag:{}", consumerTag);
log.info("消费消息:{}", new String(message.getBody(), "UTF-8"));
}
}, new CancelCallback() {
@Override
public void handle(String consumerTag) throws IOException {
log.info("consumerTag:{}", consumerTag);
log.info("消费消息失败");
}
});
}finally {
// 5.关闭通道
if (channel!=null && channel.isOpen()){
channel.close();
}
// 6.关闭连接
if (connection!=null && connection.isOpen()){
connection.close();
}
}
}
}
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.MessageProperties;
public class NewTask {
private static final String TASK_QUEUE_NAME = "task_queue";
private static final String[] msg = new String[]{"jdkssd.dds", "d23d.2w.ttt", "2332.uyyt", "eewe.764", "dsada.55"};
public static void main(String[] argv) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
try (Connection connection = factory.newConnection();
Channel channel = connection.createChannel()) {
channel.queueDeclare(TASK_QUEUE_NAME, true, false, false, null);
String message = String.join(" ", msg);
channel.basicPublish("", TASK_QUEUE_NAME,
MessageProperties.PERSISTENT_TEXT_PLAIN,
message.getBytes("UTF-8"));
System.out.println(" [x] Sent '" + message + "'");
}
}
}
任务执行者
消息确认
完成一项任务可能需要几秒钟。一旦 RabbitMQ 将消息传递给消费者,它会立即将其标记为删除。在这种情况下,如果消费者出了问题。将丢失所有发送给该消费者但尚未处理的消息。
但是我们不想丢失任何任务。我们希望将任务交付给另一个消费者。
为了确保消息永远不会丢失,RabbitMQ 支持消息确认。消费者发回一个确认,告诉 RabbitMQ 一个特定的消息已经被接收、处理并且 RabbitMQ 可以自由地删除它。
如果消费者在没有发送 ack 的情况下死亡(其通道关闭、连接关闭或 TCP 连接丢失),RabbitMQ 将理解消息未完全处理并将重新排队。如果同时有其他消费者在线,它会迅速将其重新发送给另一个消费者。这样,即使消费者偶尔异常,也可以确保不会丢失任何消息。
对消费者交付确认强制执行超时(默认为 30 分钟)。
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.DeliverCallback;
public class Worker {
private static final String TASK_QUEUE_NAME = "task_queue";
public static void main(String[] argv) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
final Connection connection = factory.newConnection();
final Channel channel = connection.createChannel();
channel.queueDeclare(TASK_QUEUE_NAME, true, false, false, null);
// 公平调度,消费完(响应)完才继续接受任务。不设置该项则是默认轮询调度
channel.basicQos(1);
DeliverCallback deliverCallback = (consumerTag, delivery) -> {
String message = new String(delivery.getBody(), "UTF-8");
System.out.println(" [x] Received '" + message + "'");
try {
doWork(message);
} finally {
System.out.println(" [x] Done");
// 消息确认
// 确认收到一个或多个消息
channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
}
};
channel.basicConsume(TASK_QUEUE_NAME, false, deliverCallback, consumerTag -> {
});
}
private static void doWork(String task) {
for (char ch : task.toCharArray()) {
if (ch == '.') {
try {
Thread.sleep(1000);
} catch (InterruptedException _ignored) {
Thread.currentThread().interrupt();
}
}
}
}
}
fanout交换机,只要绑定了该交换机的队列都会收到消息,与routingkey无关。
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeoutException;
/**
* @Description 生产者
* @Author chanyu
* @Date 2022/5/25 19:08
* @Version 1.0
**/
public class Producer {
public static void main(String[] args) throws IOException, TimeoutException {
// 1.创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection connection = null;
Channel channel = null;
try{
// 2.创建连接
connection = factory.newConnection("生产者");
// 3.获取通道
channel = connection.createChannel();
/**
* 队列名
* 是否持久化(非持久化队列会随服务器重启取消,消息也一样)
* 是否排他,是否是独占独立
* 是否自动删除,随最后一个消息消费完毕后是否自动删除队列
* 携带其他参数
*/
// 通过通道声明队列
channel.queueDeclare("fanoutqueue1",true,false,false,null);
channel.queueDeclare("fanoutqueue2",true,false,false,null);
// 4.发布消息
String msg = "一条消息";
// 5.准备交换机 交换机类型
String exchangeName = "fanoutExchange";
String type = "fanout";
// fanout 模式下 routekey无效,会发布给所有绑定了该交换机的队列
channel.exchangeDeclare(exchangeName,type,true,false,null);
String routeKey = "";
// 队列绑定交换机
channel.queueBind("fanoutqueue1",exchangeName,routeKey);
channel.queueBind("fanoutqueue2",exchangeName,routeKey);
channel.basicPublish(exchangeName,routeKey,null,msg.getBytes(StandardCharsets.UTF_8));
}finally {
// 6.关闭通道
if (channel!=null && channel.isOpen()){
channel.close();
}
// 7.关闭连接
if (connection!=null && connection.isOpen()){
connection.close();
}
}
}
}
import com.rabbitmq.client.*;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @Description 消费者
* @Author chanyu
* @Date 2022/5/25 19:08
* @Version 1.0
**/
@Slf4j
public class Consumer implements Runnable{
@SneakyThrows
@Override
public void run() {
// 1.创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
factory.setUsername("admin");
factory.setPassword("admin");
factory.setVirtualHost("/");
Connection connection = null;
Channel channel = null;
try{
// 2.创建连接
connection = factory.newConnection("生产者");
// 3.获取通道
channel = connection.createChannel();
String queue_name = Thread.currentThread().getName();
// 4.消费消息
channel.basicConsume(queue_name, true, new DeliverCallback() {
@Override
public void handle(String consumerTag, Delivery message) throws IOException {
log.info("{}消费消息:{}",queue_name, new String(message.getBody(), "UTF-8"));
}
}, new CancelCallback() {
@Override
public void handle(String consumerTag) throws IOException {
log.info("消费消息失败");
}
});
System.in.read();
}finally {
// 5.关闭通道
if (channel!=null && channel.isOpen()){
channel.close();
}
// 6.关闭连接
if (connection!=null && connection.isOpen()){
connection.close();
}
}
}
public static void main(String[] args) throws IOException, TimeoutException {
new Thread(new Consumer(),"fanoutqueue1").start();
new Thread(new Consumer(),"fanoutqueue2").start();
}
}
在fanout的基础上,通过routingkey来筛选发送消息的队列。
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeoutException;
/**
* @Description 生产者
* @Author chanyu
* @Date 2022/5/25 19:08
* @Version 1.0
**/
public class Producer {
public static void main(String[] args) throws IOException, TimeoutException {
// 1.创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection connection = null;
Channel channel = null;
try{
// 2.创建连接
connection = factory.newConnection("生产者");
// 3.获取通道
channel = connection.createChannel();
/**
* 队列名
* 是否持久化(非持久化队列会随服务器重启取消,消息也一样)
* 是否排他,是否是独占独立
* 是否自动删除,随最后一个消息消费完毕后是否自动删除队列
* 携带其他参数
*/
// 通过通道声明队列
channel.queueDeclare("directqueue1",true,false,false,null);
channel.queueDeclare("directqueue2",true,false,false,null);
// 4.发布消息
String msg = "一条消息";
// 5.准备交换机 交换机类型
String exchangeName = "directExchange";
String type = "direct";
// direct 模式下 routekey有效,会发布给所有绑定了该交换机的队列
channel.exchangeDeclare(exchangeName,type,true,false,null);
// 队列绑定交换机
channel.queueBind("directqueue1",exchangeName,"email");
channel.queueBind("directqueue2",exchangeName,"sms");
// 发布给路由为email的队列
channel.basicPublish(exchangeName,"email",null,msg.getBytes(StandardCharsets.UTF_8));
}finally {
// 6.关闭通道
if (channel!=null && channel.isOpen()){
channel.close();
}
// 7.关闭连接
if (connection!=null && connection.isOpen()){
connection.close();
}
}
}
}
import com.rabbitmq.client.*;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @Description 消费者
* @Author chanyu
* @Date 2022/5/25 19:08
* @Version 1.0
**/
@Slf4j
public class Consumer implements Runnable{
@SneakyThrows
@Override
public void run() {
// 1.创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
factory.setUsername("admin");
factory.setPassword("admin");
factory.setVirtualHost("/");
Connection connection = null;
Channel channel = null;
try{
// 2.创建连接
connection = factory.newConnection("生产者");
// 3.获取通道
channel = connection.createChannel();
String queue_name = Thread.currentThread().getName();
// 4.消费消息
channel.basicConsume(queue_name, true, new DeliverCallback() {
@Override
public void handle(String consumerTag, Delivery message) throws IOException {
log.info("{}消费消息:{}",queue_name, new String(message.getBody(), "UTF-8"));
}
}, new CancelCallback() {
@Override
public void handle(String consumerTag) throws IOException {
log.info("消费消息失败");
}
});
System.in.read();
}finally {
// 5.关闭通道
if (channel!=null && channel.isOpen()){
channel.close();
}
// 6.关闭连接
if (connection!=null && connection.isOpen()){
connection.close();
}
}
}
// 结果是只有directqueue1 email路由的队列才有消费信息
public static void main(String[] args) throws IOException, TimeoutException {
new Thread(new Consumer(),"directqueue1").start();
new Thread(new Consumer(),"directqueue2").start();
}
}
主题模式,路由模糊匹配,.# 匹配零级或多级,.*匹配1级。
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeoutException;
/**
* @Description 生产者
* @Author chanyu
* @Date 2022/5/25 19:08
* @Version 1.0
**/
public class Producer {
public static void main(String[] args) throws IOException, TimeoutException {
// 1.创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection connection = null;
Channel channel = null;
try{
// 2.创建连接
connection = factory.newConnection("生产者");
// 3.获取通道
channel = connection.createChannel();
/**
* 队列名
* 是否持久化(非持久化队列会随服务器重启取消,消息也一样)
* 是否排他,是否是独占独立
* 是否自动删除,随最后一个消息消费完毕后是否自动删除队列
* 携带其他参数
*/
// 通过通道声明队列
channel.queueDeclare("topicqueue1",true,false,false,null);
channel.queueDeclare("topicqueue2",true,false,false,null);
channel.queueDeclare("topicqueue3",true,false,false,null);
channel.queueDeclare("topicqueue4",true,false,false,null);
// 4.发布消息
String msg = "一条消息";
// 5.准备交换机 交换机类型
String exchangeName = "topicExchange";
String type = "topic";
// direct 模式下 routekey有效,会发布给所有绑定了该交换机的队列
channel.exchangeDeclare(exchangeName,type,true,false,null);
// .*是至少有1级 .#是有0--n级
// 队列绑定交换机
channel.queueBind("topicqueue1",exchangeName,"com.#");
channel.queueBind("topicqueue2",exchangeName,"*.test.*");
channel.queueBind("topicqueue3",exchangeName,"#.cy.#");
channel.queueBind("topicqueue4",exchangeName,"#.user.*");
// 发布给路由为email的队列
String routingKey = "com.test.cy.user.xxx";
channel.basicPublish(exchangeName,routingKey,null,msg.getBytes(StandardCharsets.UTF_8));
}finally {
// 6.关闭通道
if (channel!=null && channel.isOpen()){
channel.close();
}
// 7.关闭连接
if (connection!=null && connection.isOpen()){
connection.close();
}
}
}
}
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeoutException;
/**
* @Description 生产者
* @Author chanyu
* @Date 2022/5/25 19:08
* @Version 1.0
**/
public class Producer {
public static void main(String[] args) throws IOException, TimeoutException {
// 1.创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection connection = null;
Channel channel = null;
try{
// 2.创建连接
connection = factory.newConnection("生产者");
// 3.获取通道
channel = connection.createChannel();
/**
* 队列名
* 是否持久化(非持久化队列会随服务器重启取消,消息也一样)
* 是否排他,是否是独占独立
* 是否自动删除,随最后一个消息消费完毕后是否自动删除队列
* 携带其他参数
*/
// 通过通道声明队列
channel.queueDeclare("topicqueue1",true,false,false,null);
channel.queueDeclare("topicqueue2",true,false,false,null);
channel.queueDeclare("topicqueue3",true,false,false,null);
channel.queueDeclare("topicqueue4",true,false,false,null);
// 4.发布消息
String msg = "一条消息";
// 5.准备交换机 交换机类型
String exchangeName = "topicExchange";
String type = "topic";
// direct 模式下 routekey有效,会发布给所有绑定了该交换机的队列
channel.exchangeDeclare(exchangeName,type,true,false,null);
// .*是有且仅有一个(一级) .#是有零个(零级)或多个(多级)
// 队列绑定交换机
channel.queueBind("topicqueue1",exchangeName,"com.#");
channel.queueBind("topicqueue2",exchangeName,"*.test.*");
channel.queueBind("topicqueue3",exchangeName,"#.cy.#");
channel.queueBind("topicqueue4",exchangeName,"#.user.*");
// 发布给路由为email的队列
String routingKey = "com.test.cy.user.xxx";
channel.basicPublish(exchangeName,routingKey,null,msg.getBytes(StandardCharsets.UTF_8));
}finally {
// 6.关闭通道
if (channel!=null && channel.isOpen()){
channel.close();
}
// 7.关闭连接
if (connection!=null && connection.isOpen()){
connection.close();
}
}
}
}
未绑定交换机的队列,都是绑定默认交换机。
消息都是通过交换机给队列。
管理平台中,队列中获取消息要使用nack(不消费)方式获取查看消息。
如果使用ack方式会消费掉消息。
交换机类型:
fanout:发布订阅,所有绑定该交换机的都会收到消息,与路由key无关。
direct :处理路由键,带路由发送消息。
topic :模糊匹配的路由key。匹配规则:# 代表0–n级,*代表必须有一级。
Headers :根据参数匹配(发布时带入参数,消费端匹配)。