RabbitMQ and SpringBoot integration

To integrate RabbitMQ with SpringBoot, first we need to create a new SpringBoot project, which is divided into two sub modules: producer and consumer. Then we need to introduce related RabbitMQ dependencies, as follows:

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

Let's look at the project first application.yml Configuration information. The configuration information in producer and consumer is almost the same, only the application name is different, as follows:

spring:
  application:
    name: springboot-rabbitmq-producer
  rabbitmq:
    host: 127.0.0.1
    port: 5672
    username: guest
    password: guest
    virtual-host: /
    publisher-confirms: false
spring:
  application:
    name: springboot-rabbitmq-customer
  rabbitmq:
    host: 127.0.0.1
    port: 5672
    username: guest
    password: guest
    virtual-host: /
    publisher-confirms: false



Then let's look at the producer code module producer of the message and see the RabbitConfig configuration class of the producer, as follows:

@Configuration
public class RabbitConfig {

    @Value("${spring.rabbitmq.host}")
    private String addresses;

    @Value("${spring.rabbitmq.port}")
    private String port;

    @Value("${spring.rabbitmq.username}")
    private String username;

    @Value("${spring.rabbitmq.password}")
    private String password;

    @Value("${spring.rabbitmq.virtual-host}")
    private String virtualHost;

    @Value("${spring.rabbitmq.publisher-confirms}")
    private boolean publisherConfirms;

    @Bean
    public ConnectionFactory connectionFactory() {
        CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
        connectionFactory.setAddresses(addresses + ":" + port);
        connectionFactory.setUsername(username);
        connectionFactory.setPassword(password);
        connectionFactory.setVirtualHost(virtualHost);
        //Sender confirmation mode
        connectionFactory.setPublisherConfirms(publisherConfirms);
        return connectionFactory;
    }

    @Bean
    public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory) {
        return new RabbitAdmin(connectionFactory);
    }

    @Bean
    public Queue directQueue() {
        return new Queue("directQueue", false, false, false, null);
    }

    @Bean
    public DirectExchange directExchange() {
        return new DirectExchange("direct-exchange", false, false, null);
    }

    @Bean
    public Binding bindingEmailExchangeMessage() {
        return BindingBuilder
                .bind(directQueue())
                .to(directExchange())
                .with("error");
    }
    
    @Bean
    public RabbitTemplate newRabbitTemplate() {
        RabbitTemplate template = new RabbitTemplate(connectionFactory());
        return template;
    }
}

In fact, the above RabbitMQ and Spring integration (I) All the time, just change the configuration in the original unloading xml to the above-mentioned form. The above configuration includes RabbitMQ's connection factory, admin, etc. it also defines queues, switches, and is bound by routing keys. In addition, RabbitTemplate is also provided to send messages.


We can send messages through RabbitTemplate as follows:

@Component
public class DirectMsgSender {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    public void sendDirectMsg() {
        String[] logLevels = {"error", "warn", "info"};
        for (String logLevel : logLevels) {
            String msg = "Hello " + logLevel;
            rabbitTemplate.convertAndSend("direct-exchange", logLevel, msg);
            //rabbitTemplate.send("direct-exchange", logLevel, new Message(msg.getBytes(), new MessageProperties()));
        }
    }
}

Then we can test the implementation of sending Direct mode through the test class. The test is as follows:

@SpringBootTest(classes = ProducerApplication.class)
@RunWith(SpringRunner.class)
public class ProducerTest {

    @Autowired
    private DirectMsgSender directMsgSender;

    @Test
    public void testDirectMsgSenderr(){
        directMsgSender.sendDirectMsg();
    }
}


After the message producer completes, let's continue to look at the message consumer. First, let's look at its RabbitConfig configuration class. Its content is similar to that of the producer. But here we don't need to define rabbittemplate without message. As follows

@Configuration
public class RabbitConfig {

    @Value("${spring.rabbitmq.host}")
    private String addresses;

    @Value("${spring.rabbitmq.port}")
    private String port;

    @Value("${spring.rabbitmq.username}")
    private String username;

    @Value("${spring.rabbitmq.password}")
    private String password;

    @Value("${spring.rabbitmq.virtual-host}")
    private String virtualHost;

    @Value("${spring.rabbitmq.publisher-confirms}")
    private boolean publisherConfirms;

    @Bean
    public ConnectionFactory connectionFactory() {
        CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
        connectionFactory.setAddresses(addresses + ":" + port);
        connectionFactory.setUsername(username);
        connectionFactory.setPassword(password);
        connectionFactory.setVirtualHost(virtualHost);
        //Sender confirmation mode
        connectionFactory.setPublisherConfirms(publisherConfirms);
        return connectionFactory;
    }

    @Bean
    public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory) {
        return new RabbitAdmin(connectionFactory);
    }

    @Bean
    public Queue directQueue() {
        return new Queue("directQueue", false, false, false, null);
    }

    @Bean
    public DirectExchange directExchange() {
        return new DirectExchange("direct-exchange", false, false, null);
    }

    @Bean
    public Binding bindingDirectExchangeMessage() {
        return BindingBuilder
                .bind(directQueue())
                .to(directExchange())
                .with("error");
    }
}

So how do we receive the news? You can use @ RabbitListener(queues="xxx") and @ RabbitHandler annotations to complete this task, as follows:

@Component
//@RabbitListener(queues = "directQueue1,directQueue2,directQueue3")
@RabbitListener(queues = "directQueue")
public class DirectMsgAccept {

    @RabbitHandler
    public void onMessage(String message) {
        System.out.println(message);
    }
}

Then start the project, and the test results are as follows:



We take sending Direct mode messages as an example. In fact, Fanout, Topic and other modes are similar. We only need to modify the switch type.


For example, the Fanout mode is as follows:


For example, the Topic mode is as follows:



Then let's see how to use sender confirmation, failure confirmation, and manual confirmation mode under spring boot, as follows:


Sender confirmation

First, let's look at the sender confirmation mode. First, we need to application.yml In the configuration file, set the sender confirmation to true


Then let's take a look at the configuration of the message producer side. We need to add a callback to the RabbitTemplate to accept the sender's confirmation. Here we directly uninstall the configuration class (which can also be defined outside, and then introduced in). The content is as follows:



Failure confirmation

Adding failure confirmation mode to SpringBoot is also relatively simple. Similar to the above, first, in RabbitTemplate, enable failure confirmation, and then add related processing, as follows:



Message manual reply

Before message consumers used @ RabbitListener(queues="xxx") and @ RabbitHandler annotation to consume messages. If we want to enable the manual response mode, we need to configure it. First, we need to add related listening and processing classes to the configuration class RabbitConfig on the consumer side, as follows:


Among them, we can set the listening queue, then turn on the manual response mode, and then set related processing classes. This processing is introduced externally, as follows:

/*
@Component
//@RabbitListener(queues = "directQueue1,directQueue2,directQueue3")
@RabbitListener(queues = "directQueue")
public class DirectMsgAccept {

    @RabbitHandler
    public void onMessage(String message) {
        System.out.println(message);
    }
}
*/

@Component
public class DirectMsgAccept implements ChannelAwareMessageListener {
    @Override
    public void onMessage(Message message, Channel channel) throws Exception {
        try {
            String msg = new String(message.getBody(), Charset.defaultCharset());
            System.out.println(msg);

            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (Exception e) {
            channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, false);
        }
    }
}


Message persistence

At last RabbitMQ and Spring integration (2) First of all, in the RabbitConfig definition, there are relevant parameters to persist its switches and queues

Then you need to persist when sending messages, as follows:

Tags: RabbitMQ Spring SpringBoot xml

Posted on Fri, 26 Jun 2020 00:47:20 -0400 by Roman Totale