SpringBoot整合RabbitMQ非常簡單,官網有對應的starter,可以自動裝配。本文使用官網的starter整合rabbitmq。個人覺得官方有starter的組件就使用starter整合,不要再像以前那樣自己寫配置客戶端,也不要二次封裝,因爲見過一些別人封裝的代碼,覺得把rabbitmq很多功能閹割了,也沒有springboot提供的starter好用靈活。
下面開始集成rabbitmq
首先pom.xml中引入starter
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
application.properties配置文件中添加rabbitmq配置信息
spring.rabbitmq.host=192.168.2.198
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest2018
spring.rabbitmq.publisher-confirms=true
spring.rabbitmq.virtual-host=/
#並行消費者數量
spring.rabbitmq.constomers=5
spring.rabbitmq.max-constomers=20
定義一個queue的枚舉類
public enum QueueConstants {
QUEUE_TEST1("queue_test_one", "隊列1"),
QUEUE_TEST2("queue_test_two", "隊列2");
String code;
String desc;
QueueConstants(String code, String desc) {
this.code = code;
this.desc = desc;
}
public String getCode() {
return code;
}
public String getDesc() {
return desc;
}
}
新建一個配置類,用於配置rabbitmq的queue, exchange, binding及customers,自定義messageConverter等等。配置完成後項目啓動可以自動建立對應的queue和exchange。當然也可以通過rabbitmq控制檯創建。注意:通過控制檯創建,queue和exchange的屬性(如:durable, autoDelete等)要和此處相對應,否則啓動會報異常:Caused by: com.rabbitmq.client.ShutdownSignalException: channel error; protocol method: #method<channel.close>(reply-code=406, reply-text=PRECONDITION_FAILED - inequivalent arg 'durable' for exchange 'maxwell' in vhost '/': received 'true' but current is 'false', class-id=40, method-id=10)
import com.xhd.constants.QueueConstants;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RabbitmqConfig {
/**
* 此處使用自動裝配,定義customers和max-customers
* @param connectionFactory
* @return
*/
@Bean
@ConfigurationProperties(prefix = "spring.rabbitmq")
public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(ConnectionFactory connectionFactory) {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
// factory.setMessageConverter(new FastJsonMessageConverter());
return factory;
}
@Bean("queue1")
public Queue queue1() {
return new Queue(QueueConstants.QUEUE_TEST1.getCode());
}
@Bean("queue2")
public Queue queue2() {
return new Queue(QueueConstants.QUEUE_TEST2.getCode());
}
/**
* 定義exchange. 根據需要定義不同的exchange
* @return
*/
@Bean
public TopicExchange exchange() {
return new TopicExchange("exchange_test", true, false);
}
@Bean
Binding bindingExchangeQueue(@Qualifier("queue1") Queue queue, TopicExchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with("topic.message");
}
@Bean
Binding bindingExchangeMessages(@Qualifier("queue2") Queue queueMessages, TopicExchange exchange) {
return BindingBuilder.bind(queueMessages).to(exchange).with("topic.#");
}
}
發送消息
@Autowired
private AmqpTemplate rabbitTemplate;
/**
* 發送字符串消息
*/
@Test
public void sendToMQ() {
String content = "this is test content";
rabbitTemplate.convertAndSend(QueueConstants.QUEUE_TEST1.getCode(), content);
}
/**
* 直接發送對象
*/
@Test
public void sendToMQ2() {
User user = new User();
user.setId(190L);
user.setUsername("xxxxx");
user.setEmail("[email protected]");
rabbitTemplate.convertAndSend(QueueConstants.QUEUE_TEST2.getCode(), user);
}
監聽消息並接收
import com.rabbitmq.client.Channel;
import com.xhd.domain.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class RabbitmqConsumer {
@RabbitHandler
@RabbitListener(queues = "queue_test_one")
public void processQueue1(Message message, Channel channel) {
// //處理成功,消息已消費
// channel.basicAck(message.getMessageProperties().getDeliveryTag(), true);
// //處理失敗,重新放入隊列並重試
// channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
// //處理失敗,丟在一邊不重試
// channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, false);
log.info("data:" + message);
}
@RabbitHandler
@RabbitListener(queues = "queue_test_one")
public void processQueue13(String data) {
try {
log.info("data:" + data);
//業務處理 ...
} catch (Exception e) {
log.error("peocess error", e);
throw new RuntimeException("process error", e); //拋出異常, 消息重新入列並重試
}
}
@RabbitHandler
@RabbitListener(queues = "queue_test_two")
public void processQueue2(User user) {
log.info("user:" + user);
}
}
參考資料:https://docs.spring.io/spring-amqp/docs/2.0.2.RELEASE/reference/html/