SpringBoot Rabbit 多IP多 virtual host 配置

实际业务中有在一个 RabbitMQ 中添加多个 virtual host (又叫vhost)的情况,现记录SpringBoot 的配置方式如下,该配置同时满足多机部署配置。
假设我们需要分别配置名为 /primary/second 的 vhost(vhost通常以/开头,实际中可按业务需求取名)。

1. SpringBoot 配置文件

spring:
  rabbitmq:
    # 可满足多机或多virtual host 配置
    primary:
      host: IP
      port: 5672
      username: guest
      password: guest
      virtual-host: /primary
    second:
      host: IP
      port: 5672
      username: guest
      password: guest
      virtual-host: /second
    # ***** 下面为可选配置 *****
    listener:
      simple:
        # 消息确认模式 其有三种配置方式,分别是none、manual和auto,默认auto
        acknowledge-mode: manual
        # 最小的消费者数量
        concurrency: 1
        # 最大的消费者数量
        maxConcurrency: 16
        # 一个消费者最多可处理的nack消息数量,如果有事务的话,必须大于等于transaction数量
        prefetch: 1
        retry:
          # 关闭自动重试
          enabled: false
      template:
        mandatory: true
        retry:
          # 启动发送重试策略
          enabled: true
          # 初始重试间隔为1s
          initial-interval: 1000
          # 重试的最大次数
          max-attempts: 3
          # 重试间隔最多10s
          max-interval: 10000
          # 每次重试的因子1.0 等差
          multiplier: 1.0

2. RabbitTemplate 配置和使用

2.1 RabbitTemplate 配置

读取不同的配置,创建两个ConnectionFactory,并分别创建对应的 RabbitTemplate
为方便使用,下面的配置中,primary 配置通过@Primary 注解标记为 优先使用的 Bean,其 ConnectionFactory 和 RabbitTemplate 在 @Bean 中不单独命名,采用默认名,但需注意命名不要与second 混淆;second ConnectionFactory 和 RabbitTemplate 在@Bean中单独标记为 secondConnectionFactory 和 secondRabbitTemplate,且在装配RabbitTemplate时要通过@Qualifier指定使用secondConnectionFactory。

package com.xxx.amqp.config;

import cn.hutool.core.util.RandomUtil;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.amqp.SimpleRabbitListenerContainerFactoryConfigurer;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import java.util.HashMap;
import java.util.Map;

@Configuration
public class RabbitMqConfiguration {
	/*
	 * ===================================================
	 * primary virtual-host /primary
	 * ===================================================
	 */
	@Bean
	@Primary
	public ConnectionFactory connectionFactory(
			@Value("${spring.rabbitmq.primary.host}") String host,
			@Value("${spring.rabbitmq.primary.port}") int port,
			@Value("${spring.rabbitmq.primary.username}") String username,
			@Value("${spring.rabbitmq.primary.password}") String password,
			@Value("${spring.rabbitmq.primary.virtual-host}") String virtualHost) {
		CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
		connectionFactory.setHost(host);
		connectionFactory.setPort(port);
		connectionFactory.setUsername(username);
		connectionFactory.setPassword(password);
		connectionFactory.setVirtualHost(virtualHost);
		return connectionFactory;
	}

	@Bean
	@Primary
	public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
		return new RabbitTemplate(connectionFactory);
	}

	/*
	 * ===================================================
	 * second virtual-host /second 
	 * ===================================================
	 */

	@Bean("secondConnectionFactory")
	public ConnectionFactory secondConnectionFactory(
			@Value("${spring.rabbitmq.second.host}") String host,
			@Value("${spring.rabbitmq.second.port}") int port,
			@Value("${spring.rabbitmq.second.username}") String username,
			@Value("${spring.rabbitmq.second.password}") String password,
			@Value("${spring.rabbitmq.second.virtual-host}") String virtualHost) {
		CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
		connectionFactory.setHost(host);
		connectionFactory.setPort(port);
		connectionFactory.setUsername(username);
		connectionFactory.setPassword(password);
		connectionFactory.setVirtualHost(virtualHost);
		return connectionFactory;
	}

	@Bean("secondRabbitTemplate")
	public RabbitTemplate otbSyncRabbitTemplate(@Qualifier("secondConnectionFactory") ConnectionFactory connectionFactory) {
		return new RabbitTemplate(connectionFactory);
	}
}

2.2 RabbitTemplate 注入使用

建议优先使用@Resource注解注入。
如果要使用 primaryRabbitTemplate ,可直接注入使用,无需指定name

@Resource
private RabbitTemplate rabbitTemplate;

如果要使用 secondRabbitTemplate,则须特别指定name属性:

@Resource(name = "secondRabbitTemplate")
private RabbitTemplate secondRabbitTemplate;

或者,如果你倾向于使用@Autowired注入,则需要同时使用@Qualifier注解指定name

@Autowired
@Qualifier("secondRabbitTemplate")
private RabbitTemplate secondRabbitTemplate;

3. 消息监听配置

这里采用@RabbitListener注解的方式监听消息消费。
如果要监听/primary,可在@RabbitListener注解中只声明要监听的queues,Spring会自动监听默认vhost/primary中的queue;但是如果要监听/second的消息,在声明queues(例如,使用 second-test-queue)的同时,还要在消费端配置中声明相应的containerFactory
首先,消费端RabbitTemplate配置同上,在此基础上增加下面RabbitListenerContainerFactory配置(该配置为示例,具体场景可按需设置):

@Bean(name = "secondListenerContainer")
public SimpleRabbitListenerContainerFactory secondRabbitListenerContainer(
		SimpleRabbitListenerContainerFactoryConfigurer configurer,
		@Qualifier("secondConnectionFactory") ConnectionFactory connectionFactory) {
	SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
	configurer.configure(factory, connectionFactory);
	return factory;
}

然后在消息监听类方法的@RabbitListener中声明使用该containerFactory

package com.xxx.amqp.consumer;

import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

import java.io.IOException;

@Slf4j
@Component
public class SecondTestRabbitListener {

    @RabbitListener(queues = "second-test-queue", containerFactory = "secondListenerContainer")
    public void updateCoreMainCategoryFlag(Message message, Channel channel) throws IOException {
        String messageBody = IOUtils.toString(message.getBody(), StandardCharsets.UTF_8.toString());
        log.info("消息体内容: {}", messageBody);
        // 消息处理逻辑
        // ...

		// 处理结束后手动 ack
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
    }
}

4. 参考

[1] SpringBoot配置多个RabbitMQ

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值