Java 简单操作 RabbitMq
Java项目的开发过程中使用到了 RabbitMq,因业务逻辑代码封装比较多,这里简单写一个 Demo
首先 pom.xml 文件引入 rabbitMq 依赖。 当然也可自行查找合适的版本:spring-boot-starter-amqp
<dependencies>
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
...
</dependencies>
在 application.yml 或 application.properties 文件配置 rabbitMq的数据源,这里以 yml 文件举例:
spring:
rabbitmq:
#账号
username: guest
#密码
password: guest
#地址
addresses: localhost:5672
#连接超时时间(秒)
connection-timeout: 3
定义三个常量:交换机,路由key,队列名
package com.demo.www.constant;
/**
* rabbitMq 常量配置
* @author AnYuan
*/
public interface RabbitMqConstant {
String USER_EXCHANGE = "user_exchange";
String USER_ROUTING_KEY = "user_routing_key";
String USER_QUEUE = "user_queue";
}
这里创建一个队列配置初始化类: UserQueueConfig 。项目启动时会同时创建 交换机和队列,如该交换机或队列存在则不会创建。
在提测或环境移植时,可减少手动或忘记创建带来的麻烦。
如果不想交换机和队列通过 routing_key 绑定在一起,可以将常量 USER_ROUTING_KEY 的值设为 "" (空字符串)。
package com.demo.www.rabbitmq.config; import com.demo.www.constant.RabbitMqConstant; import lombok.extern.slf4j.Slf4j; import org.springframework.amqp.core.*; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * 初始化 交换机和队列,并将队列绑定在交换机上 * @author AnYuan */ @Configuration @Slf4j public class UserQueueConfig { @Bean public Queue userMassageQueue() { log.info("userMassageQueue init"); return new Queue(RabbitMqConstant.USER_QUEUE); } @Bean public DirectExchange userMassageExchange() { log.info("userMassageExchange init"); return new DirectExchange(RabbitMqConstant.USER_EXCHANGE); } @Bean public Binding queueBindingExchange() { log.info("queueBindingExchange init"); return BindingBuilder.bind(userMassageQueue()) .to(userMassageExchange()) .with(RabbitMqConstant.USER_ROUTING_KEY); }
}
一个接口类 RabbitMqService:
package com.demo.www.service;
/**
* rabbiMq 服务接口
* @author AnYuan
*/
public interface RabbitMqService {
/**
* 统一发送mq
*
* @param exchange 交换机
* @param routingKey 路由key
* @param data 数据
*/
void send(String exchange, String routingKey, Object data);
}
一个实现类 RabbitMqServiceImpl:
package com.demo.www.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.demo.www.service.RabbitMqService;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* rabbitmq服务
* @author AnYuan
*/
@Service
public class RabbitMqServiceImpl implements RabbitMqService {
@Autowired
private RabbitTemplate rabbitTemplate;
@Override
public void send(String exchange, String routingKey, Object data) {
rabbitTemplate.convertAndSend(exchange, routingKey, JSONObject.toJSONString(data));
}
}
到此已经能执行消息的发送操作了,写一个测试类跑一下 RabbitMqServiceImplTest :
package com.demo.www.service.impl;
import com.demo.www.constant.RabbitMqConstant;
import com.demo.www.service.RabbitMqService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.HashMap;
import java.util.Map;
@SpringBootTest
class RabbitMqServiceImplTest {
@Autowired
private RabbitMqService rabbitMqService;
@Test
public void sendTest() {
Map<String,Object> user = new HashMap<>();
user.put("name", "张三");
user.put("age", 18);
user.put("course", "Java RabbitMq");
rabbitMqService.send(RabbitMqConstant.USER_EXCHANGE, RabbitMqConstant.USER_ROUTING_KEY, user);
}
}
在 RabbitMq 后台可以看到已经创建了:user_exchange 和 user_queue ,且两者有绑定关系,队列里面也接收到的 json 数据。
最后写一个消费者 UserConsumer, 加入 Component 注释后,项目启动时即可自动开始消费。
消息可在发送时,使用构建好的实体类或DTO,消费时直接解析成生产时的实体类或DTO更加方便,再做相应的逻辑操作。
package com.demo.www.rabbitmq.consumers;
import com.alibaba.fastjson.JSONObject;
import com.demo.www.constant.RabbitMqConstant;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
* rabbitMq 消费者
* @author AnYuan
*/
@Component
@Slf4j
public class UserConsumer {
@RabbitListener(bindings = @QueueBinding(
value = @Queue(value = RabbitMqConstant.USER_QUEUE, durable = "true"),
exchange = @Exchange(value = RabbitMqConstant.USER_EXCHANGE)
))
public void onMassageUser(Message message) {
log.info("-------开始消费-------");
Map map = JSONObject.parseObject(new String(message.getBody()), Map.class);
log.info("姓名:{},年龄:{}, 课程:{}", map.get("name"), map.get("age"), map.get("course"));
log.info("-------消费完成-------");
}
}
项目启动后,可以看到在控制台输出
队列一般用在功能之间的解耦或跨服务间的消息传输,及时性很高,如遇到消费者服务异常后,消息会堆积起来,等消费者服务正常后,消息会按照顺序被依次消费掉。
要保证消息的正确投递,可了解 RabbitMq 确认模式。