rabbitmq中交换机类型direct和topic的区别

    rabbitmq主要有三大类交换机:fanout,direct,topic,他们从名字上分别是扇区交换机、直连交换机和主题交换机。其实还有headers一类的交换机,这里不去深究。

    fanout交换机也叫无路由交换机,就是它直接与交换机exchange发生关联,不用routingKey。

    direct和topic都加入了routingKey的概念,发送数据的时候,它只跟交换机和路由发生关系,不关心最终的队列queue。就是生产者这里只需要将消息绑定到exchange和routingKey上,如果是springboot与rabbitmq关联,我们可以从api上来看看:

@Override
public void convertAndSend(String exchange, String routingKey, final Object object) throws AmqpException {
		convertAndSend(exchange, routingKey, object, (CorrelationData) null);
}

    这是一个很直观的方法,方法体中跟rabbitmq有关的只是exchange,routingKey,object。 

    这里也引出了本文的主要内容:direct类型和topic类型到底有什么区别呢?区别就是:direct类型从字面上看就是直连的意思,从生产者到消费者这条线上,routingKey只能一一对应,而topic主题类型生产者到消费者routingKey可以多对一。可以用如下直观的图形表示:

    

    如果这段描述还不是很清晰,请看下面一个示例:

    springboot整合rabbitmq

    maven依赖:

 <parent>
  	<groupId>org.springframework.boot</groupId>
  	<artifactId>spring-boot-starter-parent</artifactId>
  	<version>2.1.4.RELEASE</version>
  </parent>

  <dependencies>
	<dependency>
	  <groupId>org.springframework.boot</groupId>
	  <artifactId>spring-boot-starter</artifactId>
	</dependency>
	<dependency>
	  <groupId>org.springframework.boot</groupId>
	  <artifactId>spring-boot-starter-amqp</artifactId>
	</dependency>
	<!-- tool -->
	<dependency>
	    <groupId>org.apache.commons</groupId>
	    <artifactId>commons-lang3</artifactId>
	</dependency>

	<dependency>
	    <groupId>com.alibaba</groupId>
	    <artifactId>fastjson</artifactId>
	    <version>1.2.58</version>
	</dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <scope>test</scope>
    </dependency>
  </dependencies>
  
  <build>
  	<plugins>
  		<plugin>
  			<groupId>org.springframework.boot</groupId>
  			<artifactId>spring-boot-maven-plugin</artifactId>
  		</plugin>
  	</plugins>
  </build>

   rabbitmq连接配置信息:

spring:
  rabbitmq:
    addresses: 192.168.226.100:5672
    username: huali
    password: huali
    virtual-host: /mec
    publisher-confirms: true
    connectionTimeout: 5000
    template:
      madatory: true
    listener:
      simple:
        acknowledge-mode: manual
        concurrency: 1
        max-concurrency: 10
        retry:
          enabled: true
      

 

    RabbitTemplate配置 

package com.huali.mec.parse.config;

import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AMQPConfig {
	@Bean
	public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
		RabbitTemplate template = new RabbitTemplate(connectionFactory);
		return template;
	}
}

   监听器,这里是消费者:

package com.huali.mec.parse.listener;
import java.io.IOException;
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import com.rabbitmq.client.Channel;

@Component
public class UpMessageListener {
	
	@RabbitListener(bindings = {@QueueBinding
		(value = @Queue(value = "queue1",durable = "true"), 
		exchange = @Exchange(value="MEC1",type = ExchangeTypes.TOPIC),
		key = "test.#")})
	public void topicHandler(Message message,Channel channel) throws IOException{
		System.out.println("receive topic message -> "+new String(message.getBody()));
		channel.basicAck(message.getMessageProperties().getDeliveryTag(), true);
	}
	
	@RabbitListener(bindings = {@QueueBinding
		(value = @Queue(value = "queue2",durable = "true"), 
		exchange = @Exchange(value="MEC2",type = ExchangeTypes.DIRECT),
		key = "test.aaa")})
	public void directHandler(Message message,Channel channel) throws IOException{
		System.out.println("receive direct message -> "+new String(message.getBody()));
		channel.basicAck(message.getMessageProperties().getDeliveryTag(), true);
	}
	
	/*
	@RabbitListener(bindings = {@QueueBinding
			(value = @Queue(value = "queue2",durable = "true"), 
			exchange = @Exchange(value="MEC2",type = ExchangeTypes.DIRECT),
			key = "test.bbb")})
	public void directHandler2(Message message,Channel channel) throws IOException{
		System.out.println("receive direct message -> "+new String(message.getBody()));
		channel.basicAck(message.getMessageProperties().getDeliveryTag(), true);
	}*/
	
}

    这里是生产者,注释的部分是用来发送direct类型消息的,这样可以看清楚他们的区别。 

package com.huali.mec.parse.service;

import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class PublishService {
	@Autowired
	private RabbitTemplate rabbitTemplate;
	
	public void send(String msg) {
		rabbitTemplate.convertAndSend("MEC1", "test.aaa", msg);
		rabbitTemplate.convertAndSend("MEC1", "test.bbb", msg);
		//rabbitTemplate.convertAndSend("MEC2", "test.aaa", msg);
		//rabbitTemplate.convertAndSend("MEC2", "test.bbb", msg);
	}
}

     启动类,启动的时候循环发送10次消息。

package com.huali.mec.parse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import com.huali.mec.parse.service.PublishService;

@SpringBootApplication
public class ParseApp implements CommandLineRunner{
    public static void main( String[] args ){
    	SpringApplication.run(ParseApp.class, args);
    }
    
    @Autowired
    private PublishService publishService;
    
    @Override
    public void run(String... args) throws Exception {
    	for(int i=0;i<10;i++) {
    		publishService.send("hello,"+i);
    	}
    }
    
}

     运行这段示例,只需要准备好一个rabbitmq服务器,设定好本文所需vhost即可。队列和交换机都不用创建并绑定,程序启动会自动创建并绑定路由关系。

     这里运行分三步:

     1、直接运行本示例代码,可以查看topic交换机的输出:控制台打印20次消息,因为消费者绑定了routingKey是test.#就是会消费来自test.aaa和test.bbb的所有消息。

receive topic message -> hello,0
receive topic message -> hello,0
receive topic message -> hello,1
receive topic message -> hello,1
receive topic message -> hello,2
receive topic message -> hello,2
receive topic message -> hello,4
receive topic message -> hello,3
receive topic message -> hello,3
receive topic message -> hello,4
receive topic message -> hello,5
receive topic message -> hello,5
receive topic message -> hello,6
receive topic message -> hello,6
receive topic message -> hello,7
receive topic message -> hello,7
receive topic message -> hello,8
receive topic message -> hello,8
receive topic message -> hello,9
receive topic message -> hello,9

     2、将PublishService中发送topic交换机的代码注释,打开发送direct交换机的代码,如下所示:

@Component
public class PublishService {
	@Autowired
	private RabbitTemplate rabbitTemplate;
	
	public void send(String msg) {
		//rabbitTemplate.convertAndSend("MEC1", "test.aaa", msg);
		//rabbitTemplate.convertAndSend("MEC1", "test.bbb", msg);
		rabbitTemplate.convertAndSend("MEC2", "test.aaa", msg);
		rabbitTemplate.convertAndSend("MEC2", "test.bbb", msg);
	}
}

  同样运行启动程序,打印如下所示:

receive direct message -> hello,0
receive direct message -> hello,1
receive direct message -> hello,2
receive direct message -> hello,3
receive direct message -> hello,4
receive direct message -> hello,5
receive direct message -> hello,7
receive direct message -> hello,6
receive direct message -> hello,8
receive direct message -> hello,9

    虽然发送了两组routingKey=test.aaa和routingKey=test.bbb的消息,但是只打印了test.aaa这个routingKey的消息。因为我们的监听器那里只绑定了一次routingKey。

    3、将代码UpMessageListener.java中的另一个绑定routingKey的代码注释打开,运行:

public class UpMessageListener {
	
	@RabbitListener(bindings = {@QueueBinding
		(value = @Queue(value = "queue1",durable = "true"), 
		exchange = @Exchange(value="MEC1",type = ExchangeTypes.TOPIC),
		key = "test.#")})
	public void topicHandler(Message message,Channel channel) throws IOException{
		System.out.println("receive topic message -> "+new String(message.getBody()));
		channel.basicAck(message.getMessageProperties().getDeliveryTag(), true);
	}
	
	@RabbitListener(bindings = {@QueueBinding
		(value = @Queue(value = "queue2",durable = "true"), 
		exchange = @Exchange(value="MEC2",type = ExchangeTypes.DIRECT),
		key = "test.aaa")})
	public void directHandler(Message message,Channel channel) throws IOException{
		System.out.println("receive direct message -> "+new String(message.getBody()));
		channel.basicAck(message.getMessageProperties().getDeliveryTag(), true);
	}
	
	
	@RabbitListener(bindings = {@QueueBinding
			(value = @Queue(value = "queue2",durable = "true"), 
			exchange = @Exchange(value="MEC2",type = ExchangeTypes.DIRECT),
			key = "test.bbb")})
	public void directHandler2(Message message,Channel channel) throws IOException{
		System.out.println("receive direct message -> "+new String(message.getBody()));
		channel.basicAck(message.getMessageProperties().getDeliveryTag(), true);
	}
	
}

    这次运行就打印了20次消息:

receive direct message -> hello,0
receive direct message -> hello,1
receive direct message -> hello,0
receive direct message -> hello,2
receive direct message -> hello,3
receive direct message -> hello,1
receive direct message -> hello,4
receive direct message -> hello,3
receive direct message -> hello,2
receive direct message -> hello,5
receive direct message -> hello,7
receive direct message -> hello,4
receive direct message -> hello,5
receive direct message -> hello,6
receive direct message -> hello,6
receive direct message -> hello,7
receive direct message -> hello,8
receive direct message -> hello,8
receive direct message -> hello,9
receive direct message -> hello,9

     至此,示例结束,再回过头来想想direct和topic类型交换机的区别,其实在生产者端几乎完全没有区别,主要在于消费者端这里,消费者要去消费routingKey,direct只能一一对应消费单个的routingKey,而topic可以使用通配符*和#来匹配多个routingKey。至于他们绑定到queue上,是一个还是多个,他们之间又没有区别。

    他们两者与fanout的区别是一个有routingKey,一个没有。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

luffy5459

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值