第一步:添加maven依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--springboot继承junit的起步依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- rocketmq所需依赖 -->
<dependency>
<groupId>com.alibaba.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>3.5.8</version>
</dependency>
</dependencies>
第二步:applicaiton.properties内容如下:
spring.application.name=springboot-rocketmq
server.port=8888
###producer
#该应用是否启用生产者
rocketmq.producer.isOnOff=on
#发送同一类消息的设置为同一个group,保证唯一,默认不需要设置,rocketmq会使用ip@pid(pid代表jvm名字)作为唯一标示
rocketmq.producer.groupName=${spring.application.name}
#mq的nameserver地址
rocketmq.producer.namesrvAddr=192.168.2.203:9876
#消息最大长度 默认1024*4(4M)
rocketmq.producer.maxMessageSize=4096
#发送消息超时时间,默认3000
rocketmq.producer.sendMsgTimeout=3000
#发送消息失败重试次数,默认2
rocketmq.producer.retryTimesWhenSendFailed=2
###consumer
##该应用是否启用消费者
rocketmq.consumer.isOnOff=on
rocketmq.consumer.groupName=${spring.application.name}
#mq的nameserver地址
rocketmq.consumer.namesrvAddr=192.168.2.203:9876
#该消费者订阅的主题和tags("*"号表示订阅该主题下所有的tags),格式:topic~tag1||tag2||tag3;topic2~*;
rocketmq.consumer.topics=DemoTopic~*;
#rocketmq.consumer.topics=DemoTopic;
rocketmq.consumer.consumeThreadMin=20
rocketmq.consumer.consumeThreadMax=64
#设置一次消费消息的条数,默认为1条
rocketmq.consumer.consumeMessageBatchMaxSize=1
第三步:创建mvaen工程,项目结构图如下:
第四步:编写生产者MQProducerConfiguration 代码:
@SpringBootConfiguration
public class MQProducerConfiguration {
/**
* 发送同一类消息的设置为同一个group,保证唯一,默认不需要设置,rocketmq会使用ip@pid(pid代表jvm名字)作为唯一标示
*/
@Value("${rocketmq.producer.groupName}")
private String groupName;
@Value("${rocketmq.producer.namesrvAddr}")
private String namesrvAddr;
/**
* 消息最大大小,默认4M
*/
@Value("${rocketmq.producer.maxMessageSize}")
private Integer maxMessageSize ;
/**
* 消息发送超时时间,默认3秒
*/
@Value("${rocketmq.producer.sendMsgTimeout}")
private Integer sendMsgTimeout;
/**
* 消息发送失败重试次数,默认2次
*/
@Value("${rocketmq.producer.retryTimesWhenSendFailed}")
private Integer retryTimesWhenSendFailed;
@Bean
public DefaultMQProducer getRocketMQProducer() throws RocketMQException {
if(StringUtils.isEmpty(this.groupName)){
throw new RocketMQException(RocketMQErrorEnum.PARAMM_NULL,"groupName is blank",false);
}
if (StringUtils.isEmpty(this.namesrvAddr)) {
throw new RocketMQException(RocketMQErrorEnum.PARAMM_NULL,"nameServerAddr is blank",false);
}
DefaultMQProducer producer;
producer = new DefaultMQProducer(this.groupName);
producer.setNamesrvAddr(this.namesrvAddr);
producer.setCreateTopicKey("AUTO_CREATE_TOPIC_KEY");
System.out.println(this.groupName+"--"+this.namesrvAddr);
//如果需要同一个jvm中不同的producer往不同的mq集群发送消息,需要设置不同的instanceName
//producer.setInstanceName(instanceName);
if(this.maxMessageSize!=null){
producer.setMaxMessageSize(this.maxMessageSize);
}
if(this.sendMsgTimeout!=null){
producer.setSendMsgTimeout(this.sendMsgTimeout);
}
//如果发送消息失败,设置重试次数,默认为2次
if(this.retryTimesWhenSendFailed!=null){
producer.setRetryTimesWhenSendFailed(this.retryTimesWhenSendFailed);
}
try {
producer.start();
System.out.println(String.format("producer is start ! groupName:[%s],namesrvAddr:[%s]"
, this.groupName, this.namesrvAddr));
} catch (MQClientException e) {
System.out.println(String.format("producer is error {}"
, e.getMessage(),e));
throw new RocketMQException(e);
}
return producer;
}
}
第五步:编写消费者代码,分为两部分,一部分是监听,另一部分是消费者
@Component
public class MQConsumeMsgListenerProcessor implements MessageListenerConcurrently{
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
if(CollectionUtils.isEmpty(msgs)){
System.out.println("接收到的消息为空,不做任何处理");
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
MessageExt messageExt = msgs.get(0);
String msg = new String(messageExt.getBody());
System.out.println("接收到的消息是:"+msg);
if(messageExt.getTopic().equals("你的topic")){
if(messageExt.getTags().equals("你的tag")){
int reconsumeTimes = messageExt.getReconsumeTimes();
if(reconsumeTimes == 3){
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
//TODO 处理对应的业务逻辑
}
}
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
}
@SpringBootConfiguration
public class MQConsumerConfiguration {
public static final Logger logger = LoggerFactory.getLogger(MQConsumerConfiguration.class);
@Value("${rocketmq.consumer.namesrvAddr}")
private String namesrvAddr;
@Value("${rocketmq.consumer.groupName}")
private String groupName;
@Value("${rocketmq.consumer.consumeThreadMin}")
private int consumeThreadMin;
@Value("${rocketmq.consumer.consumeThreadMax}")
private int consumeThreadMax;
@Value("${rocketmq.consumer.topics}")
private String topics;
@Value("${rocketmq.consumer.consumeMessageBatchMaxSize}")
private int consumeMessageBatchMaxSize;
@Autowired
private MQConsumeMsgListenerProcessor mqMessageListenerProcessor;
@Bean
public DefaultMQPushConsumer getRocketMQConsumer() throws RocketMQException{
if (StringUtils.isEmpty(groupName)){
throw new RocketMQException(RocketMQErrorEnum.PARAMM_NULL,"groupName is null !!!",false);
}
if (StringUtils.isEmpty(namesrvAddr)){
throw new RocketMQException(RocketMQErrorEnum.PARAMM_NULL,"namesrvAddr is null !!!",false);
}
if(StringUtils.isEmpty(topics)){
throw new RocketMQException(RocketMQErrorEnum.PARAMM_NULL,"topics is null !!!",false);
}
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer(groupName);
consumer.setNamesrvAddr(namesrvAddr);
consumer.setConsumeThreadMin(consumeThreadMin);
consumer.setConsumeThreadMax(consumeThreadMax);
consumer.registerMessageListener(mqMessageListenerProcessor);
/**
* 设置Consumer第一次启动是从队列头部开始消费还是队列尾部开始消费
* 如果非第一次启动,那么按照上次消费的位置继续消费
*/
consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
/**
* 设置消费模型,集群还是广播,默认为集群
*/
//consumer.setMessageModel(MessageModel.CLUSTERING);
/**
* 设置一次消费消息的条数,默认为1条
*/
consumer.setConsumeMessageBatchMaxSize(consumeMessageBatchMaxSize);
try {
/**
* 设置该消费者订阅的主题和tag,如果是订阅该主题下的所有tag,
* 则tag使用*;如果需要指定订阅该主题下的某些tag,则使用||分割,例如tag1||tag2||tag3
*/
String[] topicTagsArr = topics.split(";");
for (String topicTags : topicTagsArr) {
String[] topicTag = topicTags.split("~");
consumer.subscribe(topicTag[0],topicTag[1]);
}
consumer.start();
System.out.println("consumer is start !!! groupName:{},topics:{},namesrvAddr:{},"+groupName+","+topics+","+namesrvAddr+"");
} catch (Exception e) {
System.out.println("consumer is start error !!! groupName:{},topics:{},namesrvAddr:{},"+groupName+","+topics+","+namesrvAddr+"");
throw new RocketMQException(e);
}
return consumer;
}
}
第六步:一些异常类和常量的封装
public interface ErrorCode extends Serializable {
/**
* 错误码
*
* @return
*/
String getCode();
/**
* 错误信息
*
* @return
*/
String getMsg();
}
public class AppException extends RuntimeException {
private static final long serialVersionUID = 1L;
/**
* 错误编码
*/
protected ErrorCode errCode;
/**
* 错误信息
*/
protected String errMsg;
/**
* 无参构造函数
*/
public AppException() {
super();
}
public AppException(Throwable e) {
super(e);
}
public AppException(ErrorCode errCode, String... errMsg) {
super(errCode.getMsg());
this.errCode = errCode;
setErrMsg(errMsg,true);
}
public AppException(ErrorCode errCode, String errMsg,Boolean isTransfer) {
super(errMsg);
this.errCode = errCode;
setErrMsg(new String[]{errMsg},isTransfer);
}
/**
* 构造函数
*
* @param cause 异常
*/
public AppException(ErrorCode errCode, Throwable cause, String... errMsg) {
super(errCode.getCode() + errCode.getMsg(), cause);
this.errCode = errCode;
setErrMsg(errMsg,true);
}
public ErrorCode getErrCode() {
return errCode;
}
public void setErrCode(ErrorCode errCode) {
this.errCode = errCode;
}
public String getErrMsg() {
return this.errMsg;
}
public void setErrMsg(String[] errMsg,Boolean isTransfer) {
if (null != errMsg &&errMsg.length>0) {
if(errCode.getMsg().contains("%s") && isTransfer){
this.errMsg = String.format(errCode.getMsg(), errMsg);
}else{
StringBuffer sf = new StringBuffer();
for (String msg : errMsg) {
sf.append(msg+";");
}
this.errMsg = sf.toString();
}
}else{
this.errMsg = errCode.getMsg();
}
}
public static void main(String[] args) {
String str = "ERRCode:1004--对象不存在:[%s]";
if (str.contains("%s")){
System.out.println("包含");
}
}
}
public enum RocketMQErrorEnum implements ErrorCode {
/******** 公共 ********/
PARAMM_NULL("MQ_001", "参数为空"),
/******** 生产者 *******/
/******** 消费者 *******/
NOT_FOUND_CONSUMESERVICE("MQ_100", "根据topic和tag没有找到对应的消费服务"),
HANDLE_RESULT_NULL("MQ_101", "消费方法返回值为空"),
CONSUME_FAIL("MQ_102", "消费失败");
private String code;
private String msg;
private RocketMQErrorEnum(String code, String msg) {
this.code = code;
this.msg = msg;
}
@Override
public String getCode() {
return this.code;
}
@Override
public String getMsg() {
return this.msg;
}
}
public class RocketMQException extends AppException {
private static final long serialVersionUID = 1L;
/**
* 无参构造函数
*/
public RocketMQException() {
super();
}
public RocketMQException(Throwable e) {
super(e);
}
public RocketMQException(ErrorCode errorType) {
super(errorType);
}
public RocketMQException(ErrorCode errorCode, String... errMsg) {
super(errorCode, errMsg);
}
/**
* 封装异常
*
* @param errorCode
* @param errMsg
* @param isTransfer
* 是否转换异常信息,如果为false,则直接使用errMsg信息
*/
public RocketMQException(ErrorCode errorCode, String errMsg, Boolean isTransfer) {
super(errorCode, errMsg, isTransfer);
}
public RocketMQException(ErrorCode errCode, Throwable cause, String... errMsg) {
super(errCode, cause, errMsg);
}
}
第七步:创建测试类DefaultProductTest
@SpringBootTest
@RunWith(SpringRunner.class)
public class DefaultProductTest {
/**使用RocketMq的生产者*/
@Autowired
private DefaultMQProducer defaultMQProducer;
@Test
public void send() throws MQClientException, RemotingException, MQBrokerException, InterruptedException{
String msg = "demo msg test";
System.out.println("开始发送消息:"+msg);
Message sendMsg = new Message("DemoTopic","DemoTag",msg.getBytes());
//默认3秒超时
SendResult sendResult = defaultMQProducer.send(sendMsg);
System.out.println("消息发送响应信息:"+sendResult.toString());
}
}
第八步:执行测试
依次启动rocketmq的nameserver、broker,然后执行DefaultProductTest这个类,输出结果如下所示: