由于需要在本地开发RocketMQ,于是在windows环境下搭建了一套RocketMQ的环境,记下来搭建的流程和注意的问题。
github的地址是:https://github.com/alibaba/RocketMQ/releases
我选择的是3.2.6的版本,页面上是这样的:
在Downloads那一栏有下载项,其中Source code是RocketMQ工程源代码,下载解压之后可以使用install.bat编译工程,或者使用mvn -Dmaven.test.skip=true clean packageinstall assembly:assembly –U命令编译工程(其实install.bat里面写的就是这个),编译之后可以得到可以运行的RocketMQ工程,其实也就是Downloads那一栏的alibaba-rocketmq-3.2.6.tar.gz,所以可以直接选择alibaba-rocketmq-3.2.6.tar.gz下载解压。
解压后的目录大概是这样的:
进入工程的bin目录,可以找到mqnamesrv.exe,双击打开就可以启动RocketMQ的server,如果程序显示The Name Server boot success.则说明启动成功。
我在这里遇见的坑:
1,工程文件夹的路径疑似不可以有中文。我一开始的路径有中文,双击mqnamesrv.exe后出现错误,显示:
This application has requested the runtimeto terminate it in an unusual way.
Please contact the aplication's supportteam for more information.
网上什么改注册表啊改dll啊都没用,直接把工程扔到e盘根目录下就解决了。
2,JDK需要64位的。另外版本太低的不行,JDK1.7是可以的。
3,在bin目录的mqnamesrv.xml文件中记录的server运行的一些配置,其中堆内存默认配置的<-Xms512m>-Xms512m>和<-Xmx1g>-Xmx1g>可能会有点小,我在运行的时候程序提示Error occurred during initialization of VM.Too small initial heapfor new size specified.这个错误一闪而过,程序就关闭了。把这两项分别改为<-Xms512m>-Xms512m>和<-Xmx1g>-Xmx1g>就可以解决。
在工程的bin目录下有mqbroker.exe文件,但是这个不能直接双击打开。
正确的打开方式是:在bin目录下打开一个命令行窗口,使用mqbroker -n 127.0.0.1:9876 命令启动,如果程序显示The broker... boot success.and name server is 127.0.0.1:9876 则说明启动成功了。
producer主要是用到了RocketMQ的DefaultMQProducer类,配置好NamesrvAddr属性和InstanceName属性,调用start方法,producer就启动起来了。
我用到的代码如下:
package com.tms.promise.job;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import com.alibaba.rocketmq.client.exception.MQClientException;
import com.alibaba.rocketmq.client.producer.DefaultMQProducer;
@Component
public class MyProducer {
private static final Logger logger = LoggerFactory.getLogger(MyProducer.class);
private static DefaultMQProducer defaultMQProducer;
private static String producerGroup;
private static String namesrvAddr;
static {
try {
init();
} catch (MQClientException e) {
e.printStackTrace();
}
}
public static void init() throws MQClientException {
// 参数信息
logger.info("DefaultMQProducer initialize!");
producerGroup = "MyProducerGroup";
namesrvAddr = "127.0.0.1:9876";
logger.info(producerGroup);
logger.info(namesrvAddr);
// 初始化
defaultMQProducer = new DefaultMQProducer(producerGroup);
defaultMQProducer.setNamesrvAddr(namesrvAddr);
defaultMQProducer.setInstanceName(String.valueOf(System.currentTimeMillis()));
defaultMQProducer.start();
logger.info("DefaultMQProudcer start success!");
}
public void destroy() {
defaultMQProducer.shutdown();
}
public DefaultMQProducer getDefaultMQProducer() {
return defaultMQProducer;
}
public void setProducerGroup(String producerGroup) {
this.producerGroup = producerGroup;
}
public void setNamesrvAddr(String namesrvAddr) {
this.namesrvAddr = namesrvAddr;
}
public String getProducerGroup(){
return producerGroup;
}
}
consumer主要是用到DefaultMQPushConsumer类,调用start方法:
consumer的代码如下:
package com.tms.promise.job;
import java.util.List;
import com.alibaba.rocketmq.client.exception.MQClientException;
import com.alibaba.rocketmq.client.consumer.DefaultMQPushConsumer;
import com.alibaba.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
import com.alibaba.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import com.alibaba.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import com.alibaba.rocketmq.common.message.MessageExt;
public class PushConsumer {
/**
* 当前例子是PushConsumer用法,使用方式给用户感觉是消息从RocketMQ服务器推到了应用客户端。
* 但是实际PushConsumer内部是使用长轮询Pull方式从MetaQ服务器拉消息,然后再回调用户Listener方法
*/
public static void main(String[] args) throws InterruptedException,
MQClientException {
/**
* 一个应用创建一个Consumer,由应用来维护此对象,可以设置为全局对象或者单例
* 注意:ConsumerGroupName需要由应用来保证唯一
*/
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer(
"ConsumerGroupName");
consumer.setNamesrvAddr("127.0.0.1:9876");
consumer.setInstanceName("Consumber");
/**
* 订阅指定topic=MyTopic下tags=MyTag的情形
*/
consumer.subscribe("MyTopic", "MyTag");
/**
* 订阅指定topic=MyTopic下所有tags
*/
consumer.subscribe("MyTopic", "*");
consumer.registerMessageListener(new MessageListenerConcurrently() {
public ConsumeConcurrentlyStatus consumeMessage(
List msgs, ConsumeConcurrentlyContext context) {
System.out.println(Thread.currentThread().getName()
+ " Receive New Messages: " + msgs.size());
MessageExt msg = msgs.get(0);
if (msg.getTopic().equals("MyTopic")) {
// 执行TopicTest1的消费逻辑
if (msg.getTags() != null && msg.getTags().equals("MyTag")) {
// 执行MyTag的消费
System.out.println(new String(msg.getBody()));
} else if (msg.getTags() != null
&& msg.getTags().equals("TagA")) {
// 执行TagA的消费
System.out.println(new String(msg.getBody()));
}
} else if (msg.getTopic().equals("TopicTest2")) {
System.out.println(new String(msg.getBody()));
}
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
/**
* Consumer对象在使用之前必须要调用start初始化,初始化一次即可
*/
consumer.start();
System.out.println("ConsumerStarted.");
}
}
发消息就是用DefaultMQProducer的send方法。
发消息的代码大概是这样的:
private MyProducer myProducer;
Message msg = newMessage("MyTopic", "MyTag", "messagebody".getBytes());//第一个参数是Topic,第二个参数是tags,第三个参数是消息体,需要转成byte数组
SendResult sendResult =myProducer.getDefaultMQProducer().send(msg);
if (sendResult == null ||sendResult.getSendStatus() != SendStatus.SEND_OK) {//这是发送失败的处理
}