前回の記事では 中springboot統合RabbitMQの、私たちは、この記事の簡単な統合springbootとRabbitMQのを実現し、物品の機能を強化するために主にある、それは、以下の機能を実行します。
要件:
ブート時にプロデューサー、自動的に作成したキュー、結合、スイッチおよび設定良い死の手紙交換、バックアップスイッチ(代替交換)。メッセージプロデューサによって送信された後、メッセージのプロデューサ側は、受信したメッセージのRabbitMQの確認応答を送信する必要があります。メッセージはなく、メッセージ、送信者のルーティングデッドレターをテストするために、変速機11が正常で、メッセージは、代替交換にそのスイッチに、メッセージキューにルーティングされないメッセージを送信し、メッセージキューにルーティングされてもよいですインチ メッセージ、乱数拒否メッセージを受信した後、受信者は、X-デッドレター交換媒体中にそれを作ります。
以下の機能を実現します:
1、@Beanモードを自動的に切り替え、バインディングの作成、キューに入れます。
2、@RabbitListenerメッセージキューリスナーを使用しました。
3、達成するための確認メッセージプロデューサ。
4、不正メール交換を達成するために(期限切れのメッセージ、basic.nackまたはbasic.rejectと再キューイングパラメータがfalseであるか、完全なメッセージをキューすると、スイッチが入ります)。
図5に示すように、バックアップスイッチ(代替交換)、メッセージの適切なルーティングが、このスイッチを通過しません。
機能の一部を実現するために重要:
1、メッセージプロデューサ確認
| - trueにspring.rabbitmq.template.mandatory = trueをセット
| - 设置spring.rabbitmq.publisher-確認=真成真
| - 私たちは、メッセージがRabbitMQのサーバに到達したことを確認することが可能なインターフェースRabbitTemplate.ConfirmCallbackを実装するJavaクラスを記述します。
図2に示すように、実施交換不正メール
| - X-デッドレター交換パラメータを設定する際にキューを宣言
図3に示すように、ルーティングメッセージ処理ではありません
| - スイッチは、代替交換パラメータを設定する際に述べました
手順は次のとおりです。
1、ジャーパッケージを問わず、生産者と消費者を紹介しました
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
図2に示すように、生産者 - プロファイル
server:
port: 9088
spring:
rabbitmq:
host: 140.143.237.224
port: 5672
username: root
password: root
virtual-host: /
connection-timeout: 10000
template:
mandatory: true
publisher-confirms: true
注意:ここでは、必要とtrueに必須パラメータを出版社が、確認
3、プロデューサー - プロデューサー書かれた確認メッセージ
@Slf4j
public class RabbitConfirmCallback implements RabbitTemplate.ConfirmCallback {
@Override
public void confirm(CorrelationData correlationData, boolean ack, String cause) {
log.info("(start)生产者消息确认=========================");
log.info("correlationData:[{}]", correlationData);
log.info("ack:[{}]", ack);
log.info("cause:[{}]", cause);
if (!ack) {
log.info("消息可能未到达rabbitmq服务器");
}
log.info("(end)生产者消息确认=========================");
}
}
注意:ここにあなたがRabbitTemplate.ConfirmCallbackインターフェイスを達成するために必要な、メッセージ確認
4、プロデューサー - プロデューサーの設定
@Configuration
public class RabbitmqConfiguration {
@Autowired
private RabbitTemplate rabbitTemplate;
@PostConstruct
public void initRabbitTemplate() {
// 设置生产者消息确认
rabbitTemplate.setConfirmCallback(new RabbitConfirmCallback());
}
/**
* 申明队列
*
* @return
*/
@Bean
public Queue queue() {
Map<String, Object> arguments = new HashMap<>(4);
// 申明死信交换器
arguments.put("x-dead-letter-exchange", "exchange-dlx");
return new Queue("queue-rabbit-springboot-advance", true, false, false, arguments);
}
/**
* 没有路由到的消息将进入此队列
*
* @return
*/
@Bean
public Queue unRouteQueue() {
return new Queue("queue-unroute");
}
/**
* 死信队列
*
* @return
*/
@Bean
public Queue dlxQueue() {
return new Queue("dlx-queue");
}
/**
* 申明交换器
*
* @return
*/
@Bean
public Exchange exchange() {
Map<String, Object> arguments = new HashMap<>(4);
// 当发往exchange-rabbit-springboot-advance的消息,routingKey和bindingKey没有匹配上时,将会由exchange-unroute交换器进行处理
arguments.put("alternate-exchange", "exchange-unroute");
return new DirectExchange("exchange-rabbit-springboot-advance", true, false, arguments);
}
@Bean
public FanoutExchange unRouteExchange() {
// 此处的交换器的名字要和 exchange() 方法中 alternate-exchange 参数的值一致
return new FanoutExchange("exchange-unroute");
}
/**
* 申明死信交换器
*
* @return
*/
@Bean
public FanoutExchange dlxExchange() {
return new FanoutExchange("exchange-dlx");
}
/**
* 申明绑定
*
* @return
*/
@Bean
public Binding binding() {
return BindingBuilder.bind(queue()).to(exchange()).with("product").noargs();
}
@Bean
public Binding unRouteBinding() {
return BindingBuilder.bind(unRouteQueue()).to(unRouteExchange());
}
@Bean
public Binding dlxBinding() {
return BindingBuilder.bind(dlxQueue()).to(dlxExchange());
}
}
注意:X-デッドレター交換と代替交換のパラメータ値と交換器の値は一貫している必要があります
5、プロデューサー - メッセージの送信者を書くために
@Component
@Slf4j
public class RabbitProducer implements ApplicationListener<ContextRefreshedEvent> {
@Autowired
private RabbitTemplate rabbitTemplate;
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
String exchange = "exchange-rabbit-springboot-advance";
String routingKey = "product";
String unRoutingKey = "norProduct";
// 1.发送一条正常的消息 CorrelationData唯一(可以在ConfirmListener中确认消息)
IntStream.rangeClosed(0, 10).forEach(num -> {
String message = LocalDateTime.now().toString() + "发送第" + (num + 1) + "条消息.";
rabbitTemplate.convertAndSend(exchange, routingKey, message, new CorrelationData("routing" + UUID.randomUUID().toString()));
log.info("发送一条消息,exchange:[{}],routingKey:[{}],message:[{}]", exchange, routingKey, message);
});
// 2.发送一条未被路由的消息,此消息将会进入备份交换器(alternate exchange)
String message = LocalDateTime.now().toString() + "发送一条消息.";
rabbitTemplate.convertAndSend(exchange, unRoutingKey, message, new CorrelationData("unRouting-" + UUID.randomUUID().toString()));
log.info("发送一条消息,exchange:[{}],routingKey:[{}],message:[{}]", exchange, unRoutingKey, message);
}
}
注:1、メッセージ2が正しくメッセージキューにルーティングすることができるメッセージを送信され、他方はroutingKeyため存在し、従ってないが、このルートに観察されたメッセージがない、キューにルーティングされることはありません代替交換のキューにバインドされました。
図2に示すように、CorrelationDataは固有のデータを必要とする、この値は、メッセージプロデューサを確認するために使用することができます。
6、プロデューサー - スタートクラス
@SpringBootApplication
public class ProducerApplication {
public static void main(String[] args) {
SpringApplication.run(ProducerApplication.class, args);
}
}
7.消費者 - プロフィール
server:
port: 9087
spring:
rabbitmq:
host: 140.143.237.224
port: 5672
username: root
password: root
virtual-host: /
connection-timeout: 10000
listener:
simple:
acknowledge-mode: manual # 手动应答
auto-startup: true
default-requeue-rejected: false # 不重回队列
concurrency: 5
max-concurrency: 20
prefetch: 1 # 每次只处理一个信息
retry:
enabled: true
図8に示すように、消費者 - メッセージが受信します
@Component
@Slf4j
public class RabbitConsumer {
/**
* 监听 queue-rabbit-springboot-advance 队列
*
* @param receiveMessage 接收到的消息
* @param message
* @param channel
*/
@RabbitListener(queues = "queue-rabbit-springboot-advance")
public void receiveMessage(String receiveMessage, Message message, Channel channel) {
try {
// 手动签收
log.info("接收到消息:[{}]", receiveMessage);
if (new Random().nextInt(10) < 5) {
log.warn("拒绝一条信息:[{}],此消息将会由死信交换器进行路由.", receiveMessage);
channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, false);
} else {
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
}
} catch (Exception e) {
log.info("接收到消息之后的处理发生异常.", e);
try {
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
} catch (IOException e1) {
log.error("签收异常.", e1);
}
}
}
}
注:消費者がいくつかのメッセージがランダムに拒否されます受け取り、この観察は、メッセージキューのxデッドレター交換にバインド交換器に入っていません。
9、結果
完全なコード:
コードは以下の通りである:https://gitee.com/huan1993/rabbitmq/tree/master/rabbitmq-springboot-advanced