消息隊列補充
補充:消息隊列概念和使用場景
大多數應用中,可以通過消息服務中間件來提升系統異步通信、擴展解耦能力。
而消息服務中兩個重要的概念:
- 消息代理
- 目的地
當消息發送者發送消息以後,將由消息代理接管,消息代理保證消息傳遞到指定目的地。
消息隊列主要有兩種形式的目的地:
- 隊列(queue):點對點消息通信。
一個消息只有唯一的發送者和接收者。 - 主題(topic):發佈(publish)/訂閱(subscribe)消息通信。
一個消息可以有多個接收者。
兩種消息代理規範
- JMS: Java Message Service,即 Java 消息服務,是基於 JVM 消息代理的規範。實現:ActiveMQ 。
- AMQP: Advanced Message Queuing Protocol,即高級消息隊列協議,也是一個消息代理的規範,兼容 JMS。實現:RabbitMQ。
Spring中對消息隊列的支持
- spring-jms提供了對JMS的支持
- spring-rabbit提供了對AMQP的支持
- 需要ConnectionFactory的實現來連接消息代理
- 提供JmsTemplate、RabbitTemplate來發送消息
- @JmsListener(JMS)、@RabbitListener(AMQP)註解在方法上監聽消息代理髮布的消息
- @EnableJms、@EnableRabbit開啓支持
相關的兩個自動配置
- JmsAutoConfiguration
- RabbitAutoConfiguration
RabbitMQ 補充
RabbitMQ的各個組件:
AMQP相比JMS增加了 Exchange 和 Binding,生產者把消息發給 Broker,Broker 會將消息給到合適的 Exchange,而 Binding 決定交換器的消息應該發送到的隊列,消息最終到達隊列並被消費者接收。
整合 RabbitMQ
本地 RabbitMQ 的安裝可以參考上面的補充,這裏主要講 SpringBoot 中對 RabbitMQ 的配置和使用。
RabbitMQ 後臺中添加我們的交換器以及消息隊列,並進行關聯綁定:
- 交換器
- 消息隊列
- 綁定並指定路由鍵
配置好 RabbitMQ 後,我們就可以在 SpringBoot 中操作我們定義的消息隊列,在補充中我們操作 RabbitMQ 之前需要通過連接工廠獲取連接,這些都在 RabbitAutoConfiguration 幫我們配置好了。
所以我們可以勾選需要的模塊快速創建 SpringBoot 應用,並在配置文件中進行必要配置:
spring:
rabbitmq:
host: localhost
username: guest
password: guest
port: 5672
在 RabbitAutoConfiguration 中還給我們提供了 RabbitTemplate(收發消息) 以及 AmqpAdmin(系統管理組件)。
通過 RabbitTemplate 進行操作:
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
void contextLoads() {
//Message消息對象,要發送的消息
Map<String,Object> map = new HashMap<String,Object>();
map.put("msg","測試消息");
map.put("data", Arrays.asList("1",2,3));
//發送指明交換器,路由鍵,消息體
rabbitTemplate.convertAndSend("myexchange.direct","user",map);
}
@Test
void receiveMsg(){
Object ob = rabbitTemplate.receiveAndConvert("userqueue");
System.out.println(ob.getClass());
System.out.println(ob);
}
同樣的我們可以通過編寫配置文件修改一些配置,比如 RabbitTemplate 默認的序列化機制:
@Configuration
public class AMQPConfig {
@Bean
public MessageConverter myMessageConverter(){
return new Jackson2JsonMessageConverter();
}
}
RabbitListener
一般我們不會通過上面的方法來直接獲取隊列中的消息,而是會使用監聽器來監聽隊列中是否有消息並進行必要的處理。
注:需要開啓基於註解的 RabbitMQ 模式,main 上加 @EnableRabbit
@Service
public class BookService {
@RabbitListener(queues = "userqueue")
public void receive(User user){
System.out.println(user);
}
}
AmqpAdmin
前面我是通過 RabbitMQ 後臺頁面進行交換器以及隊列的創建,其實我們還可以通過 AmqpAdmin 進行定義。
@Autowired
private AmqpAdmin amqpAdmin;
@Test
void createExchange(){
amqpAdmin.declareExchange(new FanoutExchange("myexchange.fanout"));//定義交換器
amqpAdmin.declareQueue(new Queue("xfdgqueue",true));//定義消息隊列
amqpAdmin.declareBinding(new Binding("xfdgqueue",Binding.DestinationType.QUEUE,"myexchange.fanout","",null));//綁定
}