org.springframework.boot
spring-boot-starter-amqp
spring:
rabbitmq:
host: 11.53.56.69
port: 5672
username: scp
password: Passc0de33!
## druid配置
druid:
filters: stat,wall,log4j,config
max-active: 100
initial-size: 1
max-wait: 60000
min-idle: 1
time-between-eviction-runs-millis: 60000
min-evictable-idle-time-millis: 300000
validation-query: select 'x'
test-while-idle: true
test-on-borrow: false
test-on-return: false
pool-prepared-statements: true
max-open-prepared-statements: 50
max-pool-prepared-statement-per-connection-size: 20
package com.config.mq;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.SerializerMessageConverter;
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;
/**
* rabbitMQ config by CHENYB of 2019-07-22
*/
@Configuration
public class RabbitMQConfig {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
/**
* 连接
*/
@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;
@Bean
public ConnectionFactory connectionFactory() {
//rabbitMQ 连接
CachingConnectionFactory connectionFactory = new CachingConnectionFactory(host,port);
connectionFactory.setUsername(username);
connectionFactory.setPassword(password);
connectionFactory.setVirtualHost("/");
connectionFactory.setPublisherConfirms(true);
return connectionFactory;
}
@Bean
@Scope("prototype")//必须是prototype类型,处理rabbitTemplate 对象唯一性
public RabbitTemplate rabbitTemplate() {
//生成模板对象
RabbitTemplate template = new RabbitTemplate(connectionFactory());
template.setMandatory(true);
template.setMessageConverter(new SerializerMessageConverter());
return template;
}
/**
* 针对消费者配置
* 1. 设置交换机类型
* 2. 将队列绑定到交换机
FanoutExchange: 将消息分发到所有的绑定队列,无routingkey的概念
HeadersExchange :通过添加属性key-value匹配
DirectExchange:按照routingkey分发到指定队列
TopicExchange:多关键字匹配
*/
@Bean
public DirectExchange defaultExchangeA() {
return new DirectExchange( MQCoordinate.EXCHANGE_A);
}
/**
* 获取队列A
* @return
*/
@Bean
public Queue queueA() {
return new Queue(MQCoordinate.QUEUE_A, true);
}
/**
* 一个交换机可以绑定多个消息队列,也就是消息通过一个交换机,可以分发到不同的队列当中去。
* 设置多个 , 添加多个binding方法即可
* @return
*/
@Bean
public Binding bindingA() {
return BindingBuilder.bind(queueA()).to(defaultExchangeA()).with( MQCoordinate.ROUTINGKEY_A);
}
}
package com.config.mq;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.support.CorrelationData;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.UUID;
/**
* 消息生成者配置类 by CHENYB of 2019-07-22
*/
public class MsgProducer implements RabbitTemplate.ConfirmCallback {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private RabbitTemplate rabbitTemplate;
@Autowired
public MsgProducer(RabbitTemplate rabbitTemplate) {
this.rabbitTemplate = rabbitTemplate;
// rabbitTemplate.setConfirmCallback(this);
}
public void sendMsg(String content) {
CorrelationData correlationId = new CorrelationData( UUID.randomUUID().toString());
//注意 交换机,路由,队列 定位
// rabbitTemplate.convertAndSend( "exchange","routingKey","content",new CorrelationData() );//结构样例
rabbitTemplate.convertAndSend( MQCoordinate.EXCHANGE_A, MQCoordinate.ROUTINGKEY_A, content, correlationId);
}
@Override
public void confirm(CorrelationData correlationData, boolean b, String s) {
logger.info(" 回调id:" + correlationData);
if (b) {
logger.info("消息成功消费");
} else {
logger.info("消息消费失败:" + s);
}
}
}
//package com.config.mq;
//
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;
//import org.springframework.amqp.rabbit.annotation.RabbitHandler;
//import org.springframework.amqp.rabbit.annotation.RabbitListener;
//import org.springframework.stereotype.Component;
//
///**
// * 这里只做为监听者demo by CHENYB of date 2019-07-22
// */
//@Component
//@RabbitListener(queues = MQCoordinate.QUEUE_A)
//public class MsgReceiver {
//
// private final Logger logger = LoggerFactory.getLogger(this.getClass());
//
// @RabbitHandler
// public void process(String content) {
// logger.info("处理器one接收处理队列A当中的消息: " + content);
// }
//}
package com.config.mq;
/**
* MQ坐标类
* by ChenYb date 2019/7/22
*/
public class MQCoordinate {
/**
* 坐标
*/
public static final String EXCHANGE_A = "sync_A"; //交换机
public static final String ROUTINGKEY_A = "sync_routingKey_A";//路由
public static final String QUEUE_A = "sync_queue_A";//队列
}
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
public void sendMsg (){
MsgProducer msgProducer = new MsgProducer( rabbitTemplate );
msgProducer.sendMsg( "张飞" );
System.out.println("OK!");
}
有了订阅模式做基础,接下来的模式就很好上手,很好理解了 ,主要就是交换机类型,和绑定与其队列的关系;如果需要做交换机持久化
@Bean("EXCHANGE_TOPIC_KAIFENG")//声明
public Exchange EXCHANGE_TOPIC_INFORM(){
//声明了一个Topic类型的交换机,durable是持久化(重启rabbitmq这个交换机不会被自动删除)
return ExchangeBuilder.directExchange("EXCHANGE_TOPIC_KAIFENG").durable(true).build();
}
//广播
public static final String FANOUT_EXCHANGE_NAME = "fanout.exchange.name";
public static final String TEST_QUEUE1_NAME = "test.queue1.name";
public static final String TEST_QUEUE2_NAME = "test.queue2.name";
这里只说一下核心的变动 , 重复的东西这里就不说了
FanoutExchange 只注意返回值,返回值为 FanoutExchange的方法 , FanoutExchange对象为扇形传播,广播模式,交换机切换广播模式;
Queue 返回值为 Queue方法,创建两个(更多)这里只做样例,意味着两个队列;
/**
* 设置交换机类型 扇形(广播)
* @return
*/
@Bean
public FanoutExchange fanoutExchange() {
logger.info("【【【广播交换机实例创建成功】】】");
return new FanoutExchange(MQCoordinate.FANOUT_EXCHANGE_NAME);
}
/*广播队列1*/
@Bean
public Queue queue1() {
return new Queue(MQCoordinate.TEST_QUEUE1_NAME);
}
/*广播队列2*/
@Bean
public Queue queue2() {
return new Queue(MQCoordinate.TEST_QUEUE2_NAME);
}
/**
* 绑定广播队列到交换机
* @return
*/
@Bean
public Binding bingQueue1ToExchange() {
return BindingBuilder.bind(queue1()).to(fanoutExchange());
}
@Bean
public Binding bingQueue2ToExchange() {
return BindingBuilder.bind(queue2()).to(fanoutExchange());
}
/**
* 广播-发送消息
* 说明: routingKey可以指定也可以不指定,这里我们给一个空字符串""
* 空字符串""就可以
*/
public void fanoutSendMsg(Object message) {
logger.info( "【消息发送者】发送消息到fanout交换机,消息内容为: {}", message );
rabbitTemplate.convertAndSend( MQCoordinate.FANOUT_EXCHANGE_NAME, "", message );
}
package com.config.mq;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
/**
* 这里只做为监听者demo
*/
@Component
@RabbitListener(queues = MQCoordinate.TEST_QUEUE1_NAME)
public class MsgReceiver {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@RabbitHandler
public void process(String content) {
logger.info("广播消息-接收处理队列1当中的消息: " + content);
}
}
package com.config.mq;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
/**
* 这里只做为监听者demo
*/
@Component
@RabbitListener(queues = MQCoordinate.TEST_QUEUE2_NAME)
public class MsgReceiver2 {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@RabbitHandler
public void process(String content) {
logger.info("广播消息-接收处理队列2当中的消息: " + content);
}
}
@Test
public void fanoutSendMsg (){
MsgProducer msgProducer = new MsgProducer( rabbitTemplate );
for (int i = 0; i < 100; i++) {
msgProducer.fanoutSendMsg( "下面的朋友可以收到我的第<"+(i+1)+">次问候吗?" );
}
}
配置类: (主要说交换机和binding)
/**
* 创建模糊播-交换机
* @return
*/
@Bean
public TopicExchange topicExchange (){
logger.info("【【【模糊交换机实例创建成功】】】");
return new TopicExchange( MQCoordinate.TOPIC_EXCHANGE_NAME );
}
/**
* 创建两个队列
* @return
*/
@Bean
public Queue topQueue1(){
return new Queue( MQCoordinate.TOPIC_QUEUE1_NAME );
}
@Bean
public Queue topQueue2(){
return new Queue( MQCoordinate.TOPIC_QUEUE2_NAME );
}
@Bean
public Queue topQueue3(){
return new Queue( MQCoordinate.TOPIC_QUEUE3_NAME );
}
/**
* routingkey可以有通配符:'*','#'.
*
* 其中'*'表示匹配一个单词, '#'则表示匹配没有或者多个单词
* @return
*/
@Bean
public Binding topQueue1ToExchange(){
return BindingBuilder.bind( topQueue1() ).to( topicExchange() ).with( MQCoordinate.TOPIC_QUEUE1_NAME );
}
@Bean
public Binding topQueue2ToExchange(){
return BindingBuilder.bind( topQueue2() ).to( topicExchange() ).with( MQCoordinate.TOPIC_QUEUE2_NAME );
}
@Bean
public Binding topQueue3ToExchange(){
return BindingBuilder.bind( topQueue3() ).to( topicExchange() ).with( MQCoordinate.TOPIC_QUEUE3_NAME );
}
坐标类:
//模糊播
public static final String TOPIC_EXCHANGE_NAME = "topic.exchange.name";
public static final String TOPIC_QUEUE1_NAME = "*.weather";
public static final String TOPIC_QUEUE2_NAME = "*.news";
public static final String TOPIC_QUEUE3_NAME = "#";
生产者:
public void topicSendMsg (String message){
logger.info( "【消息发送者】发送消息到topic交换机,消息内容为: {}", message );
rabbitTemplate.convertAndSend( MQCoordinate.TOPIC_EXCHANGE_NAME, MQCoordinate.TOPIC_QUEUE2_NAME, message );
}
消费者:(这里用一个类,处理多个监听消息)
package com.config.mq;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
/**
* 这里只做为监听者demo
*/
@Component
public class MsgReceiver {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@RabbitListener(queues = MQCoordinate.TOPIC_QUEUE1_NAME)
public void process(String content) {
logger.info("模糊播消息-接收处理队列A当中的消息: " + content);
}
@RabbitListener(queues = MQCoordinate.TOPIC_QUEUE2_NAME)
public void process2(String content) {
logger.info("模糊播消息-接收处理队列B当中的消息: " + content);
}
@RabbitListener(queues = MQCoordinate.TOPIC_QUEUE3_NAME)
public void process3(String content) {
logger.info("模糊播消息-接收处理队列C当中的消息: " + content);
}
}
测试代码:
@Test
public void topicSendMsg (){
MsgProducer msgProducer = new MsgProducer( rabbitTemplate );
msgProducer.topicSendMsg1( "黑龙江,多云!" );
msgProducer.topicSendMsg2( "黑龙江,街头古惑仔" );
}
效果:
配置类:(这里只说交换机和Banding)
/**
* 创建headers 交换机
*/
public HeadersExchange headersExchange (){
logger.info("【【【headers交换机实例创建成功】】】");
return new HeadersExchange( MQCoordinate.HEADERS_EXCHANGE_NAME );
}
@Bean
public Binding headers1Binding (){
Map map = new HashMap<>();
map.put("queueName","queueN1");
map.put("bindType","whereAll");
//whereAny表示部分匹配
return BindingBuilder.bind(headersQueue2()).to(headersExchange()).whereAny(map).match();
}
@Bean
public Binding headers2Binding (){
Map map = new HashMap<>();
map.put("queueName","queueN1");
map.put("bindType","whereAll");
// whereAll表示全部匹配
return BindingBuilder.bind(headersQueue1()).to(headersExchange()).whereAll(map).match();
}
坐标:
public static final String HEADERS_EXCHANGE_NAME = "headers.exchange";
public static final String HEADERS_QUEUE_NAME1 = "queueN1";
public static final String HEADERS_QUEUE_NAME2 = "queueN2";
异常忽略:(配置类中需要开启异常忽略,否则会IO异常问题)
@Bean
public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory) {
RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
//设置忽略声明异常
rabbitAdmin.setIgnoreDeclarationExceptions(true);
return rabbitAdmin;
}
测试代码:
@Test
public void headersSendMsg1 (){
MsgProducer msgProducer = new MsgProducer( rabbitTemplate );
/**
* 声明消息 (消息体, 消息属性)
*/
String messageStr = "hello queueN1";
MessageProperties messageProperties = new MessageProperties();
messageProperties.setHeader("queueName","queueN1");
messageProperties.setHeader("bindType","whereAll");
Message message = new Message(messageStr.getBytes(), messageProperties);
msgProducer.headersSendMsg(message);
}
Mr.chenyb 随笔记录,方便学习
201907-19