Java 集成阿里云消息队列,日志消息存储

JSON 2018-04-24 23:35:57 5212

根据地区ECS分布,选择相同地区的消息队列组件,对  阿里云  消息队列我做了简单的压测,效果还是不错的,费用比较低。最近一个项目中实际应用到了阿里云的消息队列。用来处理日志和业务数据。测试可以选择公网topic。生产环境一定要选择与自己ECS相同的低于,比如你ECS是华南1,华北2,那么你的队列实例也选择相同的即可。

这篇可能给你要使用,或者已经使用阿里云队列的人员会有所帮助,其他请略过。

  Springboot   集成阿里云队列:https://www.sojson.com/blog/293.html

阿里云集群/广播消费:https://help.aliyun.com/document_detail/43163.html

  Spring  集成消息队列:https://help.aliyun.com/document_detail/29553.html

  Java   环境准备:https://help.aliyun.com/document_detail/29546.html

事物消息队列:https://help.aliyun.com/document_detail/29548.html

日志队列消费者

消费我采用多节点  Springboot   微服务消费。直接上代码了。

@Configuration
@Slf4j
public class QueueConsumer {


    @Value("${aliyun.accessKey}")
    private String accessKey;
    @Value("${aliyun.accessSecretKey}")
    private String secretKey;



    @Value("${aliyun.queue.stock.consumerId}")
    private String stockConsumerId;
    @Value("${aliyun.queue.stock.topic}")
    private String stockTopic;
    @Value("${aliyun.queue.log.consumerId}")
    private String logConsumerId;
    @Value("${aliyun.queue.log.topic}")
    private String logTopic;
    @Autowired
    AppleCheckUtils appleCheckUtils;
    @Autowired
    StockDetailsService stockDetailsService;
    @Autowired
    StockService stockService;
    @Autowired
    LogRepository logRepository;
    @Autowired
    LogUtils logUtils;

    @Bean(name="stockConsumerBean")
    public ConsumerBean initStockConsumerBean(){
        ConsumerBean consumerBean = new ConsumerBean();
        Properties properties = new Properties();
        properties.put(PropertyKeyConst.ConsumerId, stockConsumerId);
        properties.put(PropertyKeyConst.AccessKey, accessKey);
        properties.put(PropertyKeyConst.SecretKey, secretKey);
        properties.put(PropertyKeyConst.ConsumeThreadNums, 10);

        consumerBean.setProperties(properties);

        //监听消息
        MessageListener messageListener = (message, context) -> {

            String json = new String(message.getBody());
            SOMap<String,String> map = new Gson().fromJson(json, SOMap.class);
            String transactionId = map.get("transactionId");
            String checksum = map.get("checksum");


            log.info("队列消费开始:[]。transactionId:{} , checksum:{}",message.getMsgID(),transactionId,checksum);
            logUtils.init(1L)
                    .begin().log("队列消费开始:[]。transactionId:{} , checksum:{}",message.getMsgID(),transactionId,checksum).businessId(checksum);
            try {
                StockDetails stockDetails = stockDetailsService.findById(transactionId);
                if(null == stockDetails){
                    log.error("队列消费出现查询不到stockDetails对象:[{}]。transactionId:{} , checksum:{}",message.getMsgID(),transactionId,checksum);
                    logUtils.error("队列消费出现查询不到stockDetails对象:[{}]。transactionId:{} , checksum:{}",message.getMsgID(),transactionId,checksum)
                            .end().send();
                    return Action.ReconsumeLater;
                }
                if(!new Integer(0).equals(stockDetails.getStatus())){
                    log.error("队列消费出现stockDetails.status != 0:[{}],:[{}]。transactionId:{} , checksum:{}",stockDetails.getStatus(),message.getMsgID(),transactionId,checksum);
                    logUtils.error("队列消费出现stockDetails.status != 0:[{}],:[{}]。transactionId:{} , checksum:{}",stockDetails.getStatus(),message.getMsgID(),transactionId,checksum)
                            .end().send();
                    return Action.CommitMessage;
                }
                Boolean result = appleCheckUtils.check(stockDetails.getReceiptDataOne(), transactionId, checksum);
                if(result){
                    stockDetailsService.updateStatus1ByQueue(stockDetails,checksum);
                    return Action.CommitMessage;
                }
                logUtils.log("{}:队列成功 :transactionId:{}",checksum,transactionId)
                        .end().send();
                return Action.ReconsumeLater;
            }catch (Exception e) {
                log.error("{}:队列执行失败 :transactionId:{}",checksum,transactionId,e);
                logUtils.error("{}:队列执行失败 :transactionId:{}",checksum,transactionId)
                        .end().send();
                return Action.ReconsumeLater;
            }
        };
        Map<Subscription, MessageListener> subscriptionTable = new HashMap<>();

        Subscription subscription = new Subscription();
        subscription.setTopic(stockTopic);
        subscription.setExpression("*");
        subscriptionTable.put(subscription,messageListener);
        consumerBean.setSubscriptionTable(subscriptionTable);
        consumerBean.start();




        return consumerBean;
    }

    @Bean(name="logConsumerBean")
    public ConsumerBean initLogConsumerBean(){
        ConsumerBean consumerBean = new ConsumerBean();
        Properties properties = new Properties();
        properties.put(PropertyKeyConst.ConsumerId, logConsumerId);
        properties.put(PropertyKeyConst.AccessKey, accessKey);
        properties.put(PropertyKeyConst.SecretKey, secretKey);
        properties.put(PropertyKeyConst.ConsumeThreadNums, 10);

        consumerBean.setProperties(properties);
        //监听消息
        MessageListener messageListener = (message, context) -> {


            String body = new String(message.getBody());
            Log logx = new Gson().fromJson(body, Log.class);

            try {
                logRepository.save(logx);
                return Action.CommitMessage;
            }catch (Exception e) {
                log.error("日志队列出错",e);
                return Action.ReconsumeLater;
            }
        };
        Map<Subscription, MessageListener> subscriptionTable = new HashMap<>();

        Subscription subscription = new Subscription();
        subscription.setTopic(logTopic);
        subscription.setExpression("*");
        subscriptionTable.put(subscription,messageListener);
        consumerBean.setSubscriptionTable(subscriptionTable);
        consumerBean.start();

        return consumerBean;
    }
}

消息生产者

消息生产者是用普通的SSM项目,  XML  配置的,也是直接贴代码了。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="producer" class="com.aliyun.openservices.ons.api.bean.ProducerBean" init-method="start" destroy-method="shutdown">
        <!-- Spring 接入方式支持 Java SDK 支持的所有配置项 -->
        <property name="properties" > <!--生产者配置信息-->
            <props>
                <prop key="ProducerId">${queue_log_producerId}</prop> <!--请替换 XXX-->
                <prop key="AccessKey">${aliyun_accessKey}</prop>
                <prop key="SecretKey">${aliyun_accessSecretKey}</prop>
            </props>
        </property>
    </bean>

    <!--<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">-->
        <!--<property name="staticMethod" value="com.sojson.common.utils.LogUtils.setProducer"/>-->
        <!--<property name="arguments" ref="producer"/>-->
    <!--</bean>-->

    <bean id="logUtils" class="com.sojson.common.utils.LogUtils" init-method="init">
<property name="producer" ref="producer" /> <property name="logTypeService" ref="logTypeService" /> <property name="logTopic" value="${queue_log_topic}" /> <property name="logPriducerId" value="${queue_log_producerId}" /> </bean> </beans>

另外贴一下我的日志工具类。就是会同步到队列里去,然后消费日志入库的操作。

@Slf4j
@Data
@Component
public final class LogUtils {

    private Log logEntity;

    private LogUtils(){}


    public String logTopic;

    public String logPriducerId;
    private int id;

    private ProducerBean producer;

    private LogTypeService logTypeService;


    /**
     * 初始化log工具类,
     * @param type  日志的类型,如果没有必须要先添加,填写ID
     * @return
     */
    public  LogUtils init(int type){
        //保存上一次的,里面会判断是否为null
        send();
        i(type);
        return this;
    }

    void i(int id){
        Log elog = new Log();
        this.id = id;
        elog.setLogType(id);
        elog.setLogTypeName(LogType.get(id));
        elog.setId(MathUtil.uuid());
        this.logEntity = elog;
    }
    public LogUtils clear(){
        return init(this.id);
    }

    /**
     * 操作之前描述
     * @param obj
     * @return
     */
    public LogUtils before(Object obj){
        if(obj !=null){
            String before = toJSON(obj);
            this.logEntity.setBeforex(before);
        }
        return this;
    }
    /**
     * 改变之后描述
     * @param obj
     * @return
     */
    public LogUtils after(Object obj){
        if(obj !=null){
            String after = toJSON(obj);
            this.logEntity.setAfterx(after);
        }
        return this;
    }
    //业务ID
    public LogUtils businessId(Object id){
        if(id !=null){
            String businessId = id.toString();
            this.logEntity.setBusinessId(businessId);
        }
        return this;
    }
    //操作用户
    public LogUtils memberName(String name){
        if(name !=null){
            this.logEntity.setMemberName(name);
        }
        return this;
    }
    /**
     * 用户信息id,可以是操作id,可以是数据相关的用户ID
     * @param id
     * @return
     */
    public LogUtils memberId(Long id){
        if(id !=null){
            this.logEntity.setMemberId(id);
        }
        return this;
    }
    public LogUtils member(){
        Member token = TokenManager.getToken();
        if(token !=null){
            this.logEntity.setMemberName(token.getUserName());
            this.logEntity.setMemberId(token.getId());
        }
        return this;
    }
    //直接给一个用户对象
    public LogUtils member(Member token){

        if(token !=null){
            this.logEntity.setMemberName(token.getUserName());
            this.logEntity.setMemberId(token.getId());
        }
        return this;
    }

    /**
     * 描述信息
     * @param str   第一个是字符串,后面可以多个参数,占位用“{}”
     * @return
     */
    public LogUtils log(Object...str){
        return out(str);
    }
    public LogUtils error(Object...str){
        if(null != this.logEntity){
            this.logEntity.setType(2);
        }
        return out(str);
    }
    LogUtils out(Object...str){
        if(str !=null && str.length !=0){
            //默认log类型
            if(null != this.logEntity && null == this.logEntity.getType()){
                this.logEntity.setType(1);
            }

            String logstr = (String)str[0];
            if(str.length > 1){
                for(int i=1;i<str.length;i++){
                    String element = toJSON(str[i]);
                    logstr = logstr.replaceFirst("\\{\\s*?}",element);
                }
            }
            String old = StringUtils.trim(this.logEntity.getLogIntro());
            if(null == old){
                this.logEntity.setLogIntro(logstr);
            }else{
                this.logEntity.setLogIntro(old +"\n"+logstr);
            }
        }
        return this;
    }
    /**
     * 参数信息
     * @param str   第一个是字符串,后面可以多个参数,占位用“{}”
     * @return
     */
    public LogUtils parms(Object...str){
        if(str !=null && str.length !=0){
            String logstr = (String) str[0];
            if(str.length > 1){
                for(int i=1;i<str.length;i++){
                    String element = toJSON(str[i]);
                    logstr = logstr.replaceFirst("\\{\\s*?}",element);
                }
            }
            String old = this.logEntity.getParms();
            if(null == old){
                this.logEntity.setParms(logstr);
            }else{
                this.logEntity.setParms(old +" \n "+logstr);
            }
        }
        return this;
    }

    /**
     * 开始时间
     * @return
     */
    public LogUtils begin(){
        return begin(new Date());
    }
    public LogUtils begin(Date date){
        this.logEntity.setBeginTime(date);
        return this;
    }

    /**
     * 结束时间
     * @return
     */
    public LogUtils end(){
        return end(new Date());
    }
    public LogUtils end(Date date){
        this.logEntity.setEndTime(date);

        //时间计算
        if(null != this.logEntity.getBeginTime()){
            this.logEntity.setTime(date.getTime() - this.logEntity.getBeginTime().getTime());
        }
        return this;
    }


    public void send(){
        if(null != logEntity && null != logEntity.getLogIntro() && null != logEntity.getId()){
            try{
                Message m = new Message();
                //创建时间
                this.logEntity.setCreateTime(new Date());

                m.setBody(new Gson().toJson(this.logEntity).getBytes());
                m.setTopic(logTopic);
                m.setTag("log");
                producer.send(m);
            }catch (Exception e){
                log.error("添加队列失败,:{}",e);
            }
        }
        i(id);
    }

    String toJSON(Object obj){
        try {
            String str;
            if(obj instanceof String || obj instanceof Integer|| obj instanceof Boolean || obj instanceof Short || obj instanceof Float || obj instanceof  Double|| obj instanceof Long || obj instanceof Byte){
                str =  String.valueOf(obj);
            }else{
                str = new Gson().toJson(obj);
            }
            return str;
        } catch (Exception e) {
            return obj.toString();
        }
    }



    public LogUtils debug(){
        if(null != this.logEntity){
            this.logEntity.setType(1);
        }
        return this;
    }
    public LogUtils warn(){
        if(null != this.logEntity){
            this.logEntity.setType(3);
        }
        return this;
    }


    public void setProducer(ProducerBean producer){
        this.producer = producer;
    }
    public void setLogPriducerId(String logPriducerId){
        this.logPriducerId = logPriducerId;
    }
    public void setLogTopic(String logTopic){
        this.logTopic = logTopic;
    }
    public void setLogTopic(LogTypeService logTypeService){
        this.logTypeService = logTypeService;
    }

    private void init() {
        LogType.init(logTypeService.findAll());
    }
}


版权所属:SO JSON在线解析

原文地址:https://www.sojson.com/blog/297.html

转载时必须以链接形式注明原始出处及本声明。

本文主题:

如果本文对你有帮助,那么请你赞助我,让我更有激情的写下去,帮助更多的人。

关于作者
一个低调而闷骚的男人。
相关文章
Springboot 集成Aliyun MQ消息队列,Aliyun 消息队列配置及代码实现
对Log4j 日志工具类的封装,java LoggerUtils查看和下载
阿里和腾讯哪个好?
阿里 RDS Specified key was too long; max key length is 767 bytes 解决方案
MySQL存储引擎
MySQL存储引擎
SpringBoot 集成Spring-data-redis,redis对象序列化存储
阿里的服务态度就是一坨屎,阿里你自己来看下你的服务。
阿里DNS 解析讲解,SEO配置搜索引擎线路解析
使用七牛存储实现图片API,自动删除图片方案合集
最新文章
文件上传漏洞与防御 4058
前端构建工具选型指南:Webpack、Vite、Rollup、esbuild 深度对比 1444
物联网时代2026年时序数据库选型指南 1151
SaaS行业面临AI挑战:从“无限复用”到“灵活适应” 1269
神经网络:从构造到模型训练全链路解析 1168
一文吃透 Redis 核心存储结构:ziplist、listpack 与哈希表扩容 / 并发查询 1593
Linux sudo提权完整指南:从基础用法到生产级安全配置 691
XSS 和 CSRF 的本质区别及开发防御全解析 772
JVM垃圾回收(GC)全维度解析:从原理到调优实战 813
Linux动静态库与ELF加载全解析:从实操制作到底层原理 912
最热文章
免费天气API,天气JSON API,不限次数获取十五天的天气预报 783114
最新MyEclipse8.5注册码,有效期到2020年 (已经更新) 711464
苹果电脑Mac怎么恢复出厂系统?苹果系统怎么重装系统? 679993
Jackson 时间格式化,时间注解 @JsonFormat 用法、时差问题说明 562673
我为什么要选择RabbitMQ ,RabbitMQ简介,各种MQ选型对比 512621
Elasticsearch教程(四) elasticsearch head 插件安装和使用 484794
Jackson 美化输出JSON,优雅的输出JSON数据,格式化输出JSON数据... ... 302947
Java 信任所有SSL证书,HTTPS请求抛错,忽略证书请求完美解决 247433
Elasticsearch教程(一),全程直播(小白级别) 233097
谈谈斐讯路由器劫持,你用斐讯路由器,你需要知道的事情 228329
支付扫码

所有赞助/开支都讲公开明细,用于网站维护:赞助名单查看

查看我的收藏

正在加载... ...