Development and application of rabbitmq in springboot project

Introduction to AMQP

AMQP (Advanced Message Queuing Protocol) is a network protocol that delivers asynchronous messages between processes.

Exchange has Direct, Fanout, Topic, Headers, and the three most common types are Direct, Fanout, Topic.

Production/Consumption Message Model
The producer sends a message to the broker server (RabbitMQ).Inside the Broker, the user creates Exchange/Queue,
Link the two through Binding rules.Exchange distributes messages according to different distribution policies of type/binding.
The message ends up in Queue, waiting for the consumer to take it away.

Basic concepts in AMQP messaging
Broker: The application that receives and distributes messages, RabbitMQ Server is Message Broker.
Virtual host: Designed for multi-tenant and security reasons, the basic components of AMQP are grouped into a virtual group, similar to the namespace concept in the network.When multiple different users use services provided by the same RabbitMQ server, they can be divided into multiple vhosts, and each user creates exchange/queue in his own vhosts.
Connection: TCP connection between publisher/consumer and broker.Disconnecting occurs only on the client side and Broker does not disconnect unless there is a network failure or a problem with the broker service.
Channel: If a Connection is established for every RabbitMQ access, the cost and efficiency of establishing a TCP Connection will be enormous when there are a lot of messages.Channel is a logical connection established within a connection. If the application supports multiple threads, a separate channel is usually created for each thread to communicate. AMQP method contains channel IDs to help clients and message broker s identify the channel, so the channel is completely isolated from each other.Channel as a lightweight connection greatly reduces the operating system's overhead of establishing TCP connections.
Exchange: The message arrives at the broker's first station, matches the routing key in the query table according to the distribution rules, and distributes the message to the queue.Common types are direct (point-to-point), topic (publish-subscribe), and fanout (multicast).
queue: The message was finally sent here waiting for consumer to take it away.A message can be copied to multiple queues at the same time.
Binding: A virtual connection between exchange and queue, in which routing key s can be included.Binding information is saved to the query table in exchange to distribute message s based on.

A, SpringAMQP declaration
The SpringAMQP declaration declares an exchange, Bingding, queue within the rabbit base API.To declare using SpringAMQP, you need to declare using @bean.

B,RabbitAdmin
(1) The RabbitAdmin class works well with RabbitMQ and can be injected directly into Spring.
(2)autoStartup must be set to true, otherwise the Spring container will not load the RabbitAdmin class
(3)RabbitAdmin's underlying implementation is to get Exchagge,Bingding,RoutingKey, and Queue's @Bean declarations from the Spring container
(4) Then use RabbitTemplate's execute method to perform the corresponding declaration, modification, deletion and other operations

C,RabbitTemplate
Spring AMQP provides RabbitTemplate to simplify sending and receiving messages to RabbitMQ

D,SimpleMessageListenerContailer
(1) Simple Message Listening Container: This class is very powerful, and we can set up a lot of settings for it. For consumer configurations, this class can be satisfied
(2) Set transaction characteristics, transaction manager, transaction properties, transaction capacity, transaction opening, etc.
(3) Set up message acknowledgment and automatic acknowledgment modes, return to queue, exception capture handler function
(4) Set up consumer label generation strategies, whether exclusive mode, consumer attributes, etc.
(5) SimeMessageListenerContailer can be set dynamically, such as in-service applications can dynamically change the size of their number of consumers, the mode of receiving messages, etc.

E,MessageListenerAdapter
1) A class that does not implement the MessageListener and ChannelAwareMessageListener interfaces can be adapted to a processor that can process messages
2) The default method name is handleMessage, and a new message processing method can be set through setDefaultListenerMethod
3)MessageListenerAdapter supports different queues to be executed in different ways.Using the setQueueOrTagToMethodName method setting, when no matching method is found based on the queue name, it is handled by the default method.

F,MessageConverter
(1) Message Converter
(2) When sending messages, the message body is normally transmitted as binary data. If you want to help us convert internally or specify a custom converter, you need a MessageConverter
(3) Implement the MessageConverter interface, override toMessage(java object converted to Message) fromMessage(Message object converted to Java object)
(4)json converter, custom binary converter (such as picture type, pdf,ppt, streaming media)

 

1. Install and start amqp by: https://my.oschina.net/lion1220/blog/3151027

Sign in to amqp with the following interface

2. Create a project and import the amqp jar package

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

3. Add Configuration Items in Properrties File

spring.rabbitmq.host=127.0.0.1
spring.rabbitmq.port=5672
spring.rabbitmq.username=admin
spring.rabbitmq.password=admin
spring.rabbitmq.cache.channel.size=100
#spring.rabbitmq.publisher-confirms=true
spring.rabbitmq.virtual-host=/

#Producer
mq.producer.x.exchangeName=test_x_exchange
mq.producer.x.exchangeType=direct
mq.producer.x.queueName=test_producer_x_queue
mq.producer.x.routeKey=test_producer_x_queue
mq.producer.x.durable=true
#Consumer
mq.consumer.x.exchangeName=test_x_exchange
mq.consumer.x.exchangeType=direct
mq.consumer.x.queueName=test_consumer_x_queue
mq.consumer.x.routeKey=test_consumer_x_queue
mq.consumer.x.durable=true
#Used to send notifications
mq.notify.x.exchangeName=test_x_exchange
mq.notify.x.exchangeType=fanout
mq.notify.x.queueName=test_notify_x_queue
mq.notify.x.routeKey=test_notify_x_queue
mq.notify.x.durable=true

4. amqp Configuration Class

@Configuration
public class AmqpConfig {

    private static final Logger LOG = LoggerFactory.getLogger(AmqpConfig.class);

    @Autowired
    private Globals globals;

    public final static String RP_FACTORY_NAME = "rpMQContainerFactory";
    public final static String BANK_FACTORY_BEAN_NAME = "bankMQContainerFactory";

      @Value("${spring.rabbitmq.host:127.0.0.1}")
    private String notifyMqHost;
    @Value("${spring.rabbitmq.port:5672}")
    private Integer notifyMqPort;
    @Value("${spring.rabbitmq.username:admin}")
    private String notifyMqUsername;
    @Value("${spring.rabbitmq.password:admin}")
    private String notifyMqPassword;
    @Value("${spring.rabbitmq.channelCacheSize:1024}")
    private Integer notifyMqChannelCacheSize;
    @Value("${spring.rabbitmq.publisherConfirms:true}")
    private String notifyMqPublisherConfirms;

    /** ********* ConnectionFactory ****************  */

    @Bean(name = "factoryProvider")
    @Primary
    public CachingConnectionFactory factoryProvider(){
        CachingConnectionFactory factoryProvider = new CachingConnectionFactory();
        factoryProvider.setHost(notifyMqHost);
        factoryProvider.setPort(notifyMqPort);
        factoryProvider.setUsername(notifyMqUsername);
        factoryProvider.setPassword(notifyMqPassword);
        factoryProvider.setVirtualHost("/");
        return factoryProvider;
    }

    @Bean(name = "factoryConsumerCgt")
    public CachingConnectionFactory factoryConsumerCgt(){
        CachingConnectionFactory factoryConsumer = new CachingConnectionFactory();
        factoryConsumer.setHost(notifyMqHost);
        factoryConsumer.setPort(notifyMqPort);
        factoryConsumer.setUsername(notifyMqUsername);
        factoryConsumer.setPassword(notifyMqPassword);
        factoryConsumer.setVirtualHost("/bank");
        return factoryConsumer;
    }

    /** ********************************************  */

    @Bean
    public Jackson2JsonMessageConverter jackson2JsonMessageConverter() {
        return new Jackson2JsonMessageConverter();
    }

   /** *********************************************  */

    /**
     * rabbitTemplate
     *
     * @param rabbitAdmin
     * @return
     */
    @Bean
    public AmqpTemplate rabbitTemplate(RabbitAdmin rabbitAdmin) {
        RabbitTemplate rabbitTemplate = rabbitAdmin.getRabbitTemplate();
        rabbitTemplate.setMessageConverter(jackson2JsonMessageConverter());
        return rabbitTemplate;
    }

    @Bean
    public RabbitAdmin rabbitAdmin(CachingConnectionFactory factoryProvider) {
        return new RabbitAdmin(factoryProvider);
    }

    /** *********** Consumer Factory**************  */

    /*Consumer Factory  */
    @Bean(RP_FACTORY_NAME)
    public SimpleRabbitListenerContainerFactory rpRabbitListenerContainerFactory(
            SimpleRabbitListenerContainerFactoryConfigurer configurer,
            @Qualifier("factoryProvider")ConnectionFactory factoryProvider) {
        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        factory.setConnectionFactory(factoryProvider);
        factory.setMessageConverter(jackson2JsonMessageConverter());

        //Get quantity from queue one time
        factory.setPrefetchCount(globals.getDefaultPrefetchNumber());
        //#Default number of consumer threads
        factory.setConcurrentConsumers(globals.getMinConsumerNumber());
        //Maximum number of consumer threads
        factory.setMaxConcurrentConsumers(globals.getMaxConsumerNumber());
        //Message Format Conversion
        factory.setMessageConverter(jackson2JsonMessageConverter());
        configurer.configure(factory, factoryProvider);
        return factory;
    }

    @Bean(BANK_FACTORY_BEAN_NAME)
    public SimpleRabbitListenerContainerFactory bankRabbitListenerContainerFactory(
            @Qualifier("factoryConsumerCgt")ConnectionFactory factoryConsumerCgt) {
        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        factory.setConnectionFactory(factoryConsumerCgt);
        factory.setMessageConverter(jackson2JsonMessageConverter());
        return factory;
    }

    /** ********** Queue ***********  */

    @ConfigurationProperties(prefix = "mq.producer.bank")
    @Bean
    public QueueSetting bankProducerQueueSett() {
        return new QueueSetting();
    }

    @ConfigurationProperties(prefix = "mq.consumer.bank")
    @Bean
    public QueueSetting bankConsumerQueueSett() {
        return new QueueSetting();
    }

    @ConfigurationProperties(prefix = "mq.notify.bank")
    @Bean
    public QueueSetting bankNotifyQueueSett() {
        return new QueueSetting();
    }

   /** ************* Exchange ********************  */

    /**
     * Send out
     * @param rabbitAdmin
     * @return
     */
    @Bean
    public Exchange bankProducerExchange(RabbitAdmin rabbitAdmin, @Qualifier("bankProducerQueueSett") QueueSetting bankProducerQueueSett){
        Exchange exchange = new DirectExchange(bankProducerQueueSett().getExchangeName());
        rabbitAdmin.declareExchange(exchange);
        return exchange;
    }

    /**
     * Send out
     * @param rabbitAdmin
     * @return
     */
    @Bean
    public Exchange bankConsumerExchange(RabbitAdmin rabbitAdmin, @Qualifier("bankConsumerQueueSett") QueueSetting bankConsumerQueueSett){
        Exchange exchange = new DirectExchange(bankConsumerQueueSett().getExchangeName());
        rabbitAdmin.declareExchange(exchange);
        return exchange;
    }

    /**
     * Broadcast results
     * @param rabbitAdmin
     * @return
     */
    @Bean
    public Exchange bankNotifyExchange(RabbitAdmin rabbitAdmin, @Qualifier("bankNotifyQueueSett") QueueSetting bankNotifyQueueSett){
        Exchange exchange = new FanoutExchange(bankNotifyQueueSett().getExchangeName());
        rabbitAdmin.declareExchange(exchange);
        return exchange;
    }

    /** *******************************************  */

    public String getNotifyMqHost() {
        return notifyMqHost;
    }

    public void setNotifyMqHost(String notifyMqHost) {
        this.notifyMqHost = notifyMqHost;
    }

    public Integer getNotifyMqPort() {
        return notifyMqPort;
    }

    public void setNotifyMqPort(Integer notifyMqPort) {
        this.notifyMqPort = notifyMqPort;
    }

    public String getNotifyMqUsername() {
        return notifyMqUsername;
    }

    public void setNotifyMqUsername(String notifyMqUsername) {
        this.notifyMqUsername = notifyMqUsername;
    }

    public String getNotifyMqPassword() {
        return notifyMqPassword;
    }

    public void setNotifyMqPassword(String notifyMqPassword) {
        this.notifyMqPassword = notifyMqPassword;
    }

    public Integer getNotifyMqChannelCacheSize() {
        return notifyMqChannelCacheSize;
    }

    public void setNotifyMqChannelCacheSize(Integer notifyMqChannelCacheSize) {
        this.notifyMqChannelCacheSize = notifyMqChannelCacheSize;
    }

    public String getNotifyMqPublisherConfirms() {
        return notifyMqPublisherConfirms;
    }

    public void setNotifyMqPublisherConfirms(String notifyMqPublisherConfirms) {
        this.notifyMqPublisherConfirms = notifyMqPublisherConfirms;
    }
}

5. Broadcast Return Results

@Slf4j
@Component
public class MQProvider {

    @Autowired
    private AmqpTemplate rabbitTemplate;
    @Autowired
    private QueueSetting bankNotifyQueueSett;

    public void send(String msg) {
        log.info("MQ Broadcast message:", msg);
        rabbitTemplate.convertAndSend(bankNotifyQueueSett.getExchangeName(), bankNotifyQueueSett.getRouteKey(), msg);
    }
}

6. Consuming MQ Data

@Slf4j
@Component
public class MQConsumer {

     /**
     * Consumer data sent to MQ
     *
     * @param messageSource
     * @param channel
     * @param tag
     * @throws IOException
     * @throws InterruptedException
     */
     @RabbitListener(containerFactory = AmqpConfig.BANK_FACTORY_BEAN_NAME,
             bindings = @QueueBinding(value = @Queue(value = "${mq.consumer.bank.queueName}", durable = "true",
             exclusive = "false", autoDelete = "false"),
                     exchange = @Exchange(value = "${mq.consumer.bank.exchangeName}", durable = "${mq.consumer.bank.durable}",
                     type = ExchangeTypes.DIRECT), key = "${mq.consumer.bank.routeKey}"), admin = "rabbitAdmin")
     public void process(byte[] messageSource, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long tag){
        try {
            String message = new String(messageSource, "UTF-8");
            log.info("Receive[${mq.queueNamePre}]Message:{}" ,message);
            if (StringUtils.isEmpty(message)) {
                log.error("Receive message Is empty");
            }

            //TODO Processing Business Data

        } catch (UnsupportedEncodingException e) {
            log.error("Receive message UnsupportedEncodingException",e);
        } finally {
            try {
                channel.basicAck(tag, false);
            } catch (IOException e) {
                log.error("channel.basicAck Exception",e);
            }
        }
    }
}

7. Test Send Message

8. View Sending Data

Source example: https://gitee.com/lion123/springboot-rabbitmq-demo

Tags: Programming RabbitMQ Spring network Java

Posted on Fri, 20 Mar 2020 15:34:39 -0400 by RP