pom.xml:
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>4.5.0</version>
</dependency>
1,生产者:
RocketMQUtils.java:
支持异步,同步,单向发送。
package com.equaker.cache.rocketmq;
import java.util.List;
import java.util.ResourceBundle;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.equaker.common.utils.SerializeUtils;
public class RocketMQUtils {
private static Logger logger = LoggerFactory.getLogger(RocketMQUtils.class);
private static final String CONFIG_PATH = "config/config";
// private static final String ROCKETMQ_TOPIC_TOPIC1 = "topic-1";
// private static final String ROCKETMQ_TAGS_TAGS1 = "tags-1";
// private static final String ROCKETMQ_PRODUCEGROUP = "produce_group1";
private static DefaultMQProducer producer = null;
static {
try {
ResourceBundle resourceBundle = ResourceBundle.getBundle(CONFIG_PATH);
if (resourceBundle == null) {
throw new IllegalArgumentException("[config.properties] is not found!");
}
final String ROCKETMQ_GROUP_NAME = resourceBundle.getString("rocketmq.groupName");
final String ROCKETMQ_IP = resourceBundle.getString("rocketmq.ip");
final String ROCKETMQ_RETRYTIMES = resourceBundle.getString("rocketmq.retryTimes");
final String ROCKETMQ_TIMEOUT = resourceBundle.getString("rocketmq.timeout");
producer = new DefaultMQProducer(ROCKETMQ_GROUP_NAME);
producer.setNamesrvAddr(ROCKETMQ_IP);
producer.start();
// producer.setRetryTimesWhenSendFailed(Integer.valueOf(ROCKETMQ_RETRYTIMES));
producer.setRetryTimesWhenSendAsyncFailed(Integer.valueOf(ROCKETMQ_RETRYTIMES));
producer.setSendMsgTimeout(Integer.valueOf(ROCKETMQ_TIMEOUT));
logger.info("producer init success >>>");
// jedisPool = RedisConfig.getInstance().getJedisPool();
} catch (Exception e) {
logger.error("producer init fail!!!", e);
}
}
/**
* 异步发送消息
* @param <T>
*
* @param callback 回调函数
* @param object 消息体
* @param keys 键值对,过滤数据使用
*/
public static <T> void asyncPush(String topic, String tags, String keys, SendCallback callback, List<T> objects) {
// for (int i = 0; i < objects.size(); i++) {
// // Create a message instance, specifying topic, tag and message body.
// Message msg = new Message(topic, tags, keys, SerializeUtils.serialize(objects.get(i)));
// try {
// producer.send(msg, callback);
// logger.info("send success>>>:");
// } catch (Exception e) {
// logger.info("send error>>>:", e);
// }
// }
objects.stream().forEachOrdered(p -> {
Message msg = new Message(topic, tags, keys, SerializeUtils.serialize(p));
try {
producer.send(msg, callback);
logger.info("send success>>>:");
} catch (Exception e) {
logger.info("send error>>>:", e);
}
});
}
/**
* 同步发送消息
* @param <T>
*
* @param keys 键值对,过滤数据使用
* @param object 消息体
*/
public static <T> void syncPush(String topic, String tags, String keys, List<T> objects) {
// Integer retLength = 0;// 消息推送成功 总数
// for (int i = 0; i < objects.size(); i++) {
// Message msg = new Message(topic, tags, keys, SerializeUtils.serialize(objects.get(i)));
// try {
// SendResult sendResult = producer.send(msg);
// logger.info("send success>>>:" + sendResult.getMsgId());
// retLength++;
// } catch (Exception e) {
// logger.info("send error>>>:", e);
// }
// }
objects.stream().forEachOrdered(p->{
Message msg = new Message(topic, tags, keys, SerializeUtils.serialize(p));
try {
SendResult sendResult = producer.send(msg);
logger.info("send success>>>:" + sendResult.getMsgId());
} catch (Exception e) {
logger.info("send error>>>:", e);
}
});
//return retLength;
}
/**
* 同步发送消息
* @param <T>
*
* @param keys 键值对,过滤数据使用
* @param object 消息体
*/
public static <T> void onewayPush(String topic, String tags, String keys, List<T> objects) {
// for (int i = 0; i < objects.size(); i++) {
// Message msg = new Message(topic, tags, keys, SerializeUtils.serialize(object[i]));
// try {
// producer.sendOneway(msg);
// logger.info("send success>>>:");
// } catch (Exception e) {
// logger.info("send error>>>:", e);
// }
// }
objects.stream().forEachOrdered(p->{
Message msg = new Message(topic, tags, keys, SerializeUtils.serialize(p));
try {
producer.sendOneway(msg);
logger.info("send success>>>:");
} catch (Exception e) {
logger.info("send error>>>:", e);
}
});
}
}
config.properties:
#### rocketMQ ####
rocketmq.groupName=produce_group1
rocketmq.ip=*:*
rocketmq.retryTimes=2
rocketmq.timeout=5000
消息生产者的配置如上,网上有生产者与spring结合,在需要的地方通过注入的方式使用,个人感觉没有必要,而且容易限制producer,毕竟生产者是包含produce group,topic,tags等信息的。本身只起到一个推送消息的作用,同redis的消息队列(左进右出,和发布订阅模式)类似。
2,消费者:
消费者应该是处于阻塞阶段的程序,需要时刻检测队列是否还有数据。所以需要与spring结合,把他的生命周期交给spring管理。
1,首先需要编写一个消息处理类,实现MessageListenerConcurrently接口(或者MessageListenerOrderly,一个单线程,顺序读取,另一个则是异步)。
MessageListenerImpl.java:
package com.equaker.cache.rocketmq;
import java.util.List;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.common.message.MessageExt;
import com.equaker.common.utils.SerializeUtils;
public class MessageListenerImpl implements MessageListenerConcurrently {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
for(MessageExt msg : msgs) {
//在这里进行相应的业务逻辑,这里直接进行打印
System.out.println(SerializeUtils.deserialize(msg.getBody()));
//System.out.println(new String(msg.getBody()));
}
System.out.println("*******************");
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
}
接下来配置 rocketmq 提供的默认消息消费者:DefaultMQPushConsumer
applicationContext.xml:
<!-- rocketmq 消费者配置 -->
<bean id="messageListeners" class="com.equaker.cache.rocketmq.MessageListenerImpl"></bean>
<!-- 导入Spring配置文件 -->
<bean id="rocketmqConsumer" class="org.apache.rocketmq.client.consumer.DefaultMQPushConsumer" init-method="start" destroy-method="shutdown">
<property name="consumerGroup" value="consume1"/>
<!-- <property name="instanceName"> -->
<!-- <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> -->
<!-- <property name="targetClass"> -->
<!-- <value>com.xx.utils.RunTimeUtil</value> -->
<!-- </property> -->
<!-- <property name="targetMethod"> -->
<!-- <value>getRocketMqUniqeInstanceName</value> -->
<!-- </property> -->
<!-- </bean> -->
<!-- </property> -->
<property name="namesrvAddr" value="你的外网地址:port"/>
<property name="messageListener" ref="messageListeners"/>
<property name="subscription">
<map>
<!-- 进行topic-1的订阅-->
<entry key="topic-1" value="*" />
</map>
</property>
</bean>
配置完毕。
3,测试:
启动spring项目,会发现rocketmq 的broker.log会有日志显示:
,此时编写produce测试类:
AppTest1.java:
package org.equaker.cache;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
import com.equaker.cache.rocketmq.RocketMQUtils;
public class AppTest1 {
public static void main(String[] args) {
List<Map<String, Object>> list = new ArrayList<Map<String,Object>>();
for (int i = 0; i < 5; i++) {
Map<String, Object> map = new HashMap<String, Object>();
map.put("name", "@EQuaker-" + i);
list.add(map);
}
RocketMQUtils.asyncPush("topic-1", "tags-1", "keys-1", new SendCallback() {
@Override
public void onSuccess(SendResult sendResult) {
System.out.println("messageid: "+sendResult.getMsgId());
}
@Override
public void onException(Throwable e) {
// TODO Auto-generated method stub
}
}, list);
// int length = RocketMQUtils.syncPush("topic-1", "tags-1", "keys-1", map);
// System.out.println(length);
}
}
运行如如下:
produce-console:
consume-tomcat-console:
番外篇:
其实 rocketmq 的消费者模式,一共有两种,MessageModel.CLUSTERING(集群模式), MessageModel.BROADCASTING(广播模式)。字面上就可以理解了。
- 集群模式:一个ConsumerGroup中的Consumer实例平均分摊消费消息。例如某个Topic有9条消息,其中一个ConsumerGroup有3个实例(可能是3个进程,或者3台机器),那么每个实例只消费其中部分,消费完的消息不能被其他实例消费。
- 广播模式:发布订阅模式了解一下,订阅同一个topic的所有消费者都会收到相同信息。
另外,消费者 模式是集群模式。如想修改为 广播模式,
consumer.setMessageModel(MessageModel.BROADCASTING);
》》》》》》》》》》》》》》》》》》》
暂时这么多了,以后会继续研究rocketmq事物,messagequeue和messagequeueselector等。
欢迎关注我的公众号:EQuaker,更多东西等你来拿。