RabbitMQ自学之路(五)——-SpringBoot与RabbitMQ整合和对五种队列模式的实现

前面章节已经对RabbitMQ的五种队列模式进行了介绍,现在通过SpringBoot整合RabbitMQ来对五种队列模式进行一个更深入的描述

一、springboot集成RabbitMQ

springboot集成RabbitMQ非常简单,如果只是简单的使用配置非常少,springboot提供了spring-boot-starter-amqp对消息各种支持。

1、配置pom文件,添加spring-boot-starter-amqp的支持

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

2、配置application.yml文件,配置rabbitmq的安装地址、端口以及账户信息

#配置rabbitmq的安装地址、端口以及账户信息
spring:
  application: 
    name: spirng-boot-rabbitmq
  rabbitmq: 
    #服务器ip
    host: 127.0.0.1
    #端口号
    port: 5672
    #用户名
    username: admin
    #密码
    password: 123456
    #虚拟空间地址
    virtual-host: /

二、简单队列

在这里插入图片描述

1、配置队列

queue_simple 是队列名称

package com.springboot.rabbitmq.eimm.simple.config;

import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 
 * 	简单队列
 * @author Mr yi
 * @time 2019年6月19日
 */
@Configuration
public class RabbitConfigSimple {

	 @Bean
	 public Queue queueSimple() {
        return new Queue("queue_simple");
    }
}

2、生产者:生产者发送消息

package com.springboot.rabbitmq.eimm.simple.producers;

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

/**
 * 
 * @method 生产者
 * @author Mr yi
 * @time 2019年6月19日
 */
@Component
public class ProducersSimple {

	 @Autowired
	 private AmqpTemplate amqpTemplate;
	 
	 public void send() {
	        String context = "Hello World! " ;
	        System.out.println("Producers sends message: " + context);
	        //简单队列的情况下routingKey即为队列名queue_simple
	        this.amqpTemplate.convertAndSend("queue_simple", context);
	    }
}

3、消费者

package com.springboot.rabbitmq.eimm.simple.consumers;

import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

/**
 * 
 * @method 消费者
 * @author Mr yi
 * @time 2019年6月19日
 */
@Component
@RabbitListener(queues = "queue_simple")
public class ConsumersSimple {

	//@RabbitListener 标注在类上面表示当有收到消息的时候,就交给 @RabbitHandler 的方法处理,
	 //具体使用哪个方法处理,根据 MessageConverter 转换后的参数类型
	
	@RabbitHandler
    public void process(String message) {
        System.out.println("Consumers receiver message : " + message);
    }
	
	@RabbitHandler
    public void process(byte[] message) {
        System.out.println("Consumers receiver message : " + new String(message));
    }
}

4、测试

@Autowired
    private ProducersSimple producers;

	@RequestMapping("/send")
    public void send() throws Exception {
    	producers.send();
    }

5、结果

控制台打印
在这里插入图片描述
查看RabbitMq 服务器,发现新增了一个queue_simple的队列,点击队列名称可以查询详细信息
在这里插入图片描述

三、Work模式

1、配置队列

queue_work是队列名称

package com.springboot.rabbitmq.eimm.work.config;

import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 
 * 	Work模式
 * @author Mr yi
 * @time 2019年6月19日
 */
@Configuration
public class RabbitConfigWork {

	 @Bean
	 public Queue queueWork() {
        return new Queue("queue_work");
    }
}


2、生产者:生产者发送多条消息

package com.springboot.rabbitmq.eimm.work.producers;

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

/**
 * 
 * @method 生产者
 * @author Mr yi
 * @time 2019年6月19日
 */
@Component
public class ProducersWork {

	 @Autowired
	 private AmqpTemplate amqpTemplate;
	 
	 //生产者发送多个消息
	 public void send() throws Exception {
		 for(int i=0;i<=10;i++) {
	        String context = "Work["+i+"]"  ;
	        System.out.println("Producers sends message: " + context);
	        this.amqpTemplate.convertAndSend("queue_work", context);
	        Thread.sleep(100);
		 }
	   }
}


3、消费者

这里配置了多个消费者,主要是了验证当有多个消息是消费者是如何接受消息的

package com.springboot.rabbitmq.eimm.work.consumers;

import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

/**
 * 
 * @method 消费者A
 * @author Mr yi
 * @time 2019年6月19日
 */
@Component
@RabbitListener(queues = "queue_work")
public class ConsumersWorkA {
	
	@RabbitHandler
    public void process(String message) {
        System.out.println("ConsumersA receiver message : " + message);
    }

}



package com.springboot.rabbitmq.eimm.work.consumers;

import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

/**
 * 
 * @method 消费者B
 * @author Mr yi
 * @time 2019年6月19日
 */
@Component
@RabbitListener(queues = "queue_work")
public class ConsumersWorkB {
	
	@RabbitHandler
    public void process(String message) {
        System.out.println("ConsumersB receiver message : " + message);
    }

}


4、测试

     @Autowired
	private ProducersWork producers;
	
	@RequestMapping("/send")
    public void send() throws Exception {
    	producers.send();
    }

5、结果

控制台打印,发现10条消息 偶数条消费者A获取,奇数条消费者B获取,并且平均分配。

当然通过代码实现按需分配,即谁的性能强,谁优先原则,实现负载均衡。
在这里插入图片描述
查看RabbitMq 服务器,发现新增了一个queue_work的队列,点击队列名称可以查询详细信息

在这里插入图片描述

四、Fanout Exchange(订阅模式)

Fanout:广播,将消息交给所有绑定到交换机的队列

1、配置队列

配置了两个队列和一个交换机,并且两个队列要和交换机进行绑定

package com.springboot.rabbitmq.eimm.fanout.config;

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.amqp.core.TopicExchange;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 
 * 	Fanout Exchange(订阅模式)
 * @author Mr yi
 * @time 2019年6月19日
 */
@Configuration
public class RabbitConfigFanout {

	/**
	 * 两个消息队列名称
	 */
	final static String queueA = "queue_fanout_a";
    final static String queueB = "queue_fanout_b";
    
    /**
     *	 交换机名称
     */
    final static String exchange = "fanoutExchange";
     
    
    @Bean
    public Queue queueFanoutA() {
        return new Queue(RabbitConfigFanout.queueA);
    }
    
    @Bean
    public Queue queueFanoutB() {
        return new Queue(RabbitConfigFanout.queueB);
    }
    
    /**
     * 
     * @method 声明一个fanout类型的交换机
     * @author Mr yi
     * @time 2019年6月19日
     * @return
     */
    @Bean
    FanoutExchange fanoutExchange() {
        return new FanoutExchange(RabbitConfigFanout.exchange);
    }
 
    /**
     * 
     * @method 绑定Queue队列到交换机,并且指定routingKey
     * @author Mr yi
     * @time 2019年6月19日
     * @param queueFanoutA 对应注入queueFanoutA()方法
     * @param fanoutExchange 对应fanoutExchange()
     * @return
     */
    @Bean
    Binding bindingFanoutExchangeA(Queue queueFanoutA, FanoutExchange  fanoutExchange) {
        return BindingBuilder.bind(queueFanoutA).to(fanoutExchange);
    }

    @Bean
    Binding bindingFanoutExchangeB(Queue queueFanoutB, FanoutExchange  fanoutExchange) {
        return BindingBuilder.bind(queueFanoutB).to(fanoutExchange);
    }
 
}


2、生产者

package com.springboot.rabbitmq.eimm.fanout.producers;

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

/**
 * 
 * @method 生产者
 * @author Mr yi
 * @time 2019年6月19日
 */
@Component
public class ProducersFanout {

	@Autowired
	private AmqpTemplate amqpTemplate;

	/**
	 * 
	 * @method 生产者发送消息,fanout模式下routingKey为空即可
	 * @author Mr yi
	 * @time 2019年6月19日
	 * @throws Exception
	 */
	public void send() throws Exception {
		String context = "fanout message";
		System.out.println("Producers sends message: " + context);
		this.amqpTemplate.convertAndSend("fanoutExchange", "", context);
	}

	 
}


3、消费者

这里配置了两个消费者,并且两个消费者需要和两个不同的队列进行绑定

package com.springboot.rabbitmq.eimm.fanout.consumers;

import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

/**
 * 
 * @method 消费者A
 * @author Mr yi
 * @time 2019年6月19日
 */
@Component
@RabbitListener(queues = "queue_fanout_a")
public class ConsumersFanoutA {

	@RabbitHandler
    public void process(String message) {
        System.out.println("ConsumersFanoutA receiver message : " + message);
    }
}




package com.springboot.rabbitmq.eimm.fanout.consumers;

import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

/**
 * 
 * @method 消费者B
 * @author Mr yi
 * @time 2019年6月19日
 */
@Component
@RabbitListener(queues = "queue_fanout_b")
public class ConsumersFanoutB {

	@RabbitHandler
    public void process(String message) {
        System.out.println("ConsumersFanoutB receiver message : " + message);
    }
}


4、测试

   @Autowired
	private ProducersFanout producers;
	
	@RequestMapping("/send")
    public void send() throws Exception {
    	producers.send();
    }

5、结果

控制台打印 ,发现两个绑定了不同队列的消费者都接受到了同一条消息

在这里插入图片描述在这里插入图片描述
查看RabbitMq 服务器

在这里插入图片描述

五、Direct Exchange(路由模式)

Direct:定向,把消息交给符合指定routing key 的队列

1、配置队列

配置了两个队列和一个交换机,并且两个队列要和交换机进行绑定。同时交换机为两个队列指定了两个不同的routing key

package com.springboot.rabbitmq.eimm.direct.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.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 
 * 	Direct Exchange(路由模式)
 * @author Mr yi
 * @time 2019年6月19日
 */
@Configuration
public class RabbitConfigDirect {

	/**
	 * 两个消息队列名称
	 */
	final static String queueA = "queue_direct_a";
    final static String queueB = "queue_direct_b";
    
    /**
     *	 交换机名称
     */
    final static String exchange = "directExchange";
     
    
    @Bean
    public Queue queueDirectA() {
        return new Queue(RabbitConfigDirect.queueA);
    }
    
    @Bean
    public Queue queueDirectB() {
        return new Queue(RabbitConfigDirect.queueB);
    }
    
    /**
     * 
     * @method 声明一个direct类型的交换机
     * @author Mr yi
     * @time 2019年6月19日
     * @return
     */
    @Bean
    DirectExchange directExchange() {
        return new DirectExchange(RabbitConfigDirect.exchange);
    }
 
    /**
     * 
     * @method 绑定Queue队列到交换机,并且指定routingKey
     * @author Mr yi
     * @time 2019年6月19日
     * @param queueDirectA 对应注入queueDirectA()方法
     * @param directExchange 对应directExchange()
     * @return
     */
    @Bean
    Binding bindingDirectExchangeA(Queue queueDirectA, DirectExchange  directExchange) {
        return BindingBuilder.bind(queueDirectA).to(directExchange).with("directKeyA");
    }

    @Bean
    Binding bindingDirectExchangeB(Queue queueDirectB, DirectExchange  directExchange) {
        return BindingBuilder.bind(queueDirectB).to(directExchange).with("directKeyB");
    }
 
}


2、生产者

生产者发送消息包含两部分
(1)消息内容(即消费者需要接受的消息)
(2)内容标签(即routingKey),路由模式下交换机会把消息交给符合指定routing key 的队列

package com.springboot.rabbitmq.eimm.direct.producers;

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

/**
 * 
 * @method 生产者
 * @author Mr yi
 * @time 2019年6月19日
 */
@Component
public class ProducersDirect {

	@Autowired
	private AmqpTemplate amqpTemplate;

	/**
	 * 
	 * @method 生产者发送消息,direct模式下需要传递一个routingKey
	 * @author Mr yi
	 * @time 2019年6月19日
	 * @throws Exception
	 */
	public void sendA() throws Exception {
		String context = "direct message";
		System.out.println("Producers sends messageA: " + context);
		this.amqpTemplate.convertAndSend("directExchange", "directKeyA", context);
	}
	
	/**
	 * 
	 * @method 生产者发送消息,direct模式下需要传递一个routingKey
	 * @author Mr yi
	 * @time 2019年6月19日
	 * @throws Exception
	 */
	public void sendB() throws Exception {
		String context = "direct message";
		System.out.println("Producers sends messageB: " + context);
		this.amqpTemplate.convertAndSend("directExchange", "directKeyB", context);
	}

	 
}



3、消费者

这里配置了两个消费者,并且两个消费者需要和两个不同的队列进行绑定

package com.springboot.rabbitmq.eimm.fanout.consumers;

import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

package com.springboot.rabbitmq.eimm.direct.consumers;

import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

/**
 * 
 * @method 消费者A
 * @author Mr yi
 * @time 2019年6月19日
 */
@Component
@RabbitListener(queues = "queue_direct_a")
public class ConsumersDirectA {

	@RabbitHandler
    public void process(String message) {
        System.out.println("ConsumersDirectA receiver message : " + message);
    }
}




package com.springboot.rabbitmq.eimm.direct.consumers;

import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

/**
 * 
 * @method 消费者B
 * @author Mr yi
 * @time 2019年6月19日
 */
@Component
@RabbitListener(queues = "queue_direct_b")
public class ConsumersDirectB {

	@RabbitHandler
    public void process(String message) {
        System.out.println("ConsumersDirectB receiver message : " + message);
    }
}


4、测试

  @Autowired
	private ProducersDirect producers;
	
	@RequestMapping("/sendA")
    public void sendA() throws Exception {
    	producers.sendA();
    }
	
	@RequestMapping("/sendB")
    public void sendB() throws Exception {
    	producers.sendB();
    }

5、结果

控制台打印

sendA()方法 下,消费者A获取了消息
在这里插入图片描述
在这里插入图片描述
sendB()方法 下,消费者A获取了消息

在这里插入图片描述
在这里插入图片描述
查看RabbitMq 服务器

在这里插入图片描述

六、Topic Exchange(主题模式)

Topic:通配符,把消息交给符合routing pattern(路由模式) 的队列

1、配置队列

配置了两个队列和一个交换机,并且两个队列要和交换机进行绑定。同时交换机为两个队列指定了两个不同的routing key

package com.springboot.rabbitmq.eimm.topic.config;

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;

/**
 * 
 * 	Topic Exchange(主题模式)
 * @author Mr yi
 * @time 2019年6月19日
 */
@Configuration
public class RabbitConfigTopic {

	/**
	 * 两个消息队列名称
	 */
	final static String queueA = "queue_topic_a";
    final static String queueB = "queue_topic_b";
    
    /**
     *	 交换机名称
     */
    final static String exchange = "topicExchange";
     
    
    @Bean
    public Queue queueTopicA() {
        return new Queue(RabbitConfigTopic.queueA);
    }
    
    @Bean
    public Queue queueTopicB() {
        return new Queue(RabbitConfigTopic.queueB);
    }
    
    /**
     * 
     * @method 声明一个Topic类型的交换机
     * @author Mr yi
     * @time 2019年6月19日
     * @return
     */
    @Bean
    TopicExchange topicExchange() {
        return new TopicExchange(RabbitConfigTopic.exchange);
    }
 
    /**
     * 
     * @method 绑定Queue队列到交换机,并且指定routingKey
     * @author Mr yi
     * @time 2019年6月19日
     * @param queueMessage
     * @param exchange
     * @return
     */
    @Bean
    Binding bindingTopicExchangeA(Queue queueTopicA, TopicExchange topicExchange) {
        return BindingBuilder.bind(queueTopicA).to(topicExchange).with("topic.keyA");
    }

    @Bean
    Binding bindingTopicExchangeB(Queue queueTopicB, TopicExchange topicExchange) {
        return BindingBuilder.bind(queueTopicB).to(topicExchange).with("topic.#");
    }
 
}



2、生产者

生产者发送消息包含两部分
(1)消息内容(即消费者需要接受的消息)
(2)内容标签(即routingKey),路由模式下交换机会把消息交给符合指定routing key 的队列

package com.springboot.rabbitmq.eimm.topic.producers;

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

/**
 * 
 * @method 生产者
 * @author Mr yi
 * @time 2019年6月19日
 */
@Component
public class ProducersTopic {

	@Autowired
	private AmqpTemplate amqpTemplate;

	/**
	 * 
	 * @method 生产者消息,并指定routingKey为topic.keyA
	 * @author Mr yi
	 * @time 2019年6月19日
	 * @throws Exception
	 */
	public void sendA() throws Exception {
		String context = "topic messageA";
		System.out.println("Producers sends messageA: " + context);
		this.amqpTemplate.convertAndSend("topicExchange", "topic.keyA", context);
	}

	/**
	 * 
	 * @method 生产者消息,并指定routingKey为topic.keyB
	 * @author Mr yi
	 * @time 2019年6月19日
	 * @throws Exception
	 */
	public void sendB() throws Exception {
		String context = "topic messageB";
		System.out.println("Producers sends messageB: " + context);
		this.amqpTemplate.convertAndSend("topicExchange", "topic.keyB", context);
	}
}



3、消费者

这里配置了两个消费者,并且两个消费者需要和两个不同的队列进行绑定

package com.springboot.rabbitmq.eimm.topic.consumers;

import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

/**
 * 
 * @method 消费者A
 * @author Mr yi
 * @time 2019年6月19日
 */
@Component
@RabbitListener(queues = "queue_topic_a")
public class ConsumersTopicA {

	@RabbitHandler
    public void process(String message) {
        System.out.println("ConsumersTopicA receiver message : " + message);
    }
}




package com.springboot.rabbitmq.eimm.topic.consumers;

import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

/**
 * 
 * @method 消费者B
 * @author Mr yi
 * @time 2019年6月19日
 */
@Component
@RabbitListener(queues = "queue_topic_b")
public class ConsumersTopicB {

	@RabbitHandler
    public void process(String message) {
        System.out.println("ConsumersTopicB receiver message : " + message);
    }
}


4、测试

  @Autowired
	private ProducersTopic producers;
	
	@RequestMapping("/sendA")
    public void sendA() throws Exception {
    	producers.sendA();
    }
	
	@RequestMapping("/sendB")
    public void sendB() throws Exception {
    	producers.sendB();
    }

5、结果

控制台打印

sendA()方法 下,消费者A和消费者B获取了消息

在这里插入图片描述
在这里插入图片描述
sendB()方法 下,只有消费者B获取了消息
在这里插入图片描述
在这里插入图片描述

查看RabbitMq 服务器

在这里插入图片描述

源码下载:https://download.csdn.net/download/qq_29914837/11252856


如果你觉得本篇文章对你有所帮助的话,麻烦请点击头像右边的关注按钮,谢谢!

技术在交流中进步,知识在分享中传播

发布了166 篇原创文章 · 获赞 212 · 访问量 19万+

猜你喜欢

转载自blog.csdn.net/qq_29914837/article/details/93144255