rabbitMQ在springboot中使用
开发工具与关键技术:Java springboot
作者:熊俊杰
撰写时间:2021.5.28
使用rabbitMQ之前需要先导入rabbitmq的架包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
然后需要在application.properties配置文件里面配置端口和ip以及rabbitmq的账号和密码:
# rabbitmq配置信息
spring.rabbitmq.host=127.0.0.1
spring.rabbitmq.port=5672
spring.rabbitmq.username=Test
spring.rabbitmq.password=123456
配置完毕就是该怎么使用rabbitmq,rabbitMQ交换机分为四种,分别是:direct、fanout、topic和 headers。
队列分为五种:
1.Hello World 模型,简单的一对一
2.工作队列模型 ,一个生产者将消息分发给多个消费者
3.发布/订阅模型 ,生产者发布消息,多个消费者同时收取
4.路由模型 ,生产者通过关键字发送消息给特定消费者
5.主题模型 ,路由模式基础上,在关键字里加入了通配符
1、简单的一对一的消费模型
创建服务,监听队列,交换器自动消费掉消息队列,也可以改为手动消费
2、手动消费消息队列:
//处理类,,将队列消息的自动确认改成手动确认,相当于开启事务
@Component
public class MyselfReceiver implements ChannelAwareMessageListener {
@Override
public void onMessage(Message message, Channel channel) throws Exception {
long DeliveryTag = message.getMessageProperties().getDeliveryTag();//消息队列的id
try {
String msg = message.toString();
//业务逻辑
String queueName = message.getMessageProperties().getConsumerQueue();//得到这个队列的名称
//System.out.println(queueName);
if("testDirectrabbit".equals(queueName)){//队列名称
//业务逻辑
System.out.println(message.toString());
channel.basicAck(DeliveryTag,true);//将小于DeliveryTag这个id的值都确认队列消息
}
else if ("QueueOne".equals(queueName)){//消息队列名称
//业务逻辑
channel.basicAck(DeliveryTag,true);//将小于DeliveryTag这个id的值都确认队列消息
}
channel.basicAck(DeliveryTag,true);//将小于DeliveryTag这个id的值都确认队列消息
}catch (Exception e){
channel.basicReject(DeliveryTag,true);//出现异常将这条消息队列返回到队列里面,重新等待使用
}
}
}
//指定哪些队列需要手动确认消息,相当于开启事务
@Configuration
public class MessageListenerConfig {
@Autowired
private CachingConnectionFactory cachingConnectionFactory;
@Autowired
private MyselfReceiver myselfReceiver;
@Bean
public SimpleMessageListenerContainer simpleMessageListenerContainer(){
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(cachingConnectionFactory);
container.setConcurrentConsumers(1);//当前消费的队列有几个
container.setMaxConcurrentConsumers(10);//当前消费的最大队列有几个
container.setAcknowledgeMode(AcknowledgeMode.MANUAL);//将默认的自动确认改为手动确认
container.setQueueNames("testDirectrabbit");//设置哪些队列需要手动确认,可以是多个队列,("testDirectrabbit","testDirectrabbit")
container.setMessageListener(myselfReceiver);//设置处理类
return container;
}
}
如果改为手动消费消息队列就不需要自动消费消息队列的服务,因为默认会进入手动消费,
3、工作队列和发布/订阅 很相似
一个交换机发送消息,下面的所有队列都会接收到消息
//扇形交换机,一个交换机同时对应多个队列
@Configuration
public class FanoutRabbitConfig {
//队列1
@Bean
public Queue QueueOne(){
return new Queue("QueueOne",true);
}
//队列2
@Bean
public Queue QueueTwo(){
return new Queue("QueueTwo",true);
}
//队列3
@Bean
public Queue QueueThree(){
return new Queue("QueueThree",true);
}
//交换机
@Bean
FanoutExchange fanoutExchange(){
return new FanoutExchange("fanoutExchange");
}
//绑定交换机
@Bean
Binding BindingExchangeOne(){
return BindingBuilder.bind(QueueOne()).to(fanoutExchange());//直接通过方法名进行调用
}
@Bean
Binding BindingExchangeTwo(){
return BindingBuilder.bind(QueueTwo()).to(fanoutExchange());//直接通过方法名进行调用
}
@Bean
Binding BindingExchangeThree(){
return BindingBuilder.bind(QueueThree()).to(fanoutExchange());//直接通过方法名进行调用
}
}
创建对应的监听消息队列,每一条消息队列都创建一个服务
当交换机发送消息的时候,下面的对应的消息队列都会收到消息
4、路由和主题模式主要用到的是Topic交换机,两个模式的用法基本差不多
//模糊交换机,交换机通过通配符进行模糊接收队列消息
@Configuration
public class TopicRabbitConfig {
public final static String ONE="topic.one";
public final static String TWO="topic.two";
//队列
@Bean
public Queue oneQueue(){
return new Queue(TopicRabbitConfig.ONE);
}
@Bean
public Queue twoQueue(){
return new Queue(TopicRabbitConfig.TWO);
}
//模糊交换机
@Bean
TopicExchange topicExchange(){
return new TopicExchange("topicExchange");
}
//第一种路由 :交换机绑定队列
@Bean
Binding bindingExchangeTopicOne(){
return
BindingBuilder.bind(oneQueue()).to(topicExchange()).with(TopicRabbitConfig.ONE);
}
//第二种主题: 模糊绑定队列,#,代表通配符,包含topic.的队列发送的消息都会被towQueue()队列接收
@Bean
Binding bindingExchangeTopicTow(){
return BindingBuilder.bind(twoQueue()).to(topicExchange()).with("topic.#");
}
}
每个队列都创建一个服务
@Component
@RabbitListener(queues = "topic.one")//监听队列
public class TopicRecever {
@RabbitHandler
public void getMessage(Map map){
//接收到消息,进行业务逻辑处理,比如商品下单
System.out.println("收到消息one:"+map.toString());
}
}
@Component
@RabbitListener(queues = "topic.two")//监听队列
public class TopicTwoRecever {
@RabbitHandler
public void getMessage(Map map){
//接收到消息,进行业务逻辑处理,比如商品下单
System.out.println("收到消息two:"+ map.toString());
}
}
路由:当我们使用路由方式的时候,可以通过关键字来访问对应的交换机,在这里我们声明了两个常量ONE和TWO,常量中对应了我们的队列,我们通过常量来将交换机绑定队列。
主题:当使用主题模式的时候,可以通过模糊绑定队列,‘#’代表通配符,当使用topic.one队列来接收消息时,两个监听队列都会接收到内容,但是当我们使用topic.two的时候我们只有TopicTwoRecever 可以接收到消息。
@RestController
@RequestMapping("/test")
public class test {
//rabbitmq-server -detached
@Autowired
private RabbitTemplate rabbitTemplate;
@RequestMapping("/send")
public String send(){
Map map = new HashMap();
map.put("orderid", UUID.randomUUID());
map.put("goods","衣服");
//"testDirectExchange"交换机,"testDirectRouting"交换机的路由键,map表示传输的类型
rabbitTemplate.convertAndSend("testDirectExchange","testDirectRouting",map);
return "success";
}
@RequestMapping("/sendFanout")
public String sendFanout(){
Map map = new HashMap();
map.put("orderid", UUID.randomUUID());
map.put("goods","鞋子");
//"fanoutExchange"交换机,在这里fanoutExchange不需要绑定队列,map表示传输的类型
rabbitTemplate.convertAndSend("fanoutExchange",null,map);
return "success";
}
@RequestMapping("/sendTopic")
public String sendTopic(){
Map map = new HashMap();
map.put("orderid", UUID.randomUUID());
map.put("goods","帽子");
//"fanoutExchange"交换机,在这里fanoutExchange不需要绑定队列,map表示传输的类型
rabbitTemplate.convertAndSend("topicExchange","topic.one",map);
return "success";
}
}