在实际业务中经常会遇到消息推送的功能,比如你现在有一条消息需要推送给APP端,但是该条消息又不是立马要推给用户,所以需要把这条数据存放到队列中,等到指定的时间内在推送给用户
在这种业务场景下,就可以使用消息队列了 比如RabbitMQ,ZeroMq,ActiveMq,Kafka等等…今天要学习的是RabbitMQ
安装配置什么的就自行百度吧
导入RabbitMQ.jar包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
yml配置
#RabbitMQ队列服务器配置
spring:
rabbitmq:
host: 10.1.7.102
port: 5672
username: rabbitadmin
password: 123456
#连接超时时间,0表示无限大
connection-timeout: 1000
#消费端配置属性
listener:
#配置为acknowledge模式
acknowledge-mode: auto
#消费者最小数量
concurrency: 8
#消费者最大数量
max-concurrency: 16
retry:
#消费端是否重试
enabled: true
#重试消费的最大次数
max-attempts: 3
#第一次与第二次重试的时间间隔
initial-interval: 10000
#生产端配置属性
template:
retry:
#配置为失败重试
enabled: true
#重试的最大次数
max-attempts: 3
#第一次与第二次重试的时间间隔
initial-interval: 1000
RabbitMQConfig配置类
@Configuration
public class RabbitMQConfig {
/**
* @Description: 建立网管队列
* @Param: []
* @return: org.springframework.amqp.core.Queue
* @Author:
* @Date: 16:32 2019/10/12
*/
@Bean(name = CommonConstrant.RABBIT_NETWORK_QUEUE_NAME)
public Queue netWorkQueue() {
/**
* 第一个参数为队列名称,第二个参数表示消息是否持久化
* 第三个参数表示是否独占队列: 即断开后是否自动删除
* 第四个参数表示当所有消费者客户端连接断开时是否自动删除队列
* 第五个参数表示Map类型的其他参数
*/
return new Queue(CommonConstrant.RABBIT_NETWORK_QUEUE_NAME, true, false, false, null);
}
/**
* @Description: 建立网管直连式交换机
* @Param: []
* @return: org.springframework.amqp.core.DirectExchange
* @Author:
* @Date: 16:31 2019/10/12
*/
@Bean(name = CommonConstrant.RABBIT_NETWORK_EXCHANGE_NAME)
public DirectExchange netWorkExchange() {
/**
* 第一个参数表示交换机名称,第二个参数表示是否持久化,第三个参数表示断开后是否自动删除
*/
return new DirectExchange(CommonConstrant.RABBIT_NETWORK_EXCHANGE_NAME, true, false);
}
/**
* @Description: 配置网管交换机与网管队列绑定
* @Param: [netWorkQueue, netWorkExchange]
* @return: org.springframework.amqp.core.Binding
* @Author:
* @Date: 16:33 2019/10/12
*/
@Bean
public Binding bindNetWorkExchange(@Qualifier(CommonConstrant.RABBIT_NETWORK_QUEUE_NAME) Queue netWorkQueue,
@Qualifier(CommonConstrant.RABBIT_NETWORK_EXCHANGE_NAME) DirectExchange netWorkExchange) {
/**
* 配置绑定:第一个参数队列名称,第二个参数交换机名称,第三个参数Routing key
*/
return BindingBuilder.bind(netWorkQueue).to(netWorkExchange).with(CommonConstrant.RABBIT_NETWORK_EXCHANGE_QUEUE_ROUTINGKEY_NAME);
}
}
交换机四种类型介绍
/** DirectExchange 表示直连式交换机 直连交换机是一种带路由功能的交换机,一个队列会和一个交换机绑定,除此之外再绑定一个routing_key,
* 当消息被发送的时候,需要指定一个binding_key,这个消息被送达交换机的时候,
* 就会被这个交换机送到指定的队列里面去。同样的一个binding_key也是支持应用到多个队列中的
*
* FanoutExchange 表示广播式交换器 扇形交换机会把能接收到的消息全部发送给绑定在自己身上的所有队列
*
* TopicExchange 主题交换机的routing_key需要有一定的规则,交换机和队列的binding_key需要采用*.#.*.....的格式,每个部分用.分开,
* 其中:*表示一个单词,#表示任意数量(零个或多个)单词。
* 假设有一条消息的routing_key为fast.rabbit.white,那么带有这样binding_key的几个队列都会接收这条消息:
* fast..\..white\fast.#\……
*
* HeadersExchange 首部交换机是忽略routing_key的一种路由方式。路由器和交换机路由的规则是通过Headers信息来交换的,
* 这个有点像HTTP的Headers。将一个交换机声明成首部交换机,绑定一个队列的时候,定义一个Hash的数据结构,消息发送的时候,
* 会携带一组hash数据结构的信息,当Hash的内容匹配上的时候,消息就会被写入队列。绑定交换机和队列的时候,Hash结构中要求携带一个键“x-match”,
* 这个键的Value可以是any或者all,这代表消息携带的Hash是需要全部匹配(all),还是仅匹配一个键(any)就可以了。相比直连交换机,
* 首部交换机的优势是匹配的规则不被限定为字符串(string)。
*/
生产者类
@Component
public class RabbitProvider {
private final Logger LOGGER = LoggerFactory.getLogger(this.getClass());
@Autowired
private RabbitTemplate rabbitTemplate;
/**
* @Description:
* @Param: []
* @return: void
* @Author:
* @Date: 16:47 2019/10/12
*/
public void sendNetWorkMessage(){
Map<String, Object> userMessageJson = new HashMap<>();
try {
userMessageJson.put("userId",123456);
userMessageJson.put("Test","test");
/**
* 第一个参数是交换机名称,第二个参数Routing Key,第三个参数是要推送的数据
*/
this.rabbitTemplate.convertAndSend(CommonConstrant.RABBIT_NETWORK_EXCHANGE_NAME,CommonConstrant.RABBIT_NETWORK_EXCHANGE_QUEUE_ROUTINGKEY_NAME, JSONObject.toJSONString(userMessageJson));
LOGGER.info("推送的消息是: "+userMessageJson.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
}
消费者类
@Component
@RabbitListener(queues = CommonConstrant.RABBIT_NETWORK_QUEUE_NAME)
public class BusinessConsumer {
private final static Logger LOGGER = LoggerFactory.getLogger(BusinessConsumer.class);
@RabbitHandler
public void onMessage(String message) {
try {
JSONObject messageJson = JSONObject.parseObject(message, JSONObject.class, Feature.AutoCloseSource);
System.out.println(messageJson);
} catch (BusinessException e) {
LOGGER.error(e.getMessage(), e);
} catch (Exception e) {
LOGGER.error("消息处理异常!!!", e);
}
}
}