RabbitMQ入门(三):交换器模式实战详解

RabbitMQ交换器分类:

  1. direct交换器(默认交换器)非常的简单,如果路由键匹配的话,消息就投递到相应的队列
  2. fanout交换器——发布/订阅模式,一个发布者,多个消费者,交换器会把一个消息发布到绑定到此交换器的所有队列
  3. topic交换器——匹配订阅模式,和fanout类似,但是可以更灵活的匹配队列,使用* 或者#进行规则匹配
  4. headers交换器——匹配AMQP消息的header而非路由键,用到较少,可以稍加了解

在了解RabbitMQ交换器之后,我们来根据官方文档把所有的交换器实现一次
一、创建SpringBoot项目,整合RabbitMQ
引入pom

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
 </dependency>

二、在配置文件中写入RabbitMQ交换器配置信息

#--------------------MQ配置--------------------
spring.rabbitmq.host=127.0.0.1
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
#消息发送确认回调
spring.rabbitmq.publisher-confirms=true
mq.env=local
#--------------------并发量的配置--------------------
# 并发消费者的初始化值
spring.rabbitmq.listener.concurrency=10 
# 并发消费者的最大值      
spring.rabbitmq.listener.max-concurrency=20  
# 每个消费者每次监听时可拉取处理的消息数量 
spring.rabbitmq.listener.prefetch=5 

#--------------------用户操作日志消息模型配置  direct模式--------------------
log.user.direct.queue=${mq.env}.log.user.direct.queue
log.user.direct.exchange=${mq.env}.log.user.direct.exchange
log.user.direct.routing.key=${mq.env}.log.user.direct.routing.key

#--------------------用户操作日志消息模型配置  fanout模式 不需要routing.key--------------------
log.user.fanout.queue1=${mq.env}.log.user.fanout.queue1
log.user.fanout.queue2=${mq.env}.log.user.fanout.queue2
log.user.fanout.exchange=${mq.env}.log.user.fanout.exchange

#--------------------用户操作日志消息模型配置  topic模式 --------------------
log.user.topic.exchange=${mq.env}.log.user.topic.exchange
#队列名
log.user.topic.queue=${mq.env}.log.user.topic.queue
#队列匹配规则
log.user.topic.queue.routing.key=#  
#测试key值
#不可以绑定到队列
log.user.topic.routing.key1=${mq.env}.log.file.topic.routing.key
#可绑定到队列
log.user.topic.routing.key2=${mq.env}.log.user.topic.routing.key

#--------------------用户操作日志消息模型配置  headers模式 --------------------
log.user.headers.exchange=${mq.env}.log.user.headers.exchange
log.user.headers.queue=${mq.env}.log.user.headers.queue

三、创建配置类,在配置类中写入所有的RabbitMQ交换器,供测试接口使用

@Configuration
public class MQConfig {
	private static final Logger log = LoggerFactory.getLogger(MQConfig.class);

	@Autowired
	private Environment env;

	@Autowired
	private CachingConnectionFactory connectionFactory;

	@Autowired
	private SimpleRabbitListenerContainerFactoryConfigurer factoryConfigurer;

	/**
	 * 单一消费者
	 * 
	 * @return
	 */
	@Bean(name = "singleListenerContainer")
	public SimpleRabbitListenerContainerFactory listenerContainer() {
		SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
		factory.setConnectionFactory(connectionFactory);
		factory.setMessageConverter(new Jackson2JsonMessageConverter());
		factory.setConcurrentConsumers(1);
		factory.setMaxConcurrentConsumers(1);
		factory.setPrefetchCount(1);
		factory.setTxSize(1);
		factory.setAcknowledgeMode(AcknowledgeMode.AUTO);
		return factory;
	}

	/**
	 * 多个消费者
	 * 
	 * @return
	 */
	@Bean(name = "multiListenerContainer")
	public SimpleRabbitListenerContainerFactory multiListenerContainer() {
		SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
		factoryConfigurer.configure(factory, connectionFactory);
		factory.setMessageConverter(new Jackson2JsonMessageConverter());
		factory.setAcknowledgeMode(AcknowledgeMode.NONE);
		factory.setConcurrentConsumers(env.getProperty("spring.rabbitmq.listener.concurrency", int.class));
		factory.setMaxConcurrentConsumers(env.getProperty("spring.rabbitmq.listener.max-concurrency", int.class));
		factory.setPrefetchCount(env.getProperty("spring.rabbitmq.listener.prefetch", int.class));
		return factory;
	}

	@Bean
	@Scope("prototype")
	public RabbitTemplate rabbitTemplate() {
		connectionFactory.setPublisherConfirms(true);
		connectionFactory.setPublisherReturns(true);
		RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
		rabbitTemplate.setMandatory(true);
		rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
			//confirm此方法会在消息发送MQ之后自动调用
			@Override
			public void confirm(CorrelationData correlationData, boolean ack, String cause) {
				log.info("消息发送成功:correlationData({}),ack({}),cause({})", correlationData, ack, cause);
			}
		});
		rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
			//returnedMessage此方法会在消息发送MQ失败之后之后自动调用
			@Override
			public void returnedMessage(Message message, int replyCode, String replyText, String exchange,
					String routingKey) {
				log.info("消息丢失:exchange({}),route({}),replyCode({}),replyText({}),message:{}", exchange, routingKey,
						replyCode, replyText, message);
			}
		});
		return rabbitTemplate;
	}
	
	//TODO 用户操作日志消息模型  direct模式
	/**
	 * 定义队列 并做持久化处理 
	 * @return
	 */
	@Bean(name = "logUserQueue")
	public Queue logUserQueue() {
		return new Queue(env.getProperty("log.user.direct.queue"),true);
	}
	/**
	 * 定义交换器 
	 * true:持久化处理 
	 * false:不进行自动删除
	 * @return
	 */
	@Bean
	public DirectExchange logUserExchange() {
		return new DirectExchange(env.getProperty("log.user.direct.exchange"),true,false);
	}
	//路由
	@Bean
	public Binding logUserBinding() {
		//链式写法: 用指定的路由键将队列绑定到交换机
		return BindingBuilder.bind(logUserQueue())
				.to(logUserExchange())
				.with(env.getProperty("log.user.direct.routing.key"));
	}
	
	//TODO 用户操作日志消息模型  Fanout模式
	/**
	 * 定义交换器 
	 * @return
	 */
	@Bean
	public FanoutExchange fanoutExchange() {
		log.info("创建FanoutExchange>>>>>>>>>>>>>>>>>>>>>>>>>>>成功");
		return new FanoutExchange(env.getProperty("log.user.fanout.exchange"),true,false);
	}
	
	/**
     * 测试队列一
     *
     * @return 队列实例
     */
    @Bean
    public Queue queue1() {
        log.info("【【【测试队列一实例创建成功】】】");
        return new Queue(env.getProperty("log.user.fanout.queue1"));
    }
 
    /**
     * 测试队列二
     *
     * @return 队列实例
     */
    @Bean
    public Queue queue2() {
        log.info("【【【测试队列二实例创建成功】】】");
        return new Queue(env.getProperty("log.user.fanout.queue2"));
    }
 
    /**
     * 绑定队列一到交换机
     *
     * @return 绑定对象
     */
    @Bean
    public Binding bingQueue1ToExchange() {
        log.info("【【【绑定队列一到交换机成功】】】");
        return BindingBuilder.bind(queue1()).to(fanoutExchange());
    }
 
    /**
     * 绑定队列二到交换机
     *
     * @return 绑定对象
     */
    @Bean
    public Binding bingQueue2ToExchange() {
        log.info("【【【绑定队列二到交换机成功】】】");
        return BindingBuilder.bind(queue2()).to(fanoutExchange());
    }
    
    //TODO  用户操作日志消息模型  Topic模式
    @Bean
    public TopicExchange topicExchange () {
    	log.info("【<<<<<<<<<<<--Topic交换器创建成功-->>>>>>>>>>>>>>>>>>>>】");
    	return new TopicExchange(env.getProperty("log.user.topic.exchange"),true,false);
    }
    
    /**
     * 测试队列
     * @return 队列实例
     */
    @Bean
    public Queue topicQueue() {
    	log.info("【<<<<<<<<<<<--测试topic队列创建成功-->>>>>>>>>>>>>>>>>>>>】");
        return new Queue(env.getProperty("log.user.topic.queue"));
    }
    
    @Bean
    public Binding bingQueue2ToTopic() {
    	Binding binding = BindingBuilder.bind(topicQueue()).to(topicExchange()).with("*.user.*");
        log.info("【<<<<<<<<<<<--topic队列绑定成功--匹配规则:"+env.getProperty("log.user.topic.queue.routing.key")+">>>>>>>>>>>>>>>>>>>>】");
        return binding;
    }
    
    //TODO  用户操作日志消息模型  Headers模式
    @Bean
    public HeadersExchange headersExchange () {
    	log.info("【<<<<<<<<<<<--Headers交换器创建成功-->>>>>>>>>>>>>>>>>>>>】");
    	return new HeadersExchange(env.getProperty("log.user.headers.exchange"),true,false);
    }
    @Bean
	public Queue headers_queue() {
		return new Queue(env.getProperty("log.user.headers.queue"),true);
	}
    
    @Bean
	Binding bindingExchangeTopicQueue2() {
		 Map<String, Object> map = new HashMap<>();
		 map.put("user", "101");
		 map.put("pwd", "202");
	    
		 //whereAll表示全部匹配
		 //return BindingBuilder.bind(queue).to(headersExchange).whereAll(map).match();
	        
		 //whereAny表示部分匹配
		 //all: 默认值。一个传送消息的header里的键值对和交换机的header键值对全部匹配,才可以路由到对应交换机
		 //any: 一个传送消息的header里的键值对和交换机的header键值对任意一个匹配,就可以路由到对应交换机
		 return BindingBuilder.bind(headers_queue()).
							   to(headersExchange()).
							   whereAny(map).match();
	}
	
}

四、创建发送消息服务

@Service
public class ProdServer {

	private static final Logger log = LoggerFactory.getLogger(ProdServer.class);

	@Autowired
	private ObjectMapper objectMapper;

	@Autowired
	private RabbitTemplate rabbitTemplate;

	@Autowired
	private Environment env;
	
	/**
	 * direct模式下发送消息
	 * @param obj
	 * @throws JsonProcessingException
	 */
	public void convertAndSend(Object obj) throws JsonProcessingException {
		
		rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
		rabbitTemplate.setExchange(env.getProperty("log.user.direct.exchange"));
		rabbitTemplate.setRoutingKey(env.getProperty("log.user.direct.routing.key"));
		
		Message message = MessageBuilder.withBody(objectMapper.writeValueAsBytes(obj))
				.setDeliveryMode(MessageDeliveryMode.PERSISTENT).build();
		message.getMessageProperties().setHeader(AbstractJavaTypeMapper.DEFAULT_CONTENT_CLASSID_FIELD_NAME,
				MessageProperties.CONTENT_TYPE_JSON);
		
		rabbitTemplate.convertAndSend(message);
		log.info("--------------------消息传入MQ成功-----------------");
	}
	
	/**
	 * fanout模式下发送消息
	 * @param obj
	 */
	public void fanoutSendMsg(Object obj) throws JsonProcessingException {
		rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
		rabbitTemplate.setExchange(env.getProperty("log.user.fanout.exchange"));
		rabbitTemplate.setRoutingKey("");
		
		Message message = MessageBuilder.withBody(objectMapper.writeValueAsBytes(obj))
				.setDeliveryMode(MessageDeliveryMode.PERSISTENT).build();
		message.getMessageProperties().setHeader(AbstractJavaTypeMapper.DEFAULT_CONTENT_CLASSID_FIELD_NAME,
				MessageProperties.CONTENT_TYPE_JSON);
		
		log.info("【消息发送者】发送消息到fanout交换机,消息内容为: {}", message);
		rabbitTemplate.convertAndSend(message);
		log.info("--------------------消息传入MQ成功-----------------");
	}
	
	/**
	 * topic模式下发送消息
	 * @param obj
	 */
	public void topicSendMsg1(Object obj) throws JsonProcessingException {
		rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
		rabbitTemplate.setExchange(env.getProperty("log.user.topic.exchange"));
		rabbitTemplate.setRoutingKey(env.getProperty("log.user.topic.routing.key1"));
		
		Message message = MessageBuilder.withBody(objectMapper.writeValueAsBytes(obj))
				.setDeliveryMode(MessageDeliveryMode.PERSISTENT).build();
		message.getMessageProperties().setHeader(AbstractJavaTypeMapper.DEFAULT_CONTENT_CLASSID_FIELD_NAME,
				MessageProperties.CONTENT_TYPE_JSON);
		
		log.info("【消息发送者1】发送消息到fanout交换机,消息内容为: {}", message);
		rabbitTemplate.convertAndSend(message);
	}
	
	/**
	 * topic模式下发送消息
	 * @param obj
	 */
	public void topicSendMsg2(Object obj) throws JsonProcessingException {
		rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
		rabbitTemplate.setExchange(env.getProperty("log.user.topic.exchange"));
		rabbitTemplate.setRoutingKey(env.getProperty("log.user.topic.routing.key2"));
		
		Message message = MessageBuilder.withBody(objectMapper.writeValueAsBytes(obj))
				.setDeliveryMode(MessageDeliveryMode.PERSISTENT).build();
		message.getMessageProperties().setHeader(AbstractJavaTypeMapper.DEFAULT_CONTENT_CLASSID_FIELD_NAME,
				MessageProperties.CONTENT_TYPE_JSON);
		
		log.info("【消息发送者2】发送消息到fanout交换机,消息内容为: {}", message);
		rabbitTemplate.convertAndSend(message);
	}
	
	/**
	 * headers模式下发送消息
	 * @param obj
	 */
	public void headersSendMsg1(Object obj) throws JsonProcessingException {
		rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
		rabbitTemplate.setExchange(env.getProperty("log.user.headers.exchange"));
		
		Message message = MessageBuilder.withBody(objectMapper.writeValueAsBytes(obj))
				.setDeliveryMode(MessageDeliveryMode.PERSISTENT).build();
		message.getMessageProperties().setHeader("user","102");
		
		log.info("【消息发送者1】发送消息到headers交换机,消息内容为: {}", message);
		rabbitTemplate.convertAndSend(message);
	}
	
	/**
	 * headers模式下发送消息
	 * @param obj
	 */
	public void headersSendMsg2(Object obj) throws JsonProcessingException {
		Map<String, Object> map_all = new HashMap<>();
		map_all.put("user", "101");
		map_all.put("pwd", "202");
		
		rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
		rabbitTemplate.setExchange(env.getProperty("log.user.headers.exchange"));
		
		Message message = MessageBuilder.withBody(objectMapper.writeValueAsBytes(obj))
				.setDeliveryMode(MessageDeliveryMode.PERSISTENT).build();
		message.getMessageProperties().getHeaders().putAll(map_all);
		
		log.info("【消息发送者2】发送消息到headers交换机,消息内容为: {}", message);
		rabbitTemplate.convertAndSend(message);
	}
}

五、创建接收消息的监听

@Component
public class LogMqListener {

	private static final Logger log= LoggerFactory.getLogger(LogMqListener.class);

    @Autowired
    private ObjectMapper objectMapper;

    /**
     * 监听消费用户日志
     * @param message
     */
    @RabbitListener(queues = "${log.user.direct.queue}",containerFactory = "singleListenerContainer")
    public void consumeUserLogQueue(@Payload byte[] message){
        try {
            String userLog=objectMapper.readValue(message, String.class);
            log.info("监听消费用户日志 监听到消息: {} ",userLog);
            //userLogMapper.insertSelective(userLog);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    
    /**
     * 监听消费用户日志 fanout模式
     * @param message
     */
    @RabbitListener(queues = "${log.user.fanout.queue1}",containerFactory = "singleListenerContainer")
    public void fanoutUserLogQueue1(@Payload byte[] message){
        try {
            String userLog=objectMapper.readValue(message, String.class);
            log.info("监听消费用户日志【队列1】 监听到消息: {} ",userLog);
            //userLogMapper.insertSelective(userLog);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    /**
     * 监听消费用户日志 fanout模式
     * @param message
     */
    @RabbitListener(queues = "${log.user.fanout.queue2}",containerFactory = "singleListenerContainer")
    public void fanoutUserLogQueue2(@Payload byte[] message){
        try {
            String userLog=objectMapper.readValue(message, String.class);
            log.info("监听消费用户日志 【队列2】监听到消息: {} ",userLog);
            //userLogMapper.insertSelective(userLog);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    
    /**
     * 监听消费用户日志 topic模式
     * @param message
     */
    @RabbitListener(queues = "${log.user.topic.queue}",containerFactory = "singleListenerContainer")
    public void topicUserLogQueue(@Payload byte[] message){
        try {
            String userLog=objectMapper.readValue(message, String.class);
            log.info("监听消费用户日志监听到消息: {} ",userLog);
            //userLogMapper.insertSelective(userLog);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    
    /**
     * 监听消费用户日志 headers模式
     * @param message
     */
    @RabbitListener(queues = "${log.user.headers.queue}",containerFactory = "singleListenerContainer")
    public void headersUserLogQueue(@Payload byte[] message){
        try {
            String userLog=objectMapper.readValue(message, String.class);
            log.info("监听消费用户日志监听到消息: {} ",userLog);
            //userLogMapper.insertSelective(userLog);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

六、创建测试类

@RestController
@RequestMapping("/mq")
public class UserController extends BaseController{
	
	@Autowired
	private ProdServer prodServer;
	
	@RequestMapping(value="/direct/add", method = {RequestMethod.GET, RequestMethod.POST})
	public String direct(String eventIds) {
		String msg = IdUtils.randomUUID();
		try {
			prodServer.convertAndSend(msg);
		} catch (Exception e) {
			e.printStackTrace();
			logger.error("-----------------mq添加出错------------");
		}
		return msg;
	}
	
	@RequestMapping(value="/fanout/add", method = {RequestMethod.GET, RequestMethod.POST})
	public String fanout(String eventIds) {
		String msg = IdUtils.randomUUID();
		try {
			prodServer.fanoutSendMsg(msg);
		} catch (Exception e) {
			e.printStackTrace();
			logger.error("-----------------mq添加出错------------");
		}
		return msg;
	}
	
	@RequestMapping(value="/topic/add", method = {RequestMethod.GET, RequestMethod.POST})
	public String topic(String eventIds) {
		String msg = IdUtils.randomUUID();
		try {
			prodServer.topicSendMsg1(msg);
			prodServer.topicSendMsg2(msg);
		} catch (Exception e) {
			e.printStackTrace();
			logger.error("-----------------mq添加出错------------");
		}
		return msg;
	}
	
	@RequestMapping(value="/headers/add", method = {RequestMethod.GET, RequestMethod.POST})
	public String headers(String eventIds) {
		String msg = IdUtils.randomUUID();
		try {
			prodServer.headersSendMsg1(msg);
			prodServer.headersSendMsg2(msg);
		} catch (Exception e) {
			e.printStackTrace();
			logger.error("-----------------mq添加出错------------");
		}
		return msg;
	}

}

所有的代码实现都已经写完了,接下来就可以把项目跑起来,调用接口看一下实现效果
启动服务
在这里插入图片描述
测试hesders交换器结果
在这里插入图片描述

小结:

这里只是写了每个交换器基本的使用方法,具体的项目使用还是需要更加深入的学习

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值