RocketMq注解形式实战——分布式微服务集成rocketmq

微服务集成rocketmq—注解形式实战

定义注解

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(MqAutoConfiguration.class)
public @interface EnableMq {
}

定义配置类注册Bean

@Data
public class MqProperties {

    /**
     * 生产者/消费者名称
     */
    private String name;

    /**
     * ip
     */
    private String host;

    /**
     * 端口
     */
    private String port;
}
package cn.mq.config;

import cn.mq.service.MyMqCustomer;
import cn.mq.service.MyMqProducer;
import cn.mq.service.impl.MyMqProducerImpl;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.common.protocol.heartbeat.SubscriptionData;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;

import java.util.Map;

/**
 * <p>
 *  生产者\消费者
 * </p>
 *
 */
@ComponentScan("cn.mq")
@EnableAutoConfiguration
@AllArgsConstructor
@Slf4j
@Configuration
public class MqAutoConfiguration {

    private final Environment environment;


    @Bean
    @ConfigurationProperties(prefix = "rocketmq")
    public MqProperties getMqProperTies() {
        return new MqProperties();
    }

    @Bean
    @ConditionalOnBean(MqProperties.class)
    public MyMqProducer myMqProducer(MqProperties mqProperties) throws MQClientException {
        log.info("==============[[启动 【MQ】 消息生产者]]=============");
        MyMqProducerImpl producer = new MyMqProducerImpl(environment.getProperty("spring.application.name", ""));
        producer.setNamesrvAddr(mqProperties.getHost() + ":" + mqProperties.getPort());
        producer.start();
        log.info("==============[[【MQ】 消息生产者启动成功]]=============");
        String namesrvAddr = producer.getNamesrvAddr();
        log.info("==============[[【producer----NamesrvAddr】 NamesrvAddr]]=============,NamesrvAddr={}",namesrvAddr);
        return producer;
    }

    @Bean
    @ConditionalOnBean({MqProperties.class, MyMqCustomer.class})
    public DefaultMQPushConsumer defaultMqPushConsumer(MqProperties mqProperties, MyMqCustomer mqCustomer) throws MQClientException {
        log.info("==============[[启动注册 【MQ】 消息消费者]]=============");
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer(environment.getProperty("spring.application.name", ""));
        consumer.setNamesrvAddr(mqProperties.getHost() + ":" + mqProperties.getPort());
        mqCustomer.subscribe(consumer);
        Map<String, SubscriptionData> sub = consumer.getDefaultMQPushConsumerImpl().getSubscriptionInner();
        sub.forEach((k, v) -> log.info("==============订阅topic【{}】, 子tags【{}】=============", k, v.getSubString()));
        mqCustomer.registerMessageListener(consumer);
        consumer.start();
        log.info("==============[[【MQ】 消息消费者注册成功]]=============");
        String namesrvAddr = consumer.getNamesrvAddr();
        log.info("==============[[【consumer----NamesrvAddr】 NamesrvAddr]]=============,NamesrvAddr={}",namesrvAddr);
        return consumer;
    }
}

生产者

package cn.mq.service;

import com.fasterxml.jackson.core.JsonProcessingException;
import org.apache.rocketmq.client.producer.MQProducer;

import java.io.UnsupportedEncodingException;


public interface MyMqProducer extends MQProducer {


    void sendImPushMsg(Integer targetUserId, Object msgType, Long dataId, String msg) throws JsonProcessingException, UnsupportedEncodingException;
}
package cn.mq.service.impl;

import cn.mq.service.MyMqProducer;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.remoting.common.RemotingHelper;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.UnsupportedEncodingException;


@Slf4j
@AllArgsConstructor
public class MyMqProducerImpl extends DefaultMQProducer implements MyMqProducer {

    @Autowired
    private ObjectMapper objectMapper;


    public MyMqProducerImpl(String producerGroup) {
        super(producerGroup);
    }

    @Override
    public void sendImPushMsg(Integer targetUserId, Object msgType, Long dataId, String msg) throws JsonProcessingException, UnsupportedEncodingException {
        JSONObject json = new JSONObject();
        json.put("creator", "zs");
        json.put("userId", targetUserId);
        json.put("type", JSONObject.toJSON(msgType));
        json.put("id", dataId);
        json.put("msg", msg);

        Message message = new Message("test-topic", null,
                objectMapper.writeValueAsString(json).getBytes(RemotingHelper.DEFAULT_CHARSET));
        SendResult sendResult = null;
        try {
            sendResult = this.send(message);
        } catch (Exception e) {
            e.printStackTrace();
        }
        log.info("IM推送消息[msgType:{}]发送MQ结果:{}", JSONObject.toJSON(msgType), sendResult.getSendStatus());
        if (sendResult.getSendStatus() != SendStatus.SEND_OK) {
            log.error("IM推送消息发送MQ失败,消息:{}", json.toJSONString());
        }

    }
}
生产者使用示例
package cn.rc100.oa.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.remoting.common.RemotingHelper;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

/**
 * <p>
 * 审核消息队列服务
 * </p>
 *
 */
@Slf4j
@Service
@AllArgsConstructor
public class AuditMqServiceImpl implements AuditMqService {

    private final MyMqProducer myMqProducer;
    private final ObjectMapper objectMapper;

    @Override
    public void sendAuditResult(Audit audit, Object obj) {
        if (ObjectUtil.isNull(obj)) {
            obj = audit;
        }
        try {
            Message msg = new Message(MqTopicConstants.OA_AUDIT_RESULT, audit.getType().toString(),
                    objectMapper.writeValueAsString(obj).getBytes(RemotingHelper.DEFAULT_CHARSET));
            SendResult sendResult = myMqProducer.send(msg);
            log.info("审核消息发送结果:{}", sendResult.getSendStatus());
        } catch (Exception e) {
            log.error("审核消息发送失败,审核Id:{},审核内容:{}", audit.getId(), audit.getContent());
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * <p>
     * 推送消息发送到mq
     * </p>
     *
     * @param targetUserId 目标用户id
     * @param type 推送消息类型
     * @param dataId 数据Id 用于数据跳转
     * @param msg 消息
     * @return void
     * @author xxx
     * @since ----
     */
    @Async
    public void sendToMq(Integer targetUserId, BaseMsgType type, Integer dataId, String msg) {
        try {
            JSONObject json = new JSONObject();
            json.put("creator", SecurityUtils.getUser() == null ? 1 : SecurityUtils.getUser().getId());
            json.put("userId", targetUserId);
            json.put("type", objectMapper.writeValueAsString(type));
            json.put("id", dataId);
            json.put("appKey", CommonConstants.EPLUS_APPKEY);
            json.put("msg", msg);
            Message message = new Message(MqTopicConstants.MSG_PUSH, null,
                    objectMapper.writeValueAsString(json).getBytes(RemotingHelper.DEFAULT_CHARSET));
            SendResult sendResult = myMqProducer.send(message);
            log.info("OA推送消息[key:{},des:{}]发送MQ结果:{}", type.getKey(), type.getDes(), sendResult.getSendStatus());
        } catch (Exception e) {
            log.error("OA推送消息发送MQ失败,类型:{},类型描述:{}", type.getKey(), type.getDes());
            e.printStackTrace();
        }
    }

    @Async
    @Override
    public void sendResultPushMsg(Audit audit, String reason) {
        String msg = StrUtil.format("您的{}审核已被{}", audit.getContent(), audit.getAuditStatus().getDescribe());
        if (audit.getAuditStatus() != OaAuditStatusEnum.PASSED && StrUtil.isNotBlank(reason)) {
            msg += StrUtil.LF + "原因:" + reason;
        }
        this.sendToMq(audit.getCreateUser(), OaMsg.create().audit().notification(), audit.getId(), msg);
    }

    @Async
    @Override
    public void sendAuditPushMsg(Audit audit, String auditUsers, boolean isUrge) {
        String str = "{}有一个{}审核需要您审批,请及时处理";
        if (isUrge) {
            str = "{}有一个{}审核急需您审批,请尽快处理";
        }
        String msg = StrUtil.format(str, audit.getCreateUserName(), audit.getContent());
        StrUtil.splitTrim(auditUsers, ",").stream()
                .filter(StrUtil::isNotBlank)
                .map(Integer::valueOf)
                .forEach(id -> this.sendToMq(id, OaMsg.create().audit().toDo(), audit.getId(), msg));
    }

    @Async
    @Override
    public void sendAuditCopyPushMsg(Audit audit, Integer userId) {
        String msg = StrUtil.format("您有一个{}的{}审核抄送,请知悉", audit.getCreateUserName(), audit.getContent());
        this.sendToMq(userId, OaMsg.create().copy().notification(), audit.getId(), msg);
    }
}

消费者

package cn.mq.service;

import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.exception.MQClientException;

/**
 * <p>
 * 消费者实例接口
 * </p>
 *
 */
public interface Consumer {
    /**
     * <p>
     * 消费监听
     * </p>
     *
     */
    void listener(DefaultMQPushConsumer consumer) throws MQClientException;
}

消费者使用

接口方式
package cn.mq.service;

import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.exception.MQClientException;

public interface MyMqCustomer {

    void subscribe(DefaultMQPushConsumer consumer) throws MQClientException;

    void registerMessageListener(DefaultMQPushConsumer consumer);
}
接口方式-其它微服务使用示例
package com.example.rock.mq;

import cn.mq.service.MyMqCustomer;
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.common.message.MessageExt;
import org.springframework.stereotype.Component;


@Slf4j
@Component
public class rockMqCustomer implements MyMqCustomer {
    @Override
    public void subscribe(DefaultMQPushConsumer consumer) throws MQClientException {
        consumer.subscribe("test-topic", "rock");
    }

    @Override
    public void registerMessageListener(DefaultMQPushConsumer consumer) {

        consumer.registerMessageListener((MessageListenerConcurrently) (msg, content) -> {
            log.info("消息接收成功");
            try {
                for (MessageExt m : msg) {
                    //log.info(m.getTopic()+":"+new String(m.getBody()));
                    if("test-topic".equals(m.getTopic())){
                        System.out.println("消费成功");
                    }
                }
            }catch (Exception e){
                return ConsumeConcurrentlyStatus.RECONSUME_LATER;
            }
            return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
        });

    }
}
抽象类方式
package cn.mq.service;

import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.common.message.MessageExt;

public interface SimpleConsumer {

    String getConsumerName();

    void subscribe(DefaultMQPushConsumer consumer);

    void consume(MessageExt msg);
}
package cn.mq;

import cn.hutool.core.util.StrUtil;
import cn.mq.config.MqProperties;
import cn.mq.service.Consumer;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.env.Environment;

/**
 * <p>
 * 消费者基类,用于多消费者实例
 * </p>
 */
@AllArgsConstructor
public abstract class BaseConsumer implements InitializingBean {
    private final Environment environment;
    private final MqProperties mqProperties;

    /**
     * <p>
     * 多消费者注册
     * </p>
     */
    protected abstract void register();

    /**
     * <p>
     * 新消费者
     * </p>
     *
     */
    @SneakyThrows
    protected void newConsumer(String consumerGroup, Consumer consumer) {
        if (StrUtil.isBlank(consumerGroup)) {
            consumerGroup = environment.getProperty("spring.application.name", "")
                    .replace("lx-", "")
                    .replace("-biz", "");
        }
        DefaultMQPushConsumer dc = new DefaultMQPushConsumer(consumerGroup);
        dc.setNamesrvAddr(mqProperties.getHost() + ":" + mqProperties.getPort());
        consumer.listener(dc);
        dc.start();
    }

    @Override
    public void afterPropertiesSet() {
        register();
    }
}
package cn.mq;

import cn.mq.config.MqProperties;
import cn.mq.service.SimpleConsumer;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.springframework.core.env.Environment;

/**
 * <p>
 * 简单消费者
 * </p>
 *
 */
@Slf4j
public abstract class BaseSimpleConsumer extends BaseConsumer implements SimpleConsumer {

    public BaseSimpleConsumer(Environment environment, MqProperties mqProperties) {
        super(environment, mqProperties);
    }

    @Override
    public String getConsumerName() {
        return null;
    }

    @Override
    protected void register() {
        newConsumer(this.getConsumerName(), consumer -> {
            this.subscribe(consumer);
            consumer.registerMessageListener((MessageListenerConcurrently)(msgs, context) -> {
                try {
                    msgs.forEach(m -> {
                        try {
                            log.info("收到MQ消息,Topic:{},Tags:{},Msg:{}", m.getTopic(), m.getTags(),
                                    JSONObject.toJSON(new String(m.getBody())));
                        } catch (Exception e) {
                            return;
                        }
                        this.consume(m);
                    });
                } catch (Exception e) {
                    e.printStackTrace();
                    return ConsumeConcurrentlyStatus.RECONSUME_LATER;
                }
                return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
            });
        });
    }
}

抽象类方式-其它服务使用示例
package cn.rc100.newhouse.mq;

import cn.mq.service.dto.DeptIdChangeDto;
import cn.mq.service.core.util.JacksonUtils;
import cn.mq.BaseSimpleConsumer;
import cn.mq.config.EplusMqProperties;
import cn.mq.constant.MqTopicConstants;
import lombok.SneakyThrows;
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.common.protocol.heartbeat.MessageModel;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

/**
 * <p>
 * mq消费者
 * </p>
 *
 */
@Component
public class MqNbCustomer extends BaseSimpleConsumer {

    private final OperationLogService operationLogService;
    private final UserDeptService userDeptService;
    private final RebateService rebateService;

    public MqNbCustomer(Environment environment, EplusMqProperties eplusMqProperties, OperationLogService operationLogService,
                        UserDeptService userDeptService, RebateService rebateService) {
        super(environment, eplusMqProperties);
        this.operationLogService = operationLogService;
        this.userDeptService = userDeptService;
        this.rebateService = rebateService;
    }

    @SneakyThrows
    @Override
    public void subscribe(DefaultMQPushConsumer consumer) {
        consumer.setMessageModel(MessageModel.BROADCASTING);
        consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
        consumer.subscribe(MqTopicConstants.DEPT_TRANSFER, "*");
        consumer.subscribe(MqTopicConstants.USER_DEPT_TRANSFER, "*");
        consumer.subscribe(MqTopicConstants.OA_AUDIT_RESULT, "34 || 35 || 36 || 38 || 39");
    }

    @Override
    public void consume(MessageExt msg) {
        // 部门调动
        if (MqTopicConstants.DEPT_TRANSFER.equals(msg.getTopic())) {
            DeptIdChangeDto changeDto = JacksonUtils.toBean(msg.getBody(), DeptIdChangeDto.class);
            operationLogService.deptTransfer(changeDto);
        } else if (MqTopicConstants.USER_DEPT_TRANSFER.equals(msg.getTopic())) {
            DeptIdChangeDto changeDto = JacksonUtils.toBean(msg.getBody(), DeptIdChangeDto.class);
            userDeptService.userDeptTransfer(changeDto);
        } else if (MqTopicConstants.OA_AUDIT_RESULT.equals(msg.getTopic())) {
            AuditResultVo result = JacksonUtils.toBean(msg.getBody(), AuditResultVo.class);
            rebateService.auditRebate(result);
        }
    }
}

服务启动类

添加自定义注解@EnableMq
package com.example.rock;

import cn.mq.annotation.EnableMq;
import cn.swagger.annotation.EnableSwagger;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@EnableMq
@EnableXxlJob
@EnableSwagger
@SpringCloudApplication
public class RockApplication {
    public static void main(String[] args) {
        SpringApplication.run(RockApplication.class, args);
    }
}
posted @ 2022-02-21 17:04  随风笔记  阅读(1296)  评论(0)    收藏  举报