RabbitMQ与Spring的框架整合之Spring AMQP实战

1、SpringAMQP用户管理组件RabbitAdmin。

  RabbitAdmin类可以很好的操作RabbitMQ,在Spring中直接进行注入即可。注意,autoStartup必须设置为true,否则Spring容器不会加载RabbitAdmin类。RabbitAdmin底层实现就是从Spring容器中获取Exchange交换机、Binding绑定、RoutingKey路由键以及Queue队列的@Bean声明。

  然后使用RabbitTemplate的execute方法执行对应的声明、修改、删除等一系列RabbitMQ基础功能操作。例如,添加一个交换机、删除一个绑定、清空一个队列里面的消息等待操作。

2、由于使用的maven工程配合了Springboot整合Spring与RabbitMQ的知识。所以先引入依赖包,如下所示:

 <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2..RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.bie</groupId>
<artifactId>rabbitmq-spring</artifactId>
<version>0.0.-SNAPSHOT</version>
<name>rabbitmq-spring</name>
<description>Demo project for Spring Boot</description> <properties>
<project.build.sourceEncoding>UTF-</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-
</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<maven-jar-plugin.version>3.1.</maven-jar-plugin.version>
</properties> <dependencies>
<!-- Spring与RabbitMQ整合的包 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit-test</artifactId>
<scope>test</scope>
</dependency>
<!-- RabbitMQ基础核心包 -->
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
</dependency>
</dependencies> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build> </project>

由于使用的是Springboot项目配合RabbitMQ来做的,所以配置文件这里使用了注解来替换,所以启动的时候,加载如下所示配置类,如下所示:

 package com.bie;

 import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration; /**
*
* @author biehl
*
*/
@Configuration
@ComponentScan(basePackages = "com.bie")
public class RabbitMQConfig { /**
* 将ConnectionFactory注入到bean容器中
*
* @return
*/
@Bean
public ConnectionFactory connectionFactory() {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
connectionFactory.setAddresses("192.168.110.133:5672");
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
connectionFactory.setVirtualHost("/");
return connectionFactory;
} /**
* 参数依赖上面注入的ConnectionFactory类,所以保持参数名称和注入的ConnectionFactory一致
*
* @param connectionFactory
* @return
*/
@Bean
public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory) {
RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
// 注意:autoStartup必须设置为true,否则Spring容器不会加载RabbitAdmin类。
rabbitAdmin.setAutoStartup(true);
return rabbitAdmin;
} }

项目主启动类,如下所示:

 package com.bie;

 import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication
public class RabbitmqSpringApplication { public static void main(String[] args) {
SpringApplication.run(RabbitmqSpringApplication.class, args);
} }

下面演示一下,Spring整合RabbitMQ,创建交换机,创建队列,将交换机和队列绑定的示例代码,如下所示:

 package com.bie;

 import java.util.HashMap;

 import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.FanoutExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner; /**
*
* @author biehl
*
*/
@SpringBootTest
@RunWith(SpringRunner.class)
public class RabbitmqSpringApplicationTests { @Autowired
private RabbitAdmin rabbitAdmin; @Test
public void rabbitmqAdmin() {
// 参数1交换机名称, 参数1是否持久化durable, 参数3是否自动删除 autoDelete
// 创建direct类型的交换机
DirectExchange directExchange = new DirectExchange("test.directExchange", false, false);
rabbitAdmin.declareExchange(directExchange); // 创建topic类型的交换机
TopicExchange topicExchange = new TopicExchange("test.topicExchange", false, false);
rabbitAdmin.declareExchange(topicExchange); // 创建fanout类型的交换机
FanoutExchange fanoutExchange = new FanoutExchange("test.fanoutExchange", false, false);
rabbitAdmin.declareExchange(fanoutExchange); // 创建direct类型的队列
Queue directQueue = new Queue("test.direct.queue", false);
rabbitAdmin.declareQueue(directQueue); // 创建topic类型的交队列
Queue topicQueue = new Queue("test.topic.queue", false);
rabbitAdmin.declareQueue(topicQueue); // 创建fanout类型的队列
Queue fanoutQueue = new Queue("test.fanout.queue", false);
rabbitAdmin.declareQueue(fanoutQueue); // 声明绑定
// 参数1 String destination,可以认为是具体的队列。
// 参数2 DestinationType destinationType,绑定的类型。
// 参数3 String exchange,交换机的名称。
// 参数4 String routingKey,路由键的名称。
// 参数5 Map<String, Object> arguments可以传入的参数。
// 将test.directExchange交换机和test.direct.queue队列进行绑定
rabbitAdmin.declareBinding(new Binding("test.direct.queue", Binding.DestinationType.QUEUE,
"test.directExchange", "direct", new HashMap<>())); // 将test.topicExchange交换机和test.topic.queue队列进行绑定
// rabbitAdmin.declareBinding(new Binding("test.topic.queue",
// Binding.DestinationType.QUEUE, "test.topicExchange",
// "topic", new HashMap<>()));
rabbitAdmin.declareBinding(BindingBuilder.bind(new Queue("test.topic.queue", false)) // 直接创建队列
.to(new TopicExchange("test.topicExchange", false, false)) // 直接创建交换机 建立关联关系
.with("user.#")); // 指定路由Key // 将test.fanoutExchange交换机和test.fanout.queue队列进行绑定
// rabbitAdmin.declareBinding(new Binding("test.fanout.queue",
// Binding.DestinationType.QUEUE,
// "test.fanoutExchange", "", new HashMap<>())); rabbitAdmin.declareBinding(BindingBuilder.bind(new Queue("test.fanout.queue", false)) // 直接创建队列
.to(new FanoutExchange("test.fanoutExchange", false, false))); // 直接创建交换机 建立关联关系 // 清空队列数据
rabbitAdmin.purgeQueue("test.direct.queue", false);
rabbitAdmin.purgeQueue("test.topic.queue", false);
rabbitAdmin.purgeQueue("test.fanout.queue", false);
} }

执行代码,完毕,可以在RabbitMQ的管控台查询效果,效果如下所示:

RabbitMQ与Spring的框架整合之Spring AMQP实战

3、使用SpringAMQP去声明,就需要使用SpringAMQP的如下模式,即声明@Bean方式。SpringAMQP-RabbitMQ声明式配置使用。可以在初始化加载配置文件中创建好交换机,队列,以及交换机和队列的绑定关系,启动项目即可将交换机,队列,以及交换机和队列的绑定创建,如下所示:

 package com.bie;

 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.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration; /**
*
* @author biehl
*
*/
@Configuration
@ComponentScan(basePackages = "com.bie")
public class RabbitMQConfig { /**
* 将ConnectionFactory注入到bean容器中
*
* @return
*/
@Bean
public ConnectionFactory connectionFactory() {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
connectionFactory.setAddresses("192.168.110.133:5672");
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
connectionFactory.setVirtualHost("/");
return connectionFactory;
} /**
* 参数依赖上面注入的ConnectionFactory类,所以保持参数名称和注入的ConnectionFactory一致
*
* @param connectionFactory
* @return
*/
@Bean
public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory) {
RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
// 注意:autoStartup必须设置为true,否则Spring容器不会加载RabbitAdmin类。
rabbitAdmin.setAutoStartup(true);
return rabbitAdmin;
} // 使用SpringAMQP去声明,就需要使用SpringAMQP的如下模式,即声明@Bean方式。
// SpringAMQP-RabbitMQ声明式配置使用 /**
* 针对消费者配置:
*
* 1. 设置交换机类型。
*
* 2. 将队列绑定到交换机。
*
* FanoutExchange: 将消息分发到所有的绑定队列,无routingkey的概念。
*
* HeadersExchange :通过添加属性key-value匹配。
*
* DirectExchange:按照routingkey分发到指定队列。
*
* TopicExchange:多关键字匹配。
*/
@Bean
public TopicExchange topicExchange001() {
return new TopicExchange("topic001", true, false);
} @Bean
public Queue queue001() {
return new Queue("queue001", true);// 队列持久化
} @Bean
public Binding bingding001() {
return BindingBuilder.bind(queue001()).to(topicExchange001()).with("spring.*");
} // 第二个交换机通过路由键绑定到队列上面。
@Bean
public TopicExchange topicExchange002() {
return new TopicExchange("topic002", true, false);
} @Bean
public Queue queue002() {
return new Queue("queue002", true);// 队列持久化
} @Bean
public Binding bingding002() {
return BindingBuilder.bind(queue002()).to(topicExchange002()).with("rabbit.*");
} // 第三个,队列通过路由键绑定到第一个队列上面,即第一个交换机绑定了两个队列。
@Bean
public Queue queue003() {
return new Queue("queue003", true);// 队列持久化
} @Bean
public Binding bingding003() {
return BindingBuilder.bind(queue003()).to(topicExchange001()).with("mq.*");
} @Bean
public Queue queue_image() {
return new Queue("image_queue", true); // 队列持久
} @Bean
public Queue queue_pdf() {
return new Queue("pdf_queue", true); // 队列持久
} }

4、RabbitTemplate,即消息模板,我们在与SpringAMQP整合的时候进行发送消息的关键类。该类提供了丰富的发送消息方法,包括可靠性投递消息方法,回调监听消息接口ConfirmCallback,返回值确认ReturnCallBack等等。同样我们需要进行注入到Spring容器中,然后直接使用。在与Spring整合的时候需要实例化,但是在与SpringBoot整合的时候,在配置文件里面添加配置即可。

 package com.bie;

 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.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration; /**
*
* @author biehl
*
*/
@Configuration
@ComponentScan(basePackages = "com.bie")
public class RabbitMQConfig { /**
* 将ConnectionFactory注入到bean容器中
*
* @return
*/
@Bean
public ConnectionFactory connectionFactory() {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
connectionFactory.setAddresses("192.168.110.133:5672");
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
connectionFactory.setVirtualHost("/");
return connectionFactory;
} /**
* 参数依赖上面注入的ConnectionFactory类,所以保持参数名称和注入的ConnectionFactory一致
*
* @param connectionFactory
* @return
*/
@Bean
public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory) {
RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
// 注意:autoStartup必须设置为true,否则Spring容器不会加载RabbitAdmin类。
rabbitAdmin.setAutoStartup(true);
return rabbitAdmin;
} // 使用SpringAMQP去声明,就需要使用SpringAMQP的如下模式,即声明@Bean方式。
// SpringAMQP-RabbitMQ声明式配置使用 /**
* 针对消费者配置:
*
* 1. 设置交换机类型。
*
* 2. 将队列绑定到交换机。
*
* FanoutExchange: 将消息分发到所有的绑定队列,无routingkey的概念。
*
* HeadersExchange :通过添加属性key-value匹配。
*
* DirectExchange:按照routingkey分发到指定队列。
*
* TopicExchange:多关键字匹配。
*/
@Bean
public TopicExchange topicExchange001() {
return new TopicExchange("topic001", true, false);
} @Bean
public Queue queue001() {
return new Queue("queue001", true);// 队列持久化
} @Bean
public Binding bingding001() {
return BindingBuilder.bind(queue001()).to(topicExchange001()).with("spring.*");
} // 第二个交换机通过路由键绑定到队列上面。
@Bean
public TopicExchange topicExchange002() {
return new TopicExchange("topic002", true, false);
} @Bean
public Queue queue002() {
return new Queue("queue002", true);// 队列持久化
} @Bean
public Binding bingding002() {
return BindingBuilder.bind(queue002()).to(topicExchange002()).with("rabbit.*");
} // 第三个,队列通过路由键绑定到第一个队列上面,即第一个交换机绑定了两个队列。
@Bean
public Queue queue003() {
return new Queue("queue003", true);// 队列持久化
} @Bean
public Binding bingding003() {
return BindingBuilder.bind(queue003()).to(topicExchange001()).with("mq.*");
} @Bean
public Queue queue_image() {
return new Queue("image_queue", true); // 队列持久
} @Bean
public Queue queue_pdf() {
return new Queue("pdf_queue", true); // 队列持久
} // RabbitTemplate,即消息模板,我们在与SpringAMQP整合的时候进行发送消息的关键类。
// 该类提供了丰富的发送消息方法,包括可靠性投递消息方法,回调监听消息接口ConfirmCallback,
// 返回值确认ReturnCallBack等等。同样我们需要进行注入到Spring容器中,然后直接使用。
// 将RabbitTemplate加入到Spring容器中
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
return rabbitTemplate;
} }

使用RabbittEmplate发送消息的案例,由于结合初始化配置文件创建的交换机,队列以及交换机和队列的绑定,将消息发送到自己创建的交换机,队列上面,所以效果请自己仔细查看,如下所示:

 package com.bie;

 import java.util.HashMap;

 import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.FanoutExchange;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner; /**
*
* @author biehl
*
*/
@SpringBootTest
@RunWith(SpringRunner.class)
public class RabbitmqSpringApplicationTests { // 发送消息
@Autowired
private RabbitTemplate rabbitTemplate; @Test
public void sendMessage() {
// 1、创建消息
MessageProperties messageProperties = new MessageProperties();
messageProperties.getHeaders().put("desc", "消息描述");
messageProperties.getHeaders().put("type", "消息类型");
Message message = new Message("hello RabbitMQ".getBytes(), messageProperties); // 2、发送消息
String exchange = "topic001";
String routingKey = "spring.amqp";
rabbitTemplate.convertAndSend(exchange, routingKey, message, new MessagePostProcessor() { @Override
public Message postProcessMessage(Message message) throws AmqpException {
System.out.println("======添加额外的设置======");
message.getMessageProperties().getHeaders().put("desc", "额外的消息描述");
message.getMessageProperties().getHeaders().put("attr", "额外的属性");
return message;
}
});
} @Test
public void sendMessage2() throws Exception {
// 1 创建消息
MessageProperties messageProperties = new MessageProperties();
messageProperties.setContentType("text/plain");
Message message = new Message("RabbitMQ的消息.......".getBytes(), messageProperties); // 2、发送消息
rabbitTemplate.send("topic001", "spring.abc", message); rabbitTemplate.convertAndSend("topic001", "spring.amqp", "hello object message send!");
rabbitTemplate.convertAndSend("topic002", "rabbit.abc", "hello object message send!");
} }

运行效果如下所示:

RabbitMQ与Spring的框架整合之Spring AMQP实战

5、SpringAMQP消息容器SimpleMessageListenerContainer。

  1)、简单消息监听器,这个类非常的强大,我们可以对他进行很多设置,对于消费者的设置项,这个类都可以满足。可以监听队列(多个队列),自动启动,自动声明功能。可以设置事务特性、事务管理器、事务属性、事务容量(并发)、是否开启事务、回滚消息等等。可以设置消费者数量、最小最大数量、批量消费等等。可以设置消息确认和自动确认模式,是否重回队列、异常捕获handler函数。可以设置消费者标签生成策略,是否独占模式,消费者属性等等。可以设置具体的监听器、消息转换器等等。
  2)、注意,SpringAMQP消息容器SimpleMessageListenerContainer可以进行动态设置,比如在运行中的应用可以动态的修改其消费者数量的大小,接收消息的模式等等。很多基于RabbitMQ的自制定化后端控制台在进行动态设置的时候,也是根据这一特性实现的。

 package com.bie;

 import java.util.UUID;

 import org.springframework.amqp.core.AcknowledgeMode;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter;
import org.springframework.amqp.rabbit.listener.api.ChannelAwareMessageListener;
import org.springframework.amqp.support.ConsumerTagStrategy;
import org.springframework.amqp.support.converter.ContentTypeDelegatingMessageConverter;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration; import com.bie.adapter.MessageDelegate;
import com.bie.convert.ImageMessageConverter;
import com.bie.convert.PDFMessageConverter;
import com.bie.convert.TextMessageConverter;
import com.rabbitmq.client.Channel; /**
*
* @author biehl
*
*/
@Configuration
@ComponentScan(basePackages = "com.bie")
public class RabbitMQConfig { /**
* 将ConnectionFactory注入到bean容器中
*
* @return
*/
@Bean
public ConnectionFactory connectionFactory() {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
connectionFactory.setAddresses("192.168.110.133:5672");
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
connectionFactory.setVirtualHost("/");
return connectionFactory;
} /**
* 参数依赖上面注入的ConnectionFactory类,所以保持参数名称和注入的ConnectionFactory一致
*
* @param connectionFactory
* @return
*/
@Bean
public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory) {
RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory);
// 注意:autoStartup必须设置为true,否则Spring容器不会加载RabbitAdmin类。
rabbitAdmin.setAutoStartup(true);
return rabbitAdmin;
} // 使用SpringAMQP去声明,就需要使用SpringAMQP的如下模式,即声明@Bean方式。
// SpringAMQP-RabbitMQ声明式配置使用 /**
* 针对消费者配置:
*
* 1. 设置交换机类型。
*
* 2. 将队列绑定到交换机。
*
* FanoutExchange: 将消息分发到所有的绑定队列,无routingkey的概念。
*
* HeadersExchange :通过添加属性key-value匹配。
*
* DirectExchange:按照routingkey分发到指定队列。
*
* TopicExchange:多关键字匹配。
*/
@Bean
public TopicExchange topicExchange001() {
return new TopicExchange("topic001", true, false);
} @Bean
public Queue queue001() {
return new Queue("queue001", true);// 队列持久化
} @Bean
public Binding bingding001() {
return BindingBuilder.bind(queue001()).to(topicExchange001()).with("spring.*");
} // 第二个交换机通过路由键绑定到队列上面。
@Bean
public TopicExchange topicExchange002() {
return new TopicExchange("topic002", true, false);
} @Bean
public Queue queue002() {
return new Queue("queue002", true);// 队列持久化
} @Bean
public Binding bingding002() {
return BindingBuilder.bind(queue002()).to(topicExchange002()).with("rabbit.*");
} // 第三个,队列通过路由键绑定到第一个队列上面,即第一个交换机绑定了两个队列。
@Bean
public Queue queue003() {
return new Queue("queue003", true);// 队列持久化
} @Bean
public Binding bingding003() {
return BindingBuilder.bind(queue003()).to(topicExchange001()).with("mq.*");
} @Bean
public Queue queue_image() {
return new Queue("image_queue", true); // 队列持久
} @Bean
public Queue queue_pdf() {
return new Queue("pdf_queue", true); // 队列持久
} // RabbitTemplate,即消息模板,我们在与SpringAMQP整合的时候进行发送消息的关键类。
// 该类提供了丰富的发送消息方法,包括可靠性投递消息方法,回调监听消息接口ConfirmCallback,
// 返回值确认ReturnCallBack等等。同样我们需要进行注入到Spring容器中,然后直接使用。
// 将RabbitTemplate加入到Spring容器中
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
return rabbitTemplate;
} /**
*
* @param connectionFactory
* @return
*/
@Bean
public SimpleMessageListenerContainer messageListenerContainer(ConnectionFactory connectionFactory) {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory);
// 监听的队列,可变参数,可以添加多个队列。
container.setQueues(queue001(), queue002(), queue003(), queue_image(), queue_pdf());
// 设置消费者个数。
container.setConcurrentConsumers();
// 设置最大消费者个数。
container.setMaxConcurrentConsumers();
// 设置默认是否重回队列。
container.setDefaultRequeueRejected(false);
// 设置签收模式,自动签收。
container.setAcknowledgeMode(AcknowledgeMode.AUTO);
// 设置是否外露
container.setExposeListenerChannel(true);
// 设置标签策略。
container.setConsumerTagStrategy(new ConsumerTagStrategy() {
@Override
public String createConsumerTag(String queue) {
return queue + "_" + UUID.randomUUID().toString();
}
}); // 监听消息
container.setMessageListener(new ChannelAwareMessageListener() { @Override
public void onMessage(Message message, Channel channel) throws Exception {
String msg = new String(message.getBody());
System.out.println("===========================消费者消息msg : " + msg);
}
}); return container;
} }

可以直接在测试类里面进行启动,直接启动测试方法sendMessage2,如下所示:

 package com.bie;

 import java.util.HashMap;

 import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.FanoutExchange;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner; /**
*
* @author biehl
*
*/
@SpringBootTest
@RunWith(SpringRunner.class)
public class RabbitmqSpringApplicationTests { @Autowired
private RabbitAdmin rabbitAdmin; @Test
public void rabbitmqAdmin() {
// 参数1交换机名称, 参数1是否持久化durable, 参数3是否自动删除 autoDelete
// 创建direct类型的交换机
DirectExchange directExchange = new DirectExchange("test.directExchange", false, false);
rabbitAdmin.declareExchange(directExchange); // 创建topic类型的交换机
TopicExchange topicExchange = new TopicExchange("test.topicExchange", false, false);
rabbitAdmin.declareExchange(topicExchange); // 创建fanout类型的交换机
FanoutExchange fanoutExchange = new FanoutExchange("test.fanoutExchange", false, false);
rabbitAdmin.declareExchange(fanoutExchange); // 创建direct类型的队列
Queue directQueue = new Queue("test.direct.queue", false);
rabbitAdmin.declareQueue(directQueue); // 创建topic类型的交队列
Queue topicQueue = new Queue("test.topic.queue", false);
rabbitAdmin.declareQueue(topicQueue); // 创建fanout类型的队列
Queue fanoutQueue = new Queue("test.fanout.queue", false);
rabbitAdmin.declareQueue(fanoutQueue); // 声明绑定
// 参数1 String destination,可以认为是具体的队列。
// 参数2 DestinationType destinationType,绑定的类型。
// 参数3 String exchange,交换机的名称。
// 参数4 String routingKey,路由键的名称。
// 参数5 Map<String, Object> arguments可以传入的参数。
// 将test.directExchange交换机和test.direct.queue队列进行绑定
rabbitAdmin.declareBinding(new Binding("test.direct.queue", Binding.DestinationType.QUEUE,
"test.directExchange", "direct", new HashMap<>())); // 将test.topicExchange交换机和test.topic.queue队列进行绑定
// rabbitAdmin.declareBinding(new Binding("test.topic.queue",
// Binding.DestinationType.QUEUE, "test.topicExchange",
// "topic", new HashMap<>()));
rabbitAdmin.declareBinding(BindingBuilder.bind(new Queue("test.topic.queue", false)) // 直接创建队列
.to(new TopicExchange("test.topicExchange", false, false)) // 直接创建交换机 建立关联关系
.with("user.#")); // 指定路由Key // 将test.fanoutExchange交换机和test.fanout.queue队列进行绑定
// rabbitAdmin.declareBinding(new Binding("test.fanout.queue",
// Binding.DestinationType.QUEUE,
// "test.fanoutExchange", "", new HashMap<>())); rabbitAdmin.declareBinding(BindingBuilder.bind(new Queue("test.fanout.queue", false)) // 直接创建队列
.to(new FanoutExchange("test.fanoutExchange", false, false))); // 直接创建交换机 建立关联关系 // 清空队列数据
rabbitAdmin.purgeQueue("test.direct.queue", false);
rabbitAdmin.purgeQueue("test.topic.queue", false);
rabbitAdmin.purgeQueue("test.fanout.queue", false);
} // 发送消息
@Autowired
private RabbitTemplate rabbitTemplate; @Test
public void sendMessage() {
// 1、创建消息
MessageProperties messageProperties = new MessageProperties();
messageProperties.getHeaders().put("desc", "消息描述");
messageProperties.getHeaders().put("type", "消息类型");
Message message = new Message("hello RabbitMQ".getBytes(), messageProperties); // 2、发送消息
String exchange = "topic001";
String routingKey = "spring.amqp";
rabbitTemplate.convertAndSend(exchange, routingKey, message, new MessagePostProcessor() { @Override
public Message postProcessMessage(Message message) throws AmqpException {
System.out.println("======添加额外的设置======");
message.getMessageProperties().getHeaders().put("desc", "额外的消息描述");
message.getMessageProperties().getHeaders().put("attr", "额外的属性");
return message;
}
});
} @Test
public void sendMessage2() throws Exception {
// 1 创建消息
MessageProperties messageProperties = new MessageProperties();
messageProperties.setContentType("text/plain");
Message message = new Message("RabbitMQ的消息.......".getBytes(), messageProperties); // 2、发送消息
rabbitTemplate.send("topic001", "spring.abc", message); rabbitTemplate.convertAndSend("topic001", "spring.amqp", "hello object message send!");
rabbitTemplate.convertAndSend("topic002", "rabbit.abc", "hello object message send!");
} }

SpringAMQP消息容器SimpleMessageListenerContainer,简单消息监听器,效果如下所示:

RabbitMQ与Spring的框架整合之Spring AMQP实战

aaarticlea/jpeg;base64,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" alt="" />

作者:别先生

博客园:https://www.cnblogs.com/biehongli/

如果您想及时得到个人撰写文章以及著作的消息推送,可以扫描上方二维码,关注个人公众号哦。

上一篇:智能车学习(十一)——陀螺仪学习


下一篇:RabbitMQ 保证消息不丢失