1. Cơ sở dữ liệu
Cơ sở dữ liệu RabbitMQ là một hệ thống thông báo mạnh mẽ và linh hoạt. Nó được sử dụng để xử lý các yêu cầu một cách asynchronous, giúp giải耦 các thành phần hệ thống và xử lý các đỉnh load một cách hiệu quả.
1.1. Các chuẩn thông báo
- JMS (Java Message Service): Là một chuẩn API được Sun Microsystems phát triển, cho phép các ứng dụng Java gửi và nhận các thông báo một cách nhất quán. Các sản phẩm phổ biến hỗ trợ JMS bao gồm ActiveMQ và Redis.
- AMQP (Advanced Message Queuing Protocol): Là một chuẩn wire-level protocol nhị phân, AMQP định nghĩa cách các ứng dụng trao đổi dữ liệu qua mạng. Khác với JMS, AMQP không giới hạn qua API, mà chỉ định nghĩa định dạng dữ liệu. Điều này cho phép các client và server được phát triển bằng các ngôn ngữ khác nhau có thể kết nối với nhau. RabbitMQ là một trong những实现 nổi tiếng của AMQP.
2. Tích hợp RabbitMQ vào Spring Boot
Để sử dụng RabbitMQ trong Spring Boot, bạn cần thêm các thư viện sau vào file pom.xml:
<!-- RabbitMQ -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<!-- Các dependency được tự动生成 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
<version>5.2.8.RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit</artifactId>
<version>2.2.10.RELEASE</version>
<scope>compile</scope>
</dependency>
Cấu hình các tham số RabbitMQ trong file application.yml:
spring:
rabbitmq:
host: localhost # Địa chỉ mặc định
port: 5672 # Cổng mặc định
username: guest # Tên người dùng mặc định
password: guest # Mật khẩu mặc định
# Các tham số khác như virtual host có thể được thêm vào nếu cần
2.1. Cấu hình trao đổi và hàng đợi
Bạn có thể tạo và cấu hình các exchange, queue và binding một cách linh hoạt. Dưới đây là một ví dụ:
@Configuration
@EnableRabbit
public class RabbitConfig {
@Bean
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
RabbitTemplate template = new RabbitTemplate(connectionFactory);
// Cấu hình converter để sử dụng JSON thay vì serialization mặc định
template.setMessageConverter(new Jackson2JsonMessageConverter());
return template;
}
@Bean
public DirectExchange directExchange() {
return new DirectExchange("quang.directExchange");
}
@Bean
public Queue queue() {
return new Queue("quang.queue", true);
}
@Bean
public Binding binding() {
return BindingBuilder.bind(queue()).to(directExchange()).with("quangRoutingKey");
}
}
3. Phương thức gửi và nhận
RabbitMQ cung cấp hai phương thức chính để xử lý thông báo:
3.1. Phương thức gửi
@SpringBootTest
@RunWith(SpringRunner.class)
public class RabbitTest {
@Autowired
RabbitTemplate rabbitTemplate;
@Test
public void sendTest() {
// Gửi thông báo dạng text
rabbitTemplate.convertAndSend("quang.directExchange", "quangRoutingKey", "Xin chào RabbitMQ!");
// Gửi thông báo dạng đối tượng
User user = new User("Quang", 12345, "Nam", 30);
rabbitTemplate.convertAndSend("quang.directExchange", "quangRoutingKey", user);
}
}
3.2. Phương thức nhận
@Component
public class RabbitNguoiDung {
@RabbitListener(queues = "quang.queue")
public void nhanThongBao(String thongBao) {
System.out.println("Đã nhận được thông báo: " + thongBao);
}
}
4. So sánh các phương thức serialization
Phương thức serialization có ảnh hưởng lớn đến hiệu suất và khả năng tương thích của hệ thống. Dưới đây là một số phương thức phổ biến:
- Serialization mặc định của JDK: Sử dụng phương thức này yêu cầu các đối tượng phải implement Serializable và có constructor không tham số.
- Byte array: Dễ dàng sử dụng và có hiệu suất cao, but khó khăn trong việc unserialize nếu không có cấu trúc dữ liệu rõ ràng.
- JSON serialization: Là phương thức phổ biến nhất do nó dễ đọc, dễ maintain và có thể được sử dụng bởi nhiều ngôn ngữ khác nhau.
5. Ứng dụng trong thực tế
Trong một hệ thống phức tạp, RabbitMQ có thể được sử dụng để:
- Bảo trì các yêu cầu HTTP một cách asynchronous.
- Xử lý các tác vụ nặng một cách riêng biệt, tách khỏi luồng xử lý chính của ứng dụng.
- Giải耦 các module, cho phép chúng hoạt động độc lập.
5.1. Ví dụ ứng dụng
Xây dựng một hệ thống gửi và nhận thông báo:
// Server-side
@RestController
public class RabbitController {
@Autowired
RabbitTemplate rabbitTemplate;
@PostMapping("/send")
public String guiThongBao(@RequestParam String thongBao) {
rabbitTemplate.convertAndSend("quang.directExchange", "quangRoutingKey", thongBao);
return "Thong bao da duoc gui thanh cong!";
}
}
// Client-side
public class RabbitClient {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(RabbitConfig.class);
RabbitTemplate rabbitTemplate = context.getBean(RabbitTemplate.class);
for (int i = 0; i < 5; i++) {
String thongBao = "Thong bao " + i;
rabbitTemplate.convertAndSend("quang.directExchange", "quangRoutingKey", thongBao);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
context.close();
}
}
Khi chạy ứng dụng, bạn sẽ thấy các thông báo được xử lý và hiển thị trên console.