业务场景之类的请看另一篇生产者的实现;
package com.ttt.eee; import com.aliyun.openservices.ons.api.Action; import com.aliyun.openservices.ons.api.Consumer; import com.aliyun.openservices.ons.api.ONSFactory; import com.aliyun.openservices.ons.api.PropertyKeyConst; import java.nio.charset.Charset; import java.util.Properties; import java.util.Scanner; public class MQTestConsumer { public static void main(String[] args) { Properties properties = new Properties(); // 您在控制台创建的 Group ID,其实就是网上说的groupName properties.put(PropertyKeyConst.GROUP_ID, "eee"); // AccessKey 阿里云身份验证,在阿里云服务器管理控制台创建 properties.put(PropertyKeyConst.AccessKey, "sss"); // SecretKey 阿里云身份验证,在阿里云服务器管理控制台创建 properties.put(PropertyKeyConst.SecretKey, "bbb"); // 设置 TCP 接入域名,到控制台的实例基本信息中查看 properties.put(PropertyKeyConst.NAMESRV_ADDR, "http://ttt.mq-internet-access.mq-internet.aliyuncs.com:80"); // 集群订阅方式 (默认) // properties.put(PropertyKeyConst.MessageModel, PropertyValueConst.CLUSTERING); // 广播订阅方式 // properties.put(PropertyKeyConst.MessageModel, PropertyValueConst.BROADCASTING); Consumer consumer = ONSFactory.createConsumer(properties); // TODO tag如果是*表示订阅所有的tag消息,注意在producer里是叫tags,这里却叫subExpresion // *表示订阅所有Tag,TagA||TagB表示订阅 TagA和TagB consumer.subscribe("xxx-change", "*", (message, context) -> { // context的用处暂时不知道 System.out.println("Receive: " + message); System.out.println("具体消息为:" + new String(message.getBody(), Charset.forName("UTF-8"))); // 正常消费返回这个,如果消费消息后业务处理出现问题一般返回:Action.ReconsumeLater表示这条消息晚点处理; return Action.CommitMessage; }); //订阅另外一个 Topic // TODO 一个Consumer可以订阅多个topic ??,不过既然是官网的例子应该是可以的 /*consumer.subscribe("TopicTestMQ-Other", "*", new MessageListener() { //订阅全部 Tag public Action consume(Message message, ConsumeContext context) { System.out.println("Receive: " + message); return Action.CommitMessage; } });*/ consumer.start(); System.out.println("Consumer Started"); var scanner = new Scanner(System.in); scanner.next(); consumer.shutdown(); System.out.println("closed producer conn."); } }
集合到Spring里是:
@Bean(initMethod = "start", destroyMethod = "shutdown") public ConsumerBean xxxNotify(XxxNotifyListener xxxNotifyListener) { return this.getConsumer(gid, topic, xxxNotifyListener); } private ConsumerBean getConsumer(String gid, String topic, MessageListener messageListener) { Properties properties = new Properties(); properties.setProperty("addr", addr); properties.setProperty("AccessKey", accessKey); properties.setProperty("SecretKey", secretKey); properties.setProperty("GROUP_ID", gid); Map<Subscription, MessageListener> subscriptionTable = new HashMap<>(); Subscription subscription = new Subscription(); subscription.setTopic(topic); // 这里还可以设置subExpression来描述tag(重要:这里有个很大的坑,就是我这里设置了tag是tagA
//,但是producer发送的是tagB的,尽管这里确实不会到consume方法里进行业务消费,但这个消息在消息队列里也是没有了,它不会将tagB的消息返回到mq里待消费
// 上面的总结可能不准确,这里当初是两个消费者用的一个groupId导致的,这个有机会再测试一下;
// 经过测试如果在创建Consumer时就指定 tags,那么这个consumer只消费这个tags的消息,非此tags的消息是不会消费掉的,其他group是可以消费那些消息的;
// 而对于一个topic里有两个消费组,且aGroup消费TagA,bGroup消费TagB,那么必须在创建consumer时就指定tags,而不能通过consume方法里面判断tag,然后
// 不符合要求的则return Action.ReconsumeLater,这样是有问题的,比如bGroup消费了这个消息,发现不是自己的tag准备return ...Later,此时aGroup也
// 消费了这个消息,发现是自己的tag,然后做了业务处理,这个时候bGroup就返回了...Later,那么这条消息就可能被aGroup重复消费;
subscriptionTable.put(subscription, messageListener); ConsumerBean consumer = new ConsumerBean(); consumer.setProperties(properties); consumer.setSubscriptionTable(subscriptionTable); return consumer; }
MessageListener里是用来实现消费这个消息后的具体业务逻辑的;