直联config
package com.csrcb.config;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.annotation.EnableRabbit;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
/**
Broker:它提供一种传输服务,它的角色就是维护一条从生产者到消费者的路线,保证数据能按照指定的方式进行传输,
Exchange:消息交换机,它指定消息按什么规则,路由到哪个队列。
Queue:消息的载体,每个消息都会被投到一个或多个队列。
Binding:绑定,它的作用就是把exchange和queue按照路由规则绑定起来.
Routing Key:路由关键字,exchange根据这个关键字进行消息投递。
vhost:虚拟主机,一个broker里可以有多个vhost,用作不同用户的权限分离。
Producer:消息生产者,就是投递消息的程序.
Consumer:消息消费者,就是接受消息的程序.
Channel:消息通道,在客户端的每个连接里,可建立多个channel.
*/
@Configuration
public class RabbitMqConfig {
@Value("${spring.rabbitmq.host}")
private String host;
@Value("${spring.rabbitmq.port}")
private int port;
@Value("${spring.rabbitmq.username}")
private String username;
@Value("${spring.rabbitmq.password}")
private String password;
@Value("${spring.rabbitmq.virtual-host}")
private String virtualHost;
public static final String EXCHANGE_A = "my-mq-direct_exchange";
public static final String EXCHANGE_B = "my-mq-exchange_B";
public static final String EXCHANGE_C = "my-mq-exchange_C";
public static final String QUEUE_A = "QUEUE_A";
public static final String QUEUE_A_FAIL = "QUEUE_A_FAIL";
public static final String QUEUE_B = "QUEUE_B";
public static final String ROUTINGKEY_A = "spring-boot-routingKey_A";
public static final String ROUTINGKEY_A_FAIL = "spring-boot-routingKey_A_FAIL";
public static final String ROUTINGKEY_B = "spring-boot-routingKey_B";
//建立一个连接容器,类型数据库的连接池
@Bean
public ConnectionFactory connectionFactory() {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory(host,port);
connectionFactory.setUsername(username);
connectionFactory.setPassword(password);
connectionFactory.setVirtualHost(virtualHost);
connectionFactory.setPublisherConfirms(true);//确认机制
// connectionFactory.setPublisherReturns(true);
//发布确认,template要求CachingConnectionFactory的publisherConfirms属性设置为true
return connectionFactory;
}
//RabbitMQ的使用入口
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
//必须是prototype类型
public RabbitTemplate rabbitTemplate() {
RabbitTemplate template = new RabbitTemplate(this.connectionFactory());
template.setMessageConverter(this.jsonMessageConverter());
template.setMandatory(true);
return template;
}
//把交换机,队列,通过路由关键字进行绑定,写在RabbitConfig类当中
/**
* 针对消费者配置
* 1. 设置交换机类型
* 2. 将队列绑定到交换机
FanoutExchange: 将消息分发到所有的绑定队列,无routingkey的概念
HeadersExchange :通过添加属性key-value匹配
DirectExchange:按照routingkey分发到指定队列
TopicExchange:多关键字匹配
*/
@Bean
public DirectExchange testDirectExchange() {
return new DirectExchange(EXCHANGE_A);
}
@Bean
public DirectExchange testDirectExchangeB() {
return new DirectExchange(EXCHANGE_B);
}
@Bean
public DirectExchange testDirectExchangeC() {
return new DirectExchange(QUEUE_B);
}
/**
* 获取队列A
* durable:是否持久化,默认是false,持久化队列:会被存储在磁盘上,当消息代理重启时仍然存在,暂存队列:当前连接有效
* exclusive:默认也是false,只能被当前创建的连接使用,而且当连接关闭后队列即被删除。此参考优先级高于durable
* autoDelete:是否自动删除,当没有生产者或者消费者使用此队列,该队列会自动删除。
* return new Queue("TestDirectQueue",true,true,false);
* 一般设置一下队列的持久化就好,其余两个就是默认false
* @return
*/
@Bean
public Queue queueA() {
return new Queue(QUEUE_A, true); //队列持久
}
@Bean
public Queue queueB() {
return new Queue(QUEUE_B, true); //队列持久
}
@Bean
public Binding bindingB() {
return BindingBuilder.bind(queueB()).to(testDirectExchangeB()).with(ROUTINGKEY_B);
}
@Bean
public Queue queueAFail(){
return new Queue(QUEUE_A_FAIL, true);//队列持久
}
//将队列和交换机绑定, 并设置用于匹配键:spring-boot-routingKey_A
@Bean
public Binding binding() {
return BindingBuilder.bind(queueA()).to(testDirectExchange()).with(ROUTINGKEY_A);
}
@Bean
public Binding bindingAFail() {
return BindingBuilder.bind(queueAFail()).to(testDirectExchange()).with(RabbitMqConfig.ROUTINGKEY_A_FAIL);
}
@Bean
public MessageConverter jsonMessageConverter() {
return new Jackson2JsonMessageConverter();
}
//一个交换机可以绑定多个消息队列,也就是消息通过一个交换机,可以分发到不同的队列当中去。
// /**
// * 获取队列B
// * @return
// */
// @Bean
// public Queue queueB() {
// return new Queue(QUEUE_B, true); //队列持久
// }
// @Bean
// public Binding bindingB(){
// return BindingBuilder.bind(queueB()).to(defaultExchange()).with(ROUTINGKEY_B);
// }
// @Bean
// public CharacterEncodingFilter characterEncodingFilter() {
// CharacterEncodingFilter filter = new CharacterEncodingFilter();
// filter.setEncoding("UTF-8");
// filter.setForceEncoding(true);
// return filter;
// }
}
主题config
package com.csrcb.config;
import com.csrcb.common.Constants;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Created by michael on 2019-04-16.
*/
@Configuration
public class RabbitMQOfTopicConfig {
@Bean
public Queue firstQueue() {
return new Queue(Constants.Topic.MAN);
}
@Bean
public Queue secondQueue() {
return new Queue(Constants.Topic.WOMAN);
}
@Bean
public TopicExchange exchange() {
return new TopicExchange(Constants.Topic.EXCHANGE);
}
/**
* 将firstQueue和topicExchange绑定,而且绑定的键值为 topic.man
* 这样只要是消息携带的路由键是 topic.man, 才会分发到该队列
*
* @return
*/
@Bean
public Binding bindingExchangeMessage() {
return BindingBuilder.bind(firstQueue()).to(exchange()).with(Constants.Topic.MAN);
}
/**
* 将secondQueue和topicExchange绑定,而且绑定的键值为用上通配路由键规则topic.#
* 这样只要是消息携带的路由键是以topic.开头,都会分发到该队列
*
* @return
*/
@Bean
public Binding bindingExchangeMessage2() {
return BindingBuilder.bind(secondQueue()).to(exchange()).with(Constants.Topic.ROUTING_KEY);
}
}
扇形config
package com.csrcb.config; import com.csrcb.common.Constants; import org.springframework.amqp.core.Binding; import org.springframework.amqp.core.BindingBuilder; import org.springframework.amqp.core.FanoutExchange; import org.springframework.amqp.core.Queue; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * Created by michael on 2019-04-19. */ @Configuration public class RabbitMQOfFanoutConfig { /** * 创建三个队列 :fanout.A fanout.B fanout.C * 将三个队列都绑定在交换机 fanoutExchange 上 * 因为是扇型交换机, 路由键无需配置, 配置也不起作用 */ @Bean public Queue queueAA() { return new Queue(Constants.Fanout.QUEUE_A); } @Bean public Queue queueBB() { return new Queue(Constants.Fanout.QUEUE_B); } @Bean public Queue queueCC() { return new Queue(Constants.Fanout.QUEUE_C); } @Bean public FanoutExchange fanoutExchange() { return new FanoutExchange(Constants.Fanout.EXCHANGE); } @Bean public Binding bindingExchangeA() { return BindingBuilder.bind(queueAA()).to(fanoutExchange()); } @Bean public Binding bindingExchangeB() { return BindingBuilder.bind(queueBB()).to(fanoutExchange()); } @Bean public Binding bindingExchangeC() { return BindingBuilder.bind(queueCC()).to(fanoutExchange()); } }
静态变量
package com.csrcb.common;
/**
* 常量
* <p>
* Created by michael on 2019-04-16.
*/
public class Constants {
public static final int MESSAGE_NUMBER = 3;// 消息数量
public static String DELAY_QUEUE="delayqueue";
public static String IMMEDIATE_QUEUE="immediateqqueue";
public static String IMMEDIATE_EXCHANGE="immediatequeue";
public static String IMMEDIATE_ROUTING_KEY="immediaterouring";
public static String DELAY_ROUTING_KEY="delayrouting";
public static String DEAD_LETTER_EXCHANGE="dead_letter_exchange";
/**
* 直接
*/
public interface Direct {
// 交换机名称
String EXCHANGE = "TestDirectExchange";
String EXCHANGE_SPECIAL = "specialDirectExchange";
// 队列名称
String QUEUE = "TestDirectQueue";
// 绑定「队列」与「交换机」名称
String ROUTING_KEY = "TestDirectRouting";
}
/**
* 主题
*/
public interface Topic {
// 交换机名称
String EXCHANGE = "TestTopicExchange";
// 绑定键
String MAN = "topic.man";
String WOMAN = "topic.woman";
// 绑定「队列」与「交换机」名称
String ROUTING_KEY = "topic.#";
}
/**
* 扇形
*/
public interface Fanout {
// 交换机名称
String EXCHANGE = "TestFanoutExchange";
// 队列名称
String QUEUE_A = "fanout.A";
String QUEUE_B = "fanout.B";
String QUEUE_C = "fanout.C";
}
}
生产者controler
package com.csrcb.controller;
import com.csrcb.common.Constants;
import com.csrcb.config.RabbitMqConfig;
import com.csrcb.service.QueueMessageService;
import com.sun.jmx.snmp.Timestamp;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Stream;
/**
* @Classname ProvoderSend
* @Description 生产者路由
* @Date 2020/8/4 17:24
* @Created by gangye
*/
@RestController
@RequestMapping(value = "/provider")
@Slf4j
public class ProvoderSend {
@Autowired
private QueueMessageService queueMessageService;
@PostMapping("/sendA")
public String sendMessage() {
try {
Map<String, Object> messageMap = new HashMap<>();
messageMap.put("messageId", UUID.randomUUID().toString());
messageMap.put("messageData", "测试信息");
messageMap.put("createTime", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
queueMessageService.send(messageMap, RabbitMqConfig.EXCHANGE_A, RabbitMqConfig.ROUTINGKEY_A);
return "success";
} catch (Exception e) {
log.error("" + e);
return "error";
}
}
@PostMapping("/sendB")
public String sendMessageB() {
try {
Map<String, Object> messageMap = new HashMap<>();
messageMap.put("messageId", UUID.randomUUID().toString());
messageMap.put("messageData", "测试信息");
messageMap.put("createTime", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
queueMessageService.send(messageMap, RabbitMqConfig.EXCHANGE_B, RabbitMqConfig.ROUTINGKEY_B);
return "success";
} catch (Exception e) {
log.error("" + e);
return "error";
}
}
/**
* topic
*/
@PostMapping("/sendtopicman")
public List<Map<String, Object>> sendMessageForMan() {
List<Map<String, Object>> mapList = new ArrayList<>();
Stream.iterate(0, i -> i + 1).limit(Constants.MESSAGE_NUMBER).forEach(i -> {
String msgId = String.valueOf(UUID.randomUUID());
String msgData = "hello, I come from topic exchange「man」.";
String createTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
Map<String, Object> map = new HashMap<>();
map.put("msgId", msgId);
map.put("msgData", msgData);
map.put("createTime", createTime);
queueMessageService.convertAndSend(Constants.Topic.EXCHANGE, Constants.Topic.MAN, map);
mapList.add(map);
});
return mapList;
}
@PostMapping("/sendtopicwoman")
public List<Map<String, Object>> sendMessageForWoman() {
List<Map<String, Object>> mapList = new ArrayList<>();
Stream.iterate(0, i -> i + 1).limit(Constants.MESSAGE_NUMBER).forEach(i -> {
String msgId = String.valueOf(UUID.randomUUID());
String msgData = "hello, I come from topic exchange「woman」.";
String createTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
Map<String, Object> map = new HashMap<>();
map.put("msgId", msgId);
map.put("msgData", msgData);
map.put("createTime", createTime);
queueMessageService.convertAndSend(Constants.Topic.EXCHANGE, Constants.Topic.WOMAN, map);
mapList.add(map);
});
return mapList;
}
@PostMapping("/sendfanout")
public Map<String, Object> sendMessagefanout() {
String msgId = String.valueOf(UUID.randomUUID());
String msgData = "message: test Fanout Message ";
String createTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
Map<String, Object> map = new HashMap<>();
map.put("msgId", msgId);
map.put("msgData", msgData);
map.put("createTime", createTime);
queueMessageService.convertAndSend(Constants.Fanout.EXCHANGE, null, map);
return map;
}
@PostMapping("/senddeadqueue")
public void sendMessagefanout11111() {
this.queueMessageService.senddelayqueue("fa song si xin dui lie",20000l);
}
}
package com.csrcb.service.impl;
import com.csrcb.common.Constants;
import com.csrcb.service.QueueMessageService;
import com.sun.jmx.snmp.Timestamp;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Map;
import java.util.UUID;
/**
* @Classname QueueMessageServiceImpl
* @Date 2020/8/5 15:55
* @Created by gangye
*/
@Service
@Slf4j
public class QueueMessageServiceImpl implements QueueMessageService {
//由于配置类RabbitMqConfig配置类中的rabbitTemplate的scope属性设置为ConfigurableBeanFactory.SCOPE_PROTOTYPE
private RabbitTemplate rabbitTemplate;
@Autowired
public QueueMessageServiceImpl(RabbitTemplate rabbitTemplate){
this.rabbitTemplate = rabbitTemplate;
//设置回调为当前类对象
rabbitTemplate.setConfirmCallback(this);
}
@Override
public void send(Object message, String exchange, String queueRoutingKey) throws Exception {
//构建回调id为uuid
String callBackId = UUID.randomUUID().toString();
CorrelationData correlationId = new CorrelationData(callBackId);
log.info("开始发送消息内容:{}",message.toString());
//发送消息到消息队列
rabbitTemplate.convertAndSend(exchange, queueRoutingKey, message, correlationId);
log.info("发送定制的回调id:{}",callBackId);
}
@Override
public void convertAndSend(String exchange, String man, Map<String, Object> map) {
//构建回调id为uuid
String callBackId = UUID.randomUUID().toString();
CorrelationData correlationId = new CorrelationData(callBackId);
rabbitTemplate.convertAndSend(exchange, man, map,correlationId);
log.info("发送定制的回调id:{}",callBackId);
}
public void senddelayqueue(String user,Long time) {
log.info("消息已经发送,时间为:{}",new Timestamp(System.currentTimeMillis()));
String callBackId = UUID.randomUUID().toString();
CorrelationData correlationId = new CorrelationData(callBackId);
this.rabbitTemplate.convertAndSend(
Constants.DEAD_LETTER_EXCHANGE,
// routingKey
Constants.DELAY_ROUTING_KEY,
user,
message -> {
// 设置延迟毫秒值
message.getMessageProperties().setExpiration(String.valueOf(time));
return message;
},correlationId);
}
/**
* 消息回调确认方法
* @param correlationData 请求数据对象
* @param ack 是否发送成功
* @param s
*/
@Override
public void confirm(CorrelationData correlationData, boolean ack, String s) {
log.info(" 回调id:" + correlationData.getId());
if (ack) {
log.info("消息发送成功");
} else {
log.info("消息发送失败:" + s);
}
}
}
消费者处理消息
package com.csrcb.service; import com.csrcb.common.Constants; import com.csrcb.config.RabbitMqConfig; import lombok.extern.slf4j.Slf4j; import org.springframework.amqp.core.Message; import org.springframework.amqp.rabbit.annotation.RabbitHandler; import org.springframework.amqp.rabbit.annotation.RabbitListener; import org.springframework.stereotype.Component; import java.util.Map; import static com.csrcb.common.Constants.Topic.MAN; import static com.csrcb.common.Constants.Topic.WOMAN; /** * @Classname ConsumerService * @Date 2020/8/7 14:36 * @Created by gangye */ @Component @Slf4j public class ConsumerService { @RabbitListener(queues = RabbitMqConfig.QUEUE_A) @RabbitHandler public void consumeMessage(Message message){ log.info("收到的消息:{}",message); } @RabbitListener(queues = RabbitMqConfig.QUEUE_B) @RabbitHandler public void consumeMessageC(Message message){ log.info("收到的消息B:{}",message); } @RabbitListener(queues = WOMAN) @RabbitHandler public void consumeMessaged(Message message){ log.info("收到的消息WOMAN:{}",message); } @RabbitListener(queues = MAN) @RabbitHandler public void consumeMessageMan(Message message){ log.info("收到的消息MAN:{}",message); } @RabbitListener(queues = Constants.Fanout.QUEUE_A) @RabbitHandler public void consumeMessageA(Message message){ log.info("收到的消息fouantA:{}",message); } @RabbitListener(queues = Constants.Fanout.QUEUE_B) @RabbitHandler public void consumeMessageB(Message message){ log.info("收到的消息fouantB:{}",message); } @RabbitListener(queues = Constants.Fanout.QUEUE_C) @RabbitHandler public void consumeMessageC1(Message message){ log.info("收到的消息fouantC:{}",message); } @RabbitListener(queues = "immediateqqueue") @RabbitHandler public void consumeMessagedelaymessage(Message message){ log.info("收到的消息fouantC:{}",message); } }