rabbitMq监听队列功能

之前一直搞rabbitMQ的安装与推送数据,今天组长突然让我做一个mq队列监听,突然就没了头绪不过后来根据原有项目提取出来监听发现还可以用,甚是欣慰于是修修补补做成了一个通用的队列监听,话不多说,代码贴上留作参考

首先是RabbitMQListen 类

package cn.com.iot.domain;

import cn.com.iot.bean.bo.DeviceData;
import cn.com.iot.controller.CSCommon;
import cn.com.iot.service.CsService;
import cn.com.iot.service.DeviceService;
import cn.com.iot.util.RabbitMQUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


@Configuration
@PropertySource("classpath:config.properties")
public class RabbitMQListen implements ApplicationListener<ContextRefreshedEvent> {

    /**
     * 日志
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(RabbitMQListen.class);

    /**
     * Redis 模板
     */
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private RedisTemplate redisTemplate;
    /**
     * 同步数据接口,将数据从Redis服务中持久化到MySQL数据库中
     */

    /**
     * MQ的host地址
     */
    @Value("${mq.host}")
    private String host;

    /**
     * MQ的端口
     */
    @Value("${mq.port}")
    private int port;

    /**
     * MQ的登录名
     */
    @Value("${mq.name}")
    private String name;

    /**
     * MQ的密码
     */
    @Value("${mq.password}")
    private String password;

    /**
     * 监听原始业务数据的队列名
     */
    @Value("${business.orgData.queue}")
    private String businessDataQueue;

    /**
     * 处理业务数据的线程数量
     */
    @Value("${business.collection.conn}")
    private int businessCollectionConn;

    /**
     * 每个线程每次处理多少条数据
     */
    @Value("${business.getData.count}")
    private int businessGetDataCount;

    /**
     * 同步指标数据到MySql中线程数量
     */
    @Value("${save.targetData.conn}")
    private int saveTargetDataConn;

    /**
     * 每个线程每次同步多少条指标数据到数据库中
     */
    @Value("${save.targetData.count}")
    private int saveTargetDataCount;

    /**
     * 同步原始数据到MySql中线程数量
     */
    @Value("${save.collectionData.conn}")
    private int saveCollectionDataConn;

    /**
     * 每个线程每次同步多少条原始数据到数据库中
     */
    @Value("${save.collectionData.count}")
    private int saveCollectionDataCount;

    /**
     * 资源数据同步模块监听的MQ队列名
     */
    @Value("${sync.resourceData.queue}")
    private String syncResourceDataQueue;
    /**
     * 资源数据同步模块每次从MQ中取出多少条数据
     */
    @Value("${sync.resourceData.count}")
    private int syncResourceDataCount;
    /**
     * list 统计
     */
    public static int listCount = 0;
    /**
     * 开始时间
     */
    private static long startTime = 0;
    @Autowired
    private CsService csService;
    @Autowired
    private DeviceService deviceService;
    /**
     * TODO 测试方法,用来记录测试时间以及测试的数据量,后续删除
     *
     * @param count
     */
    public static synchronized void addListCount(int count) {
        if (listCount == 0 && count != 0) {
            startTime = System.currentTimeMillis();
            System.out.println("startTime : " + startTime);
        }
        listCount += count;
        if (listCount == 200000) {
            long endTime = System.currentTimeMillis();
            System.out.println("endTime : " + endTime);
            System.out.println("totalTime : " + (endTime - startTime));
            listCount = 0;
        }
    }
    /**
     * 该方法会被spring在服务启动完成之后自动执行
     * 利用该方法,可以实现在服务启动之后,自动调用我们需要的功能。
     * 通过异步,则能实现自定义的各功能模块自动运行
     *
     * @param contextRefreshedEvent
     */
    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        try {
            // 初始化MQ的工厂
            RabbitMQUtil.initFactory2(host,port,name,password);
            // 启用业务数据处理功能(从MQ拿原始数据---转换为指标数据---存入redis)
            listenOrgData();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    private void listenOrgData() {
        LOGGER.info("================= Mq监听功能启动成功 =================");
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    // 通过线程池来控制该业务功能的线程数,具体线程数通过配置文件指定
                    ExecutorService executorService = Executors.newFixedThreadPool(businessCollectionConn);
                    while (true){
                        executorService.execute(new Runnable() {
                            public void run() {
                                try {
                                    RabbitMQUtil.initFactory(host,port);
                                    // 调用消息接收方法,指定接收的队列以及本次获取的数据数量。队列名以及数据量由配置文件指定
                                    List<String> orgDatas = RabbitMQUtil.receiveMessages(businessDataQueue, businessGetDataCount);
                                    if (!orgDatas.isEmpty()){
                                        System.out.println("监听到的数据为:"+orgDatas);
                                        //进行数据处理给下层业务判断是否告警
                                        for (int i =0 ;i<orgDatas.size();i++){
                                            String orgData = orgDatas.get(i);
                                            //拿到deviceId进行解析
                                           /* JSONObject jsonObject = JSON.parseObject(orgData);*/
                                            DeviceData data = JSON.parseObject(orgData, new TypeReference<DeviceData>() {});
                                            System.out.println(data.getDeviceId());
                                            String deviceId = data.getDeviceId();
                                            String datas = data.getData();
                                            CSCommon cs = new CSCommon();
                                            Object commonmq = cs.commonmq(deviceId, datas);
                                            System.out.println(commonmq);
                                        }
                                    }
                                } catch (Exception e) {
                                    LOGGER.error("数据处理失败", e);
                                }
                            }
                        });
                        // 每间隔300毫秒创建一个新的线程向MQ取数据//错
                        //休眠15秒
                        Thread.sleep(10000);
                    }
                } catch (Throwable e) {
                    LOGGER.error("指标数据持久化功能异常,将于10秒后重新启动", e);
                    try {
                        Thread.sleep(10000);
                    } catch (Exception e1) {
                    }
                }
            }
        }).start();
    }
}

然后是用到的rabbitmqUtil

package cn.com.iot.util;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.QueueingConsumer;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@PropertySource("classpath:config.properties")
public class RabbitMQUtil {
    private static final Logger LOGGER = LoggerFactory.getLogger(RabbitMQUtil.class);
    private static final ConnectionFactory FACTORY = new ConnectionFactory();
    private static final List<Connection> CONNECTIONS = new ArrayList<Connection>();
    private static final int MAX_CONNECTION = 20;
    /**
     * MQ的host地址
     */
    @Value("${mq.host}")
    private String host;


    /**
     * MQ的端口
     */
    @Value("${mq.port}")
    private int port;


    static {
        initFactory("192.168.10.156",5672);
    }
    /**
     * 向指定的消息队列发送消息
     *
     * @param message 消息体
     * @param queue   队列名
     */
    public static void sendMessage(String message, String queue) {
        try {
            // 从队列中获取一个连接
            Connection connection = getConnection();
            // 创建一个MQ的管道
            Channel channel = connection.createChannel();
            // 将管道绑定到一个队列上
            channel.queueDeclare(queue, false, false, false, null);
            // 向指定的队列发送消息
            channel.basicPublish("", queue, null, message.getBytes("UTF-8"));
            // 关闭管道
            channel.close();
            // 将连接放回到队列中
            setConnection(connection);
        } catch (Exception e) {
            throw new RuntimeException("RabbitMQ connection fail, send message fail!", e);
        }
    }


    public static void sendMessageList(List<Map<String, Object>> message, String queue) {
        try {
            // 从队列中获取一个连接
            Connection connection = getConnection();
            // 创建一个MQ的管道
            Channel channel = connection.createChannel();

            // 将管道绑定到一个队列上
            channel.queueDeclare(queue, false, false, false, null);
            for (Map<String, Object> map : message) {
                // 向指定的队列发送消息

                channel.basicPublish("", queue, null, JsonUtil.toJson(map).getBytes("UTF-8"));
            }

            // 关闭管道
            channel.close();
            // 将连接放回到队列中
            setConnection(connection);
        } catch (Exception e) {
            throw new RuntimeException("RabbitMQ connection fail, send message fail!", e);
        }
    }

    /**
     * 向指定的消息队列取出固定数量的数据
     *
     * @param queue 消息队列名
     * @param count 取出的消息数量
     * @return
     */
    public static List<String> receiveMessages(String queue, int count) {
        List<String> list = new ArrayList<String>();
        try {
            // 从队列中获取连接
            Connection connection = getConnection();
            // 创建一个管道
            Channel channel = connection.createChannel();
            // 将管道绑定到队列上
            channel.queueDeclare(queue, false, false, false, null);

            // 向指定的队列中获取数据,通过循环,每次循环获取一条数据,总共循环count次
            QueueingConsumer consumer = new QueueingConsumer(channel);
            channel.basicConsume(queue, false, consumer);
            for (int i = 0; i < count; i++) {
                QueueingConsumer.Delivery delivery = consumer.nextDelivery(300);
                if (delivery == null) {
                    break;
                }
                String message = new String(delivery.getBody());
                list.add(message);
                channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);

            }
            // 关闭管道
            channel.close();
            // 将连接放回到队列中
            setConnection(connection);
        } catch (Exception e) {
            LOGGER.error("RabbitMQ connection fail, receive message fail!", e);
        } finally {
            return list;
        }
    }

    /**
     * 从队列中获取连接
     *
     * @return
     */
    public static Connection getConnection() {
        try {
            return getAndSetConnection(true, null);
        } catch (Exception e) {
            throw new RuntimeException("connection MQ fail", e);
        }
    }

    /**
     * 将使用完毕的连接放回到队列中
     *
     * @param connection
     */
    private static void setConnection(Connection connection) {
        try {
            getAndSetConnection(false, connection);
        } catch (Exception e) {
            throw new RuntimeException("connection MQ fail", e);
        }
    }

    /**
     * 通过同步锁控制连接队列,根据参数isGet来区分本次调用是从队列中取连接还是存放连接
     * @param isGet      取出或者放回的标记,true表示取连接,false表示放回连接
     * @param connection 取连接:null, 放回连接:具体连接对象
     * @return 取连接时,返回具体连接对象,放回连接时,返回null
     * @throws Exception
     */
    private static synchronized Connection getAndSetConnection(boolean isGet, Connection connection) throws Exception {
        if (isGet) {
            // 取连接,如果队列中不存在连接,则新建一个连接
            if (CONNECTIONS.isEmpty()) {
                return FACTORY.newConnection();
            }
            Connection newConnection = CONNECTIONS.get(0);

            CONNECTIONS.remove(0);
            if (newConnection.isOpen()) {
                return newConnection;
            } else {
                return FACTORY.newConnection();
            }
        } else {
            // 放回连接,如果队列中的连接数超过了MAX_CONNECTION指定数量的连接,则抛弃该连接
            if (CONNECTIONS.size() < MAX_CONNECTION) {
                CONNECTIONS.add(connection);
            }
            return null;
        }
    }

    public static void initFactory(String host, int port) {

        FACTORY.setHost(host);
        FACTORY.setPort(port);
        FACTORY.setUsername("admin");
        FACTORY.setPassword("admin");
    }
    
    public static void initFactory2(String host, int port,String name,String password) {
        System.out.println("mq登录成功");
        FACTORY.setHost(host);
        FACTORY.setPort(port);
        FACTORY.setUsername(name);
        FACTORY.setPassword(password);
    }
}

最后就是配置文件 config.properties

#mq地址、端口
mq.host = 192.168.10.156
mq.port = 5672
mq.name = admin
mq.password = admin


#mq队列名、处理业务数据的线程数量、每个线程每次处理多少条数据
business.orgData.queue = test
business.collection.conn = 4
business.getData.count = 7000

# 线程数量、数据
save.targetData.conn = 4
save.targetData.count = 10000

# 线程数量、数据
save.collectionData.conn = 4
save.collectionData.count = 10000

# 队列名。处理数据条数
sync.resourceData.queue = guangzhou_syncResource_role
sync.resourceData.count = 1000

order.business.type = guangzhou_orderBusiness

# 最大连接数数
box.data.process.conn = 4
box.data.process.queue = guangzhou_orgDataConfig
box.data.process.count = 1

项目一启动,调用线程实时监听功能实时监听配置mq队列中的消息然后进行业务处理

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值