前言
安装教程 深入浅出RocketMQ安装和部署
快速上手
1.添加依赖
第一个是原生依赖,第二个是spring-boot-starter,这里我们添加第二个依赖。
<!-- https://mvnrepository.com/artifact/org.apache.rocketmq/rocketmq-client -->
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>4.9.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.rocketmq/rocketmq-spring-boot-starter -->
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
在rocketmq-spring-boot-starter中已经包含rocketmq-client依赖

2.配置文件properties
//1
rocketmq.name-server=127.0.0.1:9876
//2
rocketmq.producer.group=provider
生产者配置两条,消费者只需要配置第一条。生产者缺失第二条会报错,错误原因后面会分析。
3.实现消费者
写一个消费消息的实现类,这里我们接受消息来删除Redis中的一个key。
@Service
@RocketMQMessageListener(consumerGroup = RedisKeyListener.GROUP,
topic = RedisKeyListener.TOPIC,
consumeMode = ConsumeMode.ORDERLY)
public class RedisKeyListener implements RocketMQListener<String> {
public static final String GROUP = "redis_group";
public static final String TOPIC = "redis_topic";
private static final Logger logger = LoggerFactory.getLogger(RedisKeyListener.class);
@Autowired
StringRedisTemplate stringRedisTemplate;
@Override
public void onMessage(String key) {
logger.info("redis consumer work for key : {} ", key);
stringRedisTemplate.delete(key);
}
}
可以通过注解中的nameServer去覆盖配置文件中的值。
4.实现发送者
写一个简单的生产者
@RequestMapping("redis")
@RestController
public class RedisKeyController {
private static final Logger logger = LoggerFactory.getLogger(RedisKeyController.class);
@Autowired
RocketMQTemplate template;
@Autowired
StringRedisTemplate stringRedisTemplate;
@GetMapping("put")
public void putKey(String key, String value) {
stringRedisTemplate.opsForValue().set(key, value);
}
@GetMapping("delete")
public void delete(String key) {
logger.info("key : {} is send to MQ ", key);
try {
template.convertAndSend(RedisConstant.TOPIC, key);
} catch (MessagingException e) {
e.printStackTrace();
}
}
}
控制台输出
c.e.r.s.b.p.c.RedisKeyController : key : 1 is send to MQ
c.e.r.s.b.c.consumer.RedisKeyListener : redis consumer work for key : 1
7.可视化界面效果图

详情

点击重复消费,后台日志会出现两条记录。
c.e.r.s.b.c.consumer.RedisKeyListener : redis consumer work for key : 1
c.e.r.s.b.c.consumer.RedisKeyListener : redis consumer work for key : 1
这样我们就已经完成了一个简单的消息收发的过程。
进阶
RocketMQAutoConfiguration中的After和Before
这几个配置类谁先谁后?
@AutoConfigureAfter({
MessageConverterConfiguration.class})
@AutoConfigureBefore({
RocketMQTransactionConfiguration.class})
MessageConverterConfiguration -> RocketMQAutoConfiguration -> RocketMQTransactionConfiguration,
after和before注解在自定义starter中已经分析过,这里不再赘述。
rocketmq.producer.group缺失报错原因分析
之前我们在配置生产者的时候,如果将注释1下面的代码去掉会导致一个报错。
rocketmq:
name-server: ip:端口
//1
producer:
group: rocketMQ
报错提示
Field template in com.example.rocketmqspringboot.controller.MessageSendController required a bean of type 'org.apache.rocketmq.spring.core.RocketMQTemplate' that could not be found.
The injection point has the following annotations:
- @org.springframework.beans.factory.annotation.Autowired(required=true)
根据提示可知,容器中没有RocketMQTemplate,我们找到自动配置类 RocketMQAutoConfiguration ,搜索RocketMQTemplate 后找到这么一段代码
@Bean(destroyMethod = "destroy")
@Conditional(ProducerOrConsumerPropertyCondition.class)
@ConditionalOnMissingBean(name = ROCKETMQ_TEMPLATE_DEFAULT_GLOBAL_NAME)
public RocketMQTemplate rocketMQTemplate(RocketMQMessageConverter rocketMQMessageConverter) {
RocketMQTemplate rocketMQTemplate = new RocketMQTemplate();
if (applicationContext.containsBean(PRODUCER_BEAN_NAME)) {
rocketMQTemplate.setProducer((DefaultMQProducer) applicationContext.getBean(PRODUCER_BEAN_NAME));
}
if (applicationContext.containsBean(CONSUMER_BEAN_NAME)) {
rocketMQTemplate.setConsumer((DefaultLitePullConsumer) applicationContext.getBean(CONSUMER_BEAN_NAME));
}
rocketMQTemplate.setMessageConverter(rocketMQMessageConverter.getMessageConverter());
return rocketMQTemplate;
}
由于代码不会返回null,说明能进到这段代码,RocketMQTemplate 一定会被创建,接下来关注这两个条件注解。
ConditionalOnMissingBean是容器没有name=rocketMQTemplate时候为true,所以问题来自@Conditional
@Conditional(ProducerOrConsumerPropertyCondition.class)
ProducerOrConsumerPropertyCondition 源码如下
static class ProducerOrConsumerPropertyCondition extends AnyNestedCondition {
public ProducerOrConsumerPropertyCondition() {
super(ConfigurationPhase.REGISTER_BEAN);
}
@ConditionalOnBean(DefaultMQProducer.class)
static class DefaultMQProducerExistsCondition {
}
@ConditionalOnBean(DefaultLitePullConsumer.class)
static class DefaultLitePullConsumerExistsCondition {
}
}
AnyNestedCondition
Any:任何、任意,Nested:嵌套,Condition: 条件
Can be used to create composite conditions. 可用于创建复合条件
在ProducerOrConsumerPropertyCondition 这个条件中,DefaultMQProducer和DefaultLitePullConsumer同时返回true,AnyNestedCondition 才会为真,相当于 && 。可以理解为下面这种形式。
@ConditionalOnBean(DefaultMQProducer.class)
@ConditionalOnBean(DefaultLitePullConsumer.class)
如果这么拆分会产生注解重复问题,所

本文围绕RocketMQ展开,先介绍快速上手步骤,包括添加依赖、配置文件、实现消费者和发送者等,完成简单消息收发。接着进入进阶部分,分析RocketMQAutoConfiguration配置顺序、producer.group缺失报错原因,还探讨消费消息策略、注解监听队列、发送顺序消息等内容及相关问题。
最低0.47元/天 解锁文章
669

被折叠的 条评论
为什么被折叠?



