在windows中使用MQ
rocketmq启动命令
进入到bin目录
1. 启动nameserver
start runserver.cmd
2.启动broker
start mqbroker.cmd -n 127.0.0.1:9876 autoCreateTopicEnable=true
pom
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> <!--Spring cloud alibaba 2.1.1.RELEASE--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>${spring.cloud.alibaba.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.apache.rocketmq</groupId> <artifactId>rocketmq-spring-boot-starter</artifactId> </dependency>
配置文件
rocketmq:
#服务地址
name-server: 127.0.0.1:9876
producer:
group: test_group
test-topic: test_topic
consumer:
# 官方建议:确保同一组中的每个消费者订阅相同的主题。
group-name: test_consumer
test-topic: test_topic
server:
port: 8888
生产者
package com.weget.rocketmq.service.impl;
import com.alibaba.fastjson.JSON;
import com.weget.rocketmq.service.AsyncMessageService;
import com.weget.util.ServletUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
/**
* @作者 ao.lou
* @创建时间 2020/9/17 13:21
* @版本 1.0
* @描述 消费服务实现
*/
@Slf4j
@Service
public class AsyncMessageServiceImpl implements AsyncMessageService {
@Autowired
private RocketMQTemplate template;
@Override
public void sendMessage(String jsonMessage, String topic) {
asyncSendMessage(jsonMessage, topic);
}
private void asyncSendMessage(String message, String topic) {
template.asyncSend(topic, MessageBuilder.withPayload(message).build(), new SendCallback() {
@Override
public void onSuccess(SendResult sendResult) {
log.info("消息发送成功,信息id为{}", sendResult.getMsgId());
}
@Override
public void onException(Throwable throwable) {
log.error("消息发送失败", throwable);
}
});
}
@Override
public ResponseEntity sendMessage(HttpServletRequest request, String topic) {
String requestIp = ServletUtil.getRequestIp(request);
String headerParam = ServletUtil.getHeaderParam(request);
String allRequestParam = ServletUtil.getAllRequestParam(request);
if (StringUtils.isBlank(allRequestParam)) {
log.info("请求体内容为空,不发送到MQ中");
return new ResponseEntity<>("body is null", HttpStatus.BAD_REQUEST);
}
String messageContent = getMessageContent(headerParam, allRequestParam);
log.info("请求IP:{},发送到MQ中的消息内容:{}", requestIp, messageContent);
asyncSendMessage(messageContent, topic);
return new ResponseEntity(HttpStatus.OK);
}
private String getMessageContent(String headerParam, String allRequestParam) {
Map<String, Object> map = new HashMap<>();
map.put("header", headerParam);
map.put("body", allRequestParam);
return JSON.toJSONString(map);
}
}
消费者: 默认集群模式,只会被一个消费掉,将其设置为广播模式,凡订阅者皆可消费
public enum MessageModel {
BROADCASTING("BROADCASTING"),
CLUSTERING("CLUSTERING");
private final String modeCN;
private MessageModel(String modeCN) {
this.modeCN = modeCN;
}
public String getModeCN() {
return this.modeCN;
}
}
@Slf4j
@Component
@RocketMQMessageListener(topic = "${rocketmq.consumer.test-topic}",messageModel = MessageModel.BROADCASTING,
consumerGroup = "${rocketmq.consumer.group-name}")
public class TestListener implements RocketMQListener<String> {
@Override
public void onMessage(String message) {
log.info("获取信息:{}", message);
}
}
测试类:
package com.weget.rocketmq.controller;
import com.weget.rocketmq.service.AsyncMessageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
/**
* @作者 ao.lou
* @创建时间 2020/9/17 14:39
* @版本 1.0
* @描述 测试发送消息
*/
@RestController
public class TestController {
@Autowired
AsyncMessageService asyncMessageService;
@Value("${rocketmq.producer.test-topic}")
private String topic;
@GetMapping("/test")
public void test() {
asyncMessageService.sendMessage("123", topic);
}
@PostMapping("/test")
public ResponseEntity test(HttpServletRequest request) {
return asyncMessageService.sendMessage(request, topic);
}
}
请求
日志信息:
广播模式:
服务A订阅广播
服务B订阅广播
activemq 启动命令
进入bin目录
apache-activemq-5.13.3\bin>activemq start
pom 关键依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-core</artifactId>
<version>5.7.0</version>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-pool</artifactId>
</dependency>
springboot 配置文件
spring:
activemq:
broker-url : tcp://localhost:61616
in-memory: true
pool:
#如果此处设置为true,需要加如下的依赖包,否则会自动配置失败,报JmsMessagingTemplate注入失败
enabled: false
jms:
template:
default-destination: custom-destination
#点对点/订阅模式
pub-sub-domain: true
配置类:设置改属性后,点对点/订阅模式将以myJmsListenerContainerFactory的pubSubDomain属性为准,不是必须的
@Configuration
public class MqConfig {
/**
* @param connectionFactory
* @return
*/
@Bean
JmsListenerContainerFactory<?> myJmsListenerContainerFactory(ConnectionFactory connectionFactory) {
SimpleJmsListenerContainerFactory simpleJmsListenerContainerFactory = new SimpleJmsListenerContainerFactory();
simpleJmsListenerContainerFactory.setConnectionFactory(connectionFactory);
//默认false ,单个消息被某消费者消费后其他不再消费,true订阅广播模式
simpleJmsListenerContainerFactory.setPubSubDomain(true);
return simpleJmsListenerContainerFactory;
}
}
生产者:
package com.jms.service.impl;
import com.jms.service.ProducerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsMessagingTemplate;
import org.springframework.stereotype.Service;
import javax.jms.Destination;
/***
* 生产者
*/
@Service
public class ProducerServiceImpl implements ProducerService {
@Autowired
private JmsMessagingTemplate jmsMessagingTemplate;
@Override
public void sendMessage(Destination destination, final String message) {
jmsMessagingTemplate.convertAndSend(destination, message);
}
}
消费者: 可以复制多个消费者,用来测试点对点/订阅模式
package com.jms.consumer;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;
@Component
public class Consumer {
/**
* 使用JmsListener配置消费者监听的队列,其中text是接收到的消息
* ,containerFactory = "myJmsListenerContainerFactory"
*/
@JmsListener(destination = "mytest.queue")
public void receiveQueue(String text) {
System.out.println("Consumer收到的报文为:" + text);
}
}
测试类:使用时需要注意发送点对点ActiveMQQueue和发布订阅ActiveMQTopic的Destination不一样,且注意配置文件中
jms:
template:
default-destination: custom-destination
#点对点/订阅模式
pub-sub-domain: true
pub-sub-domain的属性设置
package com.jms;
import javax.jms.Destination;
import com.jms.service.ProducerService;
import org.apache.activemq.command.ActiveMQQueue;
import org.apache.activemq.command.ActiveMQTopic;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = MQApplication.class)
public class SpringbootJmsApplicationTest {
@Autowired
private ProducerService producer;
/**
* queue
*
* @throws InterruptedException
*/
@Test
public void test() throws InterruptedException {
/*注意:订阅发布模式要配置
*# 点对点/订阅模式
* pub-sub-domain: false
*/
Destination destination = new ActiveMQQueue("mytest.queue");
for (int i = 0; i < 10; i++) {
producer.sendMessage(destination, "hello !!!" + i);
}
}
/**
* topic
*
* @throws InterruptedException
*/
@Test
public void testTopic() throws InterruptedException {
/*注意: 订阅发布模式要配置
*# 点对点/订阅模式
* pub-sub-domain: true
*/
Destination destination = new ActiveMQTopic("mytest.queue");
for (int i = 0; i < 10; i++) {
producer.sendMessage(destination, "hello !!!" + i);
}
}
}
点对点 测试结果
Consumer收到的报文为:hello !!!0
ConsumerTopic收到:hello !!!1
Consumer收到的报文为:hello !!!2
ConsumerTopic收到:hello !!!3
Consumer收到的报文为:hello !!!4
订阅模式 测试结果
Consumer收到的报文为:hello !!!0
ConsumerTopic收到:hello !!!0
ConsumerTopic收到:hello !!!1
Consumer收到的报文为:hello !!!1
Consumer收到的报文为:hello !!!2
ConsumerTopic收到:hello !!!2
ConsumerTopic收到:hello !!!3
Consumer收到的报文为:hello !!!3