rocketMQ的使用

首先服务器配置好MQ

其次添加maven依赖,增加mq配置,例如nameserver地址。

创建生产者要素

  1.  NameServer.   //boker的ip+端口。
  2.  生产者组的name名字。
  3. 也可以有其他 键值对。

创建Message要素。

  1. topic   //一个主题。主题会有消费者订阅。
  2. tag     //标签同一个标题下也会有不同的分支。
  3. 要传信息String的code[]。//可以通过json工具转成code【】。
FxTaskCommonMessageDTO fxTaskCommonMessageDTO = new FxTaskCommonMessageDTO();
fxTaskCommonMessageDTO.setType(tag);
fxTaskCommonMessageDTO.setBody(body);
fxTaskCommonMessageDTO.setUniqueId(UUID.randomUUID().toString());
//直接将一个对象转成jsonString的code形式
Message message = new Message(topic, tag,JSON.toJSONBytes(fxTaskCommonMessageDTO));

创建好生产者后,statr()后,不shotdown()是不会停止的。可以将生成的生产者放入一个map中方便随时取用。

用map缓存生产者。

Properties properties = new Properties();
properties.setProperty(PropertyKeyConst.GROUP_ID, producerGroup.getCode());
properties.setProperty(PropertyKeyConst.AccessKey, accessKey);
properties.setProperty(PropertyKeyConst.SecretKey, secretKey);
properties.setProperty(PropertyKeyConst.NAMESRV_ADDR, nameServer);
Producer producer = ONSFactory.createProducer(properties);
producer.start();
producerGroupMap.put(producerGroup.getCode(), producer);

 取生产者。发送消息。

Producer producer = producerGroupMap.get(producerGroup.getCode());
SendResult sendResult = producer.send(message);

创建消费者要素

  1. 消费组的name
  2. NameServer.  ///consumer.setNamesrvAddr("localhost:9876");
  3.  消费者订阅的topic和tag。
  4. 一个消息的处理方式例如:如下处理方式是注册一个监听。
    DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("please_rename_unique_group_name");
    consumer.setNamesrvAddr("localhost:9876");
    consumer.subscribe("Topic", "zhangkai");
    consumer.registerMessageListener(new MessageListenerConcurrently() {
    @Override
    public ConsumeConcurrentlyStatus consumeMessage(List msgs,
    ConsumeConcurrentlyContext context) {
        System.out.println(fromBytes(msgs.get(0).getBody()));
        return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
       }
    });
    consumer.start();

    又或者实现    implements MessageListener接口。然后作为消费者的参数bean。

    @RocketMQMessageListener(consumerGroup = MQConstant.GID_NJIA_COMMON, topic = MQConstant.USER_GROWTH_ORDER, selectorExpression = "pay||aftersale||settle")
    //自定义的注解。记录着这个类是一个监听类.他的消费组名,订阅的top,多个tag。
    public class UserOrderGrowthListener implements MessageListener {
        @Override
        public Action consume(Message message, ConsumeContext consumeContext) {
        }
    }
    
    private void createConsumer() {
        Class clazz = AopProxyUtils.ultimateTargetClass(bean);
        RocketMQMessageListener annotation = clazz.getAnnotation(RocketMQMessageListener.class);
        consumer.subscribe(annotation.topic(), annotation.selectorExpression(), (MessageListener) bean);
        consumer.start();
    }

    如此就创建好了接收消息的消费者。消费消息只需要对接收消息的body进行操作。

    String msgBody;
    String tag;
    try {
        msgBody = new String(message.getBody());
        tag = message.getTag();
        UserOrderGrowthDTO userOrderGrowthDTO = JSON.parseObject(msgBody, UserOrderGrowthDTO.class);
         //一下对数据进行操作。
    } catch (Exception e) {
        LoggerUtil.error(defaultLogger, e, "订单成长值消息消费失败", userId);
        return Action.ReconsumeLater;
    } finally {
        if (Objects.nonNull(key)) {
           redisCacheManager.releaseLock(key, requestId);
        }
    }

     

完整生产者代码。

@Component
public class DefaultMQProducerTemplate implements InitializingBean {

    @Value("${rocketmq.consumer.accessKey}")
    private String accessKey;

    @Value("${rocketmq.consumer.secretKey}")
    private String secretKey;

    @Value("${rocketmq.consumer.onsAddr}")
    private String nameServer;

    private static final Logger logger = LoggerUtil.ROCKET_MQ;

    private static final Map producerGroupMap = Maps.newHashMap();

    private static final Map orderProducerGroupMap = Maps.newHashMap();

    @Override
    public void afterPropertiesSet() {
        for (ProducerGroup producerGroup : ProducerGroup.values()) {
            Properties properties = new Properties();
            properties.setProperty(PropertyKeyConst.GROUP_ID, producerGroup.getCode());
            properties.setProperty(PropertyKeyConst.AccessKey, accessKey);
            properties.setProperty(PropertyKeyConst.SecretKey, secretKey);
            properties.setProperty(PropertyKeyConst.NAMESRV_ADDR, nameServer);
            if (ConsumeMode.CONCURRENTLY == producerGroup.getConsumeMode()) {
                // 创建普通生产者
                Producer producer = ONSFactory.createProducer(properties);
                producer.start();
                producerGroupMap.put(producerGroup.getCode(), producer);
            } else {
                // 创建顺序生产者
                OrderProducer producer = ONSFactory.createOrderProducer(properties);
                producer.start();
                orderProducerGroupMap.put(producerGroup.getCode(), producer);
            }
        }
    }

    private static void validate(final Message message, final Admin admin) {
        Assert.isTrue(Objects.nonNull(admin), "生产者不存在");
        Assert.isTrue(Objects.nonNull(message), "消息不能为空");
    }

    /**
     * 发送顺序消息
     *
     * @param message       要发送的消息
     * @param shardingKey   全局顺序消息,该字段可以设置为任意非空字符串。分区顺序消息中区分不同分区的关键字段,sharding key于普通消息的key是完全不同的概念。
     * @param producerGroup 生产者组
     */
    public SendResult sendOrder(final Message message, String shardingKey, final ProducerGroup producerGroup) {
        OrderProducer orderProducer = orderProducerGroupMap.get(producerGroup.getCode());
        validate(message, orderProducer);
        try {
            // 同步发送消息,只要不抛异常就是成功
            return orderProducer.send(message, shardingKey);
        } catch (ONSClientException e) {
            // 消息发送失败,需要进行重试处理,可重新发送这条消息或持久化这条数据进行补偿处理
        }
        return null;
    }

    public SendResult send(final Message message, final ProducerGroup producerGroup) {
        return send(message, producerGroup, true);
    }

    public SendResult sendDelayMessage(final Message message, final LocalDateTime startDeliverTime, final ProducerGroup producerGroup) {
        // 设置消息需要被投递的时间
        message.setStartDeliverTime(LocalDateTimeUtil.getMilliByTime(startDeliverTime));
        return send(message, producerGroup, true);
    }

    /**
     * 发送同步消息
     *
     * @param message       要发送的消息
     * @param producerGroup 生产者组
     * @param compensate    是否持久化
     */
    public SendResult send(final Message message, final ProducerGroup producerGroup, final boolean compensate) {
        Producer producer = producerGroupMap.get(producerGroup.getCode());
        validate(message, producer);
        // 需要重试
        int retryTimes = 1;
        int maxRetryTimes = 3;
        String traceId = UUID.randomUUID().toString();
        do {
            try {
                // 同步发送消息,只要不抛异常就是成功
                if (retryTimes == 1) {
                    LoggerUtil.info(logger, "[RocketMQSend]", "start", traceId, producerGroup.getCode(), message.getTopic(), message);
                }
                SendResult sendResult = producer.send(message);
                LoggerUtil.info(logger, "[RocketMQSend]", "success", traceId, producerGroup.getCode(), sendResult.getTopic(), sendResult.getMessageId());
                return sendResult;
            } catch (ONSClientException e) {
                // 消息发送失败,需要进行重试处理,可重新发送这条消息或持久化这条数据进行补偿处理
                LoggerUtil.warn(logger, e, "[RocketMQSend]", "failed", traceId, producerGroup.getCode(), message.getTopic(), "retryTimes=" + retryTimes);
                if (retryTimes >= maxRetryTimes) {
                    if (compensate) {
                        messageCompensation(message, producerGroup);
                        return new SendResult();
                    } else {
                        throw new ONSClientException("超出重试次数");
                    }
                }
                retryTimes++;
            }
        } while (true);
    }

    /**
     * 发送消息,异步Callback形式
     *
     * @param message       要发送的消息
     * @param producerGroup 生产者组
     */
    public void sendAsync(final Message message, final ProducerGroup producerGroup) {
        String traceId = UUID.randomUUID().toString();
        LoggerUtil.info(logger, "[RocketMQSendAsync]", "start", traceId, producerGroup.getCode(), message.getTopic(), message);
        Producer producer = producerGroupMap.get(producerGroup.getCode());
        validate(message, producer);
        SendCallback sendCallback = new SendCallback() {
            @Override
            public void onSuccess(final SendResult sendResult) {
                // 消费发送成功
                LoggerUtil.info(logger, "[RocketMQSendAsync]", "success", traceId, sendResult.getTopic(), sendResult.getMessageId());
            }

            @Override
            public void onException(OnExceptionContext context) {
                // 消息发送失败,需要进行重试处理,可重新发送这条消息或持久化这条数据进行补偿处理
                LoggerUtil.warn(logger, context.getException(), "[RocketMQSendAsync]", "failed", traceId, producerGroup.getCode(), context.getTopic(), context.getMessageId());
                messageCompensation(message, producerGroup);
            }
        };
        producer.sendAsync(message, sendCallback);
    }


    /**
     * 发送消息,OneWay形式,服务器不应答,无法保证消息是否成功到达服务器
     *
     * @param message       要发送的消息
     * @param producerGroup 生产者组
     */
    public void sendOneWay(final Message message, final ProducerGroup producerGroup) {
        Producer producer = producerGroupMap.get(producerGroup.getCode());
        validate(message, producer);
        producer.sendOneway(message);
    }

    /**
     * 持久化MQ消息
     *
     * @param message
     * @param producerGroup
     */
    private void messageCompensation(Message message, ProducerGroup producerGroup) {
        String messageBody = new String(message.getBody());
        MQMessageCompensationDO compensationDO = new MQMessageCompensationDO(producerGroup.getCode(), message.getTopic(), message.getTag(), message.getKey(), messageBody);
        int success = mqMessageCompensationMapper.insertMessage(compensationDO);
        if (success <= 0) {
            LoggerUtil.error(logger, "[RocketMQSend]持久化失败");
            throw new ONSClientException("持久化失败");
        }
    }
}

 

消费者配置

import com.aliyun.openservices.ons.api.Consumer;
import com.aliyun.openservices.ons.api.MessageListener;
import com.aliyun.openservices.ons.api.ONSFactory;
import com.aliyun.openservices.ons.api.PropertyKeyConst;
import com.aliyun.openservices.ons.api.order.MessageOrderListener;
import com.aliyun.openservices.ons.api.order.OrderConsumer;
import com.google.common.collect.Maps;
import org.apache.logging.log4j.Logger;
import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Configuration;

import java.util.Map;
import java.util.Properties;

@Configuration
public class ConsumeConfiguration implements ApplicationContextAware, SmartInitializingSingleton {

    private static final Logger logger = LoggerUtil.COMMON_DEFAULT;

    @Value("${rocketmq.consumer.accessKey}")
    private String accessKey;

    @Value("${rocketmq.consumer.secretKey}")
    private String secretKey;

    @Value("${rocketmq.consumer.onsAddr}")
    private String nameServer;

    private ConfigurableApplicationContext applicationContext;

    private Map> consumerGroupMap = Maps.newHashMap();

    private Map> orderConsumerGroupMap = Maps.newHashMap();

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = (ConfigurableApplicationContext) applicationContext;
    }

    @Override
    public void afterSingletonsInstantiated() {
        Map beans = this.applicationContext.getBeansWithAnnotation(RocketMQMessageListener.class);
        beans.forEach(this::registerConsumer);
        createConsumer();
    }

    private void registerConsumer(String beanName, Object bean) {
        Class clazz = AopProxyUtils.ultimateTargetClass(bean);
        RocketMQMessageListener annotation = clazz.getAnnotation(RocketMQMessageListener.class);
        String consumerGroup = annotation.consumerGroup();
        String topic = annotation.topic();
        Map> groupMap;
        if (ConsumeMode.CONCURRENTLY == annotation.consumeMode()) {
            groupMap = consumerGroupMap;
            if (!MessageListener.class.isAssignableFrom(bean.getClass())) {
                throw new IllegalStateException(clazz + " is not instance of " + MessageListener.class.getName());
            }
        } else {
            groupMap = orderConsumerGroupMap;
            if (!MessageOrderListener.class.isAssignableFrom(bean.getClass())) {
                throw new IllegalStateException(clazz + " is not instance of " + MessageOrderListener.class.getName());
            }
        }
        if (!groupMap.containsKey(consumerGroup)) {
            groupMap.put(consumerGroup, Maps.newHashMap());
        }
        // 指针引用
        Map messageListenerMap = groupMap.get(consumerGroup);

        // 判断该consumerGroup是否有重复topic
        if (messageListenerMap.keySet().contains(topic)) {
            throw new IllegalStateException("[" + topic + "]" + " topic conflicts with existing," + bean.toString());
        }
        messageListenerMap.put(topic, bean);
        LoggerUtil.info(logger, "RegisterRocketMQ", beanName, annotation);
    }

    private void createConsumer() {
        // 普通消息订阅
        for (Map.Entry> entry : consumerGroupMap.entrySet()) {
            String consumerGroup = entry.getKey();
            Map messageListenerMap = entry.getValue();
            Properties consumerProperties = createProperties(consumerGroup);
            Consumer consumer = ONSFactory.createConsumer(consumerProperties);
            // 订阅多个topic
            for (Map.Entry topicEntry : messageListenerMap.entrySet()) {
                Object bean = topicEntry.getValue();
                Class clazz = AopProxyUtils.ultimateTargetClass(bean);
                RocketMQMessageListener annotation = clazz.getAnnotation(RocketMQMessageListener.class);
                consumer.subscribe(annotation.topic(), annotation.selectorExpression(), (MessageListener) bean);
            }
            consumer.start();
            LoggerUtil.info(logger, "Consumer start success.", consumerGroup);
        }

        // 顺序消息订阅
        for (Map.Entry> entry : orderConsumerGroupMap.entrySet()) {
            String consumerGroup = entry.getKey();
            Map messageListenerMap = entry.getValue();
            Properties consumerProperties = createProperties(consumerGroup);
            OrderConsumer consumer = ONSFactory.createOrderedConsumer(consumerProperties);
            // 订阅多个topic
            for (Map.Entry topicEntry : messageListenerMap.entrySet()) {
                Object bean = topicEntry.getValue();
                Class clazz = AopProxyUtils.ultimateTargetClass(bean);
                RocketMQMessageListener annotation = clazz.getAnnotation(RocketMQMessageListener.class);
                consumer.subscribe(annotation.topic(), annotation.selectorExpression(), (MessageOrderListener) bean);
            }
            consumer.start();
            LoggerUtil.info(logger, "Order Consumer start success.", consumerGroup);
        }
    }

    private Properties createProperties(String consumerGroup) {
        Properties consumerProperties = new Properties();
        consumerProperties.setProperty(PropertyKeyConst.GROUP_ID, consumerGroup);
        consumerProperties.setProperty(PropertyKeyConst.AccessKey, accessKey);
        consumerProperties.setProperty(PropertyKeyConst.SecretKey, secretKey);
        consumerProperties.setProperty(PropertyKeyConst.NAMESRV_ADDR, nameServer);
        return consumerProperties;
    }
}

你可能感兴趣的:(分布式,实习经历,java-rocketmq,rocketmq,windows)