springboot整合rabbitmq實戰

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/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章