نمط RabbitMQ Topic Pattern، با استخدام نوع TopicExchange، يختلف عن نمط التوجيه (Direct) في أن معلمات التوجيه تدعم التطابق الضبابي. ونظرًا لأن تطابق التوجيه أكثر مرونة، فإنه نمط أكثر استخدامًا. يُظهر الهندسة المعمارية كما في الشكل التالي:
تلميح: بغض النظر عن نمط عمل RabbitMQ المستخدم، تكمن الفارقة في نوع التبادل المستخدم ومعلمات التوجيه.
1. البرنامج التعليمي الأساسي
يرجى قراءة الأقسام التالية أولاً لفهم المعرفة ذات الصلة:
- مفاهيم RabbitMQ الأساسية
- مبادئ نمط عمل RabbitMQ Topic
- البدء السريع لـ Java مع RabbitMQ (يجب القراءة، حيث لن تعيد الأقسام التالية الكود، فقط تظهر الكود الرئيسي)
- قسم نمط نشر واشتراك لـ Java RabbitMQ (يجب القراءة، حيث يكاد بناء الجملة للكود يكون متطابقاً، يختلف فقط نوع التبادل ومعلمات التوجيه)
2. تعريف تبادل الموضوع
في Spring AMQP، تكون الفئة المقابلة لتبادل Direct هي TopicExchange. نحدد التبادل من خلال فئة تكوين Spring Boot.
package com.tizi365.rabbitmq.config;
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class QueueConfig {
@Bean
public TopicExchange topic() {
// قم بتعريف التبادل
// المعلمة هي اسم التبادل، الذي يجب أن يكون فريدًا
return new TopicExchange("tizi365.topic");
}
}
تلميح: كل من منتجات الرسائل والمستهلكين بحاجة إلى التبادل.
3. إرسال الرسائل
نرسل الرسائل إلى التبادل، ويقوم التبادل بتوصيل الرسائل إلى الصفوف المقابلة استنادًا إلى قواعد التوجيه.
package com.tizi365.rabbitmq.service;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
@Service
public class SendService {
@Autowired
private RabbitTemplate template;
@Autowired
private TopicExchange topic;
// لأغراض العرض، يتم استخدام مهمة مجدولة هنا لإرسال رسالة كل ثانية
@Scheduled(fixedDelay = 1000, initialDelay = 1000)
public void send() {
// محتوى الرسالة
String message = "مرحباً بالعالم!";
// إرسال الرسالة
// المعلمة الأولى هي اسم التبادل
// المعلمة الثانية هي مفتاح التوجيه. يقوم تبادل الموضوع بتسليم الرسائل إلى صفوف تطابق مفتاح التوجيه
// المعلمة الثالثة هي محتوى الرسالة، يدعم أي نوع طالما يمكن تسلسله
template.convertAndSend(topic.getName(), "www.tizi365.com", message);
System.out.println("تم إرسال الرسالة: '" + message + "'");
}
}
تلميح: انتبه إلى المعلمة الثانية "www.tizi365.com" في طريقة convertAndSend، حيث أنها معلمة حاسمة.
4. استقبال الرسائل
4.1 تعريف الصفوف وربط التبادلات
لاستهلاك الرسائل من الصفوف، يجب عليك أولاً تعريف صف ومن ثم ربط الصف بالتبادل المستهدف. فيما يلي، تم تعريف صفين وربطهما بنفس التبادل.
package com.tizi365.rabbitmq.config;
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class QueueConfig {
@Bean
public TopicExchange topic() {
// تعريف التبادل
// المعلمة هي اسم التبادل، والذي يجب أن يكون فريداً
return new TopicExchange("tizi365.topic");
}
@Bean
public Queue queue1() {
// تعريف الصف 1
return new Queue("tizi365.topic.queue1");
}
@Bean
public Queue queue2() {
// تعريف الصف 2
return new Queue("tizi365.topic.queue2");
}
@Bean
public Binding binding1(TopicExchange topic, Queue queue1) {
// تعريف علاقة الربط، ربط الصف 1 بتبادل الموضوع بمفتاح توجيهي: *.tizi365.com
return BindingBuilder.bind(queue1).to(topic).with("*.tizi365.com");
}
@Bean
public Binding binding2(TopicExchange topic, Queue queue2) {
// تعريف علاقة الربط، ربط الصف 2 بتبادل مباشر بمفتاح توجيهي: *.baidu.com
return BindingBuilder.bind(queue2).to(topic).with("*.baidu.com");
}
}
نصيحة: عند ربط الصف 1 والصف 2 بالتبادل، فإن المفاتيح التوجيهية المُعَيَّنة تستخدم كلاهما الرمز * (نجمة) المُتَجَدد، الذي يُطابق كلمة واحدة. إذا تم تغييره إلى # (هاش)، فسيُطابق عدة كلمات.
4.2 تعريف مستمعي الصفوف
تعريف مستمعي الرسائل باستخدام تعليق RabbitListener لاستهلاك الرسائل من الصفوف المحددة.
package com.tizi365.rabbitmq.listener;
import org.springframework.amqp.rabbit.annotation.*;
import org.springframework.stereotype.Component;
// دع Spring تدير الفصل الحالي
@Component
public class DemoListener {
// تعريف مستمع، مُحَدِّدًا أي صف يجب الاستماع إليه من خلال معلمة الصفوف
@RabbitListener(queues = "tizi365.topic.queue1")
public void receive1(String msg) {
System.out.println("تم استقبال الرسالة من الصف 1: " + msg);
}
// تعريف مستمع، مُحَدّدًا أي صف يجب الاستماع إليه من خلال معلمة الصفوف
@RabbitListener(queues = "tizi365.topic.queue2")
public void receive2(String msg) {
System.out.println("تم استقبال الرسالة من الصف 2: " + msg);
}
}
نظرًا لأن الصف 1 فقط يحتوي على مفتاح توجيهي *.tizi365.com عند الربط بالتبادل، فسيُطابق الرسائل ذات المفتاح التوجيهي (www.tizi365.com). لذا، ستتمكن الصف 1 فقط من استقبال الرسائل، بينما لن يتمكن الصف 2 من استقبال أي رسائل بسبب عدم تطابق المفتاح التوجيهي.