这是我的连接工具类:
public class RabbitMqUtils {
public static Channel getChannel() throws Exception {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("192.168.195.130");
factory.setPort(5672);
factory.setUsername("admin");
factory.setPassword("admin");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
return channel;
}
}
交换机和队列的声明、绑定在生产者和消费者端都可以。声明是不区分哪一端的,连接的客户端也不区分生产者还是消费者,生产者和消费者的区别只是Channel调用的是basicConsume()还是basicPublish()的区别。 完全可以消费者消费完,然后Channel调用basicPublish()变成生产者进行发送消息。
最好是生产者端声明交换机,消费者端再次声明交换机、声明队列、并进行绑定。队列和交换机需要都存在才能绑定。
其实不需要手动声明交换机和队列都可以,但是Broker中必须要有要使用的交换机和队列。使用交换机和队列的原则是:rabbitmq服务端(Broker)含有交换机和队列,先声明,后使用
只不过为了不影响使用,编写代码时也要声明(declare)一下,再次声明一个交换机/队列不会影响原来存在的。再次声明在rabbitmq服务端(Broker)有就使用,没有就声明一个。
生产者:声明交换机
Channel channel = RabbitMqUtils.getChannel();
channel.exchangeDeclare("AA", "topic");
channel.basicPublish("AA", bindingKey, null, "生产者发送消息了");
消费者: 声明交换机和队列,并进行绑定
Channel channel = RabbitMqUtils.getChannel();
channel.exchangeDeclare("AA", "topic");
String queueName = "Q1";
channel.queueDeclare(queueName, false, false, false, null);
channel.queueBind(queueName, EXCHANGE_NAME, "*.*.rabbit");
上面只是在普通java工程中演示。在springboot工程中,我们一般把交换机和队列都在配置类中声明和绑定,这样就能和业务代码解耦。
比如如图下一个消息队列架构: 我们可以创建一个这样的配置类,把对应的交换机、队列、已经绑定关系在里面配置好:
package com.atguigu.rabbitmq.bootrabbitmq.config;
import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class TtlQueueConfig {
public static final String X_EXCHANGE = "X";
public static final String QUEUE_A = "QA";
public static final String QUEUE_B = "QB";
public static final String Y_DEAD_LETTER_EXCHANGE = "Y";
public static final String DEAD_LETTER_QUEUE = "QD";
@Bean("xExchange")
public DirectExchange xExchange() {
return new DirectExchange(X_EXCHANGE);
}
@Bean("yExchange")
public DirectExchange yExchange() {
return new DirectExchange(Y_DEAD_LETTER_EXCHANGE);
}
@Bean("queueA")
public Queue queueA() {
Map<String, Object> args = new HashMap<>(3);
args.put("x-dead-letter-exchange", Y_DEAD_LETTER_EXCHANGE);
args.put("x-dead-letter-routing-key", "YD");
args.put("x-message-ttl", 10000);
return QueueBuilder.durable(QUEUE_A).withArguments(args).build();
}
@Bean
public Binding queueaBindingX(@Qualifier("queueA") Queue queueA,
@Qualifier("xExchange") DirectExchange xExchange) {
return BindingBuilder.bind(queueA).to(xExchange).with("XA");
}
@Bean("queueB")
public Queue queueB() {
Map<String, Object> args = new HashMap<>(3);
args.put("x-dead-letter-exchange", Y_DEAD_LETTER_EXCHANGE);
args.put("x-dead-letter-routing-key", "YD");
args.put("x-message-ttl", 40000);
return QueueBuilder.durable(QUEUE_B).withArguments(args).build();
}
@Bean
public Binding queuebBindingX(@Qualifier("queueB") Queue queue1B,
@Qualifier("xExchange") DirectExchange xExchange) {
return BindingBuilder.bind(queue1B).to(xExchange).with("XB");
}
@Bean("queueD")
public Queue queueD() {
return new Queue(DEAD_LETTER_QUEUE);
}
@Bean
public Binding deadLetterBindingQAD(@Qualifier("queueD") Queue queueD,
@Qualifier("yExchange") DirectExchange yExchange) {
return BindingBuilder.bind(queueD).to(yExchange).with("YD");
}
}
然后使用Spring的RabbitTemplate,生产者就可以给消息队列发送消息
rabbitTemplate.convertAndSend("X", "XA", "消息来自 ttl 为 10S 的队列: "+message);
rabbitTemplate.convertAndSend("X", "XB", "消息来自 ttl 为 40S 的队列: "+message);
而消费者是通过监听器监听队列的消息,因此要写一个监听器
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.Date;
@Slf4j
@Component
public class DeadLetterQueueConsumer {
@RabbitListener(queues = "QD")
public void receiveD(Message message, Channel channel) throws IOException {
String msg = new String(message.getBody());
log.info("当前时间:{},收到死信队列信息{}", new Date().toString(), msg);
}
}
|