rabbit Mq 实现定向消费,设置Ip白名单

本文介绍了在生产环境中使用RabbitMQ时如何实现定向消费,并防止本地调试时误消费生产消息。提出了三种解决方案:1) 集成Spring时设置IP白名单;2) 生产消息时附带IP并在消费端判断;3) 在RabbitMQ管理后台配置固定IP白名单。作者倾向于方案三,但实际操作中可能存在限制。文中提供了方案一的代码实现,并提到方案一虽有报错,但不影响其他业务逻辑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

rabbit Mq 实现定向消费,设置Ip白名单:

初衷:为了在生产环境调试生产的问题。但是本地启动生产环境,就会产生一些不必要的问题。本地启动生产环境。就会有可能消费生产环境的消息。为了解决这一问题。我提出三种实现方案:

方案一:Mq和spring集成的时候,做Ip白名单限制。在启动项目的时候就会检测本地的Ip是否属于配置的白名单Ip段(缺点:就是只能围绕)
方案二:在mq send 的时候带上特定的Ip. 然后在消费端进行判断,如果消费端不属于Ip白名单,那么直接再次放进mq,或者说抛异常。(缺点:直接放回mq,做法不好,每次放入顶端,抛异常感觉不错,但是得把Mq配置成支持事务的方式))
方案三:需要在rabbit mq 后台管理系统上面配置用户,且需要rabbit.confg 里面配置固定的白名单Ip   

这三种方案:我更倾向于方案三。但是现实往往是不允许你去这样做。

方案一:代码启动之后会在mq manager管理系统里展现出来。但是会因为没有设置消费者就会报错。但是不会影响其他的业务逻辑。不妨碍你的测试。如果你想测试关于Mq的消费,那么你就只能把自己的Ip设置在白名单之内。

package com.rabbitmq;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @author Kevin
 * @version DCG 1.0
 * @date 2020/12/24 14:25
 */
@Configuration
@PropertySource("classpath:rabbitmq.properties")
@ComponentScan
@Slf4j
@Data
public class RabbitMqConfig{
    @Value("${consumers.Ip}")
    private String consumersIp;
    @Value("${mq.exchange}")
    private String exchange;
    @Value("${mq.queueName}")
    private String queueName;
    @Value("${routkey.consumer}")
    private String routkeyConsumer;
    @Value("${routkey.producer}")
    private String routkeyProducer;
    @Value("${current.env}")
    private String env;
    @Value("${mq.Listener.prefetch}")
    private String prefetch;
    @Value("${mq.Listener.concurrency}")
    private String concurrency;
    @Autowired
    RabbitmqResultConsumer rabbitmqResultConsumer;  //具体实现的消费者

    public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory){
        RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
        rabbitAdmin.setAutoStartup(true);
        return rabbitAdmin;
    }

    public DirectExchange directExchange() {
        // 支持持久化,长期不用补删除
        return new DirectExchange(exchange, true, false);
    }


    public Queue mqQueue() {
        // 支持持久化
        return new Queue(queueName, true);
    }


    @Bean
    public ThreadPoolTaskExecutor getThreadPoolTask(){
        ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
        threadPoolTaskExecutor.setCorePoolSize(50);
        threadPoolTaskExecutor.setMaxPoolSize(100);
        threadPoolTaskExecutor.setQueueCapacity(10000);
        threadPoolTaskExecutor.setKeepAliveSeconds(300);
        threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
        return threadPoolTaskExecutor;
    }

    @Bean
    public SimpleMessageListenerContainer messageListenerContainer(ConnectionFactory connectionFactory){
        SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
        try {
            //实例化容器
            container.setConnectionFactory(connectionFactory);
            //concurrency  设置消费者数量
            container.setConcurrentConsumers(Integer.valueOf(concurrency));
            //prefetch 限制每次发送多少数据
            container.setPrefetchCount(Integer.valueOf(prefetch));
            //自动确认,设置手动会让 消息重试失效,没有重试需求的随意
            container.setAcknowledgeMode(AcknowledgeMode.AUTO);
            //设置线程池
            container.setTaskExecutor(getThreadPoolTask());
            container.setQueueNames(queueName);
            rabbitAdmin(connectionFactory).declareBinding(BindingBuilder.bind(mqQueue()).to(directExchange()).with(routkeyConsumer));
            // 白名单,如果本地Ip是属于我们设置的白名单里的。那么就正常的注册成功。
            // 如果本地IP不属于Ip白名单范围内。那么就不设置消费者,那么就会停止这个消费者:Stopping container from aborted consumer
            if (!includeIp()){
//                throw new RuntimeException("Mq services are not within the scope of the MQ whitelist,Please contact administrator");
                log.error("The current address, MQ is not supported. Please contact the administrator");
            }else{
                container.setMessageListener(rabbitmqResultConsumer);
            }
        }catch (RuntimeException e){
            log.error("Mq service client error message:【{}】",e.getMessage());
        }
        return container;
    }

    /**
     * 判断某个Ip是否属于自己定义的Ip段
     * @param ip
     * @param cidr
     * @return
     */
    public static boolean isInRange(String ip, String cidr) {
        String[] ips = ip.split("\\.");
        int ipAddr = (Integer.parseInt(ips[0]) << 24)
                | (Integer.parseInt(ips[1]) << 16)
                | (Integer.parseInt(ips[2]) << 8) | Integer.parseInt(ips[3]);
        int type = Integer.parseInt(cidr.replaceAll(".*/", ""));
        int mask = 0xFFFFFFFF << (32 - type);
        String cidrIp = cidr.replaceAll("/.*", "");
        String[] cidrIps = cidrIp.split("\\.");
        int cidrIpAddr = (Integer.parseInt(cidrIps[0]) << 24)
                | (Integer.parseInt(cidrIps[1]) << 16)
                | (Integer.parseInt(cidrIps[2]) << 8)
                | Integer.parseInt(cidrIps[3]);

        return (ipAddr & mask) == (cidrIpAddr & mask);
    }

    private boolean includeIp(){
        boolean flag = false;
        try {
            String ip = InetAddress.getLocalHost().getHostAddress();
            List<String> consumersList = Arrays.asList(StringUtils.split(consumersIp, ","));
            for (String e:consumersList){
                if (isInRange(ip,e)){
                    flag =  true;
                }
            }
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
        return flag;
    }
}

 classpath:rabbitmq.properties:

#环境 远程连接地址
#direct exchanges
mq.exchange=

#routeKey(发送端)
routkey.producer=routkey
#routeKey(接收端)
routkey.consumer=routkey.consumer

# remote Mq Ip List(Ip 白名单)
consumers.Ip=222.222.222.0/24

#队列名称
mq.queueName=queue_name
#限制每次发送一条数据。
mq.Listener.prefetch=1
#同一个队列启动几个消费者
mq.Listener.concurrency=1

创建自己的消费者:



/**
 * 消息模板队列消费者
 */
@Slf4j
@Component
public class RabbitmqDcgCalcResultConsumer implements ChannelAwareMessageListener{
	
	@Override
	public void onMessage(Message msg, Channel arg1) {
		
		} catch (Exception e) {
			log.error("消费计算结果的Message发生错误",e);
		} finally {
			
		}
	}
}

好了这次就写到这里。  如果想知道方案二的实现方式。那么就在下面留言。

好的,我来回答您的问题。 Java实现URL白名单可以通过使用Servlet Filter来实现。在Filter中,可以通过读取配置文件或者数据库中的白名单列表,对请求的URL进行过滤,只允许白名单中的URL访问,其他的URL则会被拒绝。具体实现可以参考以下代码: ```java public class UrlFilter implements Filter { private List<String> whiteList = new ArrayList<>(); @Override public void init(FilterConfig filterConfig) throws ServletException { // 读取白名单列表 String whiteListStr = filterConfig.getInitParameter("whiteList"); if (whiteListStr != null && !whiteListStr.isEmpty()) { String[] urls = whiteListStr.split(","); for (String url : urls) { whiteList.add(url.trim()); } } } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; String uri = req.getRequestURI(); if (whiteList.contains(uri)) { // 白名单中的URL放行 chain.doFilter(request, response); } else { // 拒绝非白名单中的URL访问 HttpServletResponse resp = (HttpServletResponse) response; resp.sendError(HttpServletResponse.SC_FORBIDDEN); } } @Override public void destroy() { // TODO: 做一些清理工作 } } ``` RabbitMQ实现定向消费可以通过设置Exchange和Queue的Binding Key来实现。Binding Key是一个字符串,可以使用通配符来匹配不同的Routing Key。在生产者发送消息时,需要指定Routing Key,这样消息就会被路由到对应的Queue中。在消费者端,可以通过设置Binding Key来指定需要消费的消息。具体实现可以参考以下代码: ```java // 创建Exchange和Queue Channel channel = connection.createChannel(); channel.exchangeDeclare("direct_exchange", "direct"); channel.queueDeclare("direct_queue", true, false, false, null); channel.queueBind("direct_queue", "direct_exchange", "routing_key"); // 发送消息 channel.basicPublish("direct_exchange", "routing_key", null, "Hello, World!".getBytes()); // 接收消息 channel.basicConsume("direct_queue", true, new DefaultConsumer(channel) { @Override public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { String message = new String(body, "UTF-8"); System.out.println("Received message: " + message); } }); ``` 设置IP白名单可以通过在RabbitMQ的配置文件中设置access_control_list参数来实现。access_control_list参数是一个JSON格式的字符串,可以指定不同的用户和VHost的访问权限。具体实现可以参考以下代码: ```json { "users": [ { "name": "guest", "password_hash": "guest", "tags": "administrator" } ], "vhosts": [ { "name": "/", "tracing": false } ], "permissions": [ { "user": "guest", "vhost": "/", "configure": ".*", "write": ".*", "read": ".*" } ], "ip_list": [ "127.0.0.1", "192.168.0.1/24" ] } ``` 在上面的配置中,ip_list参数指定了允许访问RabbitMQIP地址列表。只有在这个列表中的IP地址才能够访问RabbitMQ
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值