SpringBoot整合RabbitMQ

(一)RabbitMQ自动配置原理

RabbitAutoConfiguration类可以看到其自动配置的实现,主要分为以下四步。

  1. 使用CachingConnectionFactory连接工厂建立连接。
@Bean
public CachingConnectionFactory rabbitConnectionFactory(RabbitProperties config) throws Exception {
	RabbitConnectionFactoryBean factory = new RabbitConnectionFactoryBean();
	if (config.determineHost() != null) {
	    factory.setHost(config.determineHost());
	}
	
	factory.setPort(config.determinePort());
	if (config.determineUsername() != null) {
	    factory.setUsername(config.determineUsername());
	}
	...
  1. 配置连接信息,比如host,username等都封装在RabbitProperties类中,RabbitProperties实际上是绑定了application配置文件中以spring.rabbitmq为前缀的配置。
ConfigurationProperties(
    prefix = "spring.rabbitmq"
)
public class RabbitProperties {
    private String host = "localhost";
    private int port = 5672;
    ...
  1. 使用RabbitTemplate向RabbitMq发送或接受消息。
@Bean
@ConditionalOnSingleCandidate(ConnectionFactory.class)
@ConditionalOnMissingBean({RabbitTemplate.class})
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
    RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
    MessageConverter messageConverter = (MessageConverter)this.messageConverter.getIfUnique();
    if (messageConverter != null) {
        rabbitTemplate.setMessageConverter(messageConverter);
    }
    ...
  1. 创建AmqpAdmin系统管理功能组件,作用是创建和声明队列,交换器等等。
@ConditionalOnMissingBean({AmqpAdmin.class})
public AmqpAdmin amqpAdmin(ConnectionFactory connectionFactory) {
    return new RabbitAdmin(connectionFactory);
}
...

(二)消息发送

1.RabbitTemplate方式

  1. 创建一个SpringBoot工程,勾选RabbitMQ与Web功能。核心部分依赖如下:
<dependencies>
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-amqpartifactId>
    dependency>
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-webartifactId>
    dependency>

    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-testartifactId>
        <scope>testscope>
    dependency>
dependencies>
  1. 编写配置文件application.properties。
spring.rabbitmq.host=xxx
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
#spring.rabbitmq.virtual-host=可以不填,默认为‘/’
发送方法
  1. 使用RabbitTemplate.send方法发送。(不常用)
public void send(final String exchange, final String routingKey, final Message message, final CorrelationData correlationData) throws AmqpException {
    this.execute(new ChannelCallback<Object>() {
        public Object doInRabbit(Channel channel) throws Exception {
            RabbitTemplate.this.doSend(channel, exchange, routingKey, message, RabbitTemplate.this.returnCallback != null && (Boolean)RabbitTemplate.this.mandatoryExpression.getValue(RabbitTemplate.this.evaluationContext, message, Boolean.class), correlationData);
            return null;
        }
    }, this.obtainTargetConnectionFactory(this.sendConnectionFactorySelectorExpression, message));
}

其中exchange代表交换器,routingKey为路由表,message需要自己构建,是可自定义的消息体内容和消息头。

public Message(byte[] body, MessageProperties messageProperties) {
	this.body = body;
	this.messageProperties = messageProperties;
}
  1. 使用RabbitTemplate.convertAndSend方法发送。(常用)
public void convertAndSend(String exchange, String routingKey, Object object, CorrelationData correlationData) throws AmqpException {
    this.send(exchange, routingKey, this.convertMessageIfNecessary(object), correlationData);
}

object是要发送的对象,RabbitTemplate会将它以默认序列化方式序列化后发送给rabbitmq(默认为SimpleMessageConverter)。本质上与send方法是一致的,只不过调用了this.convertMessageIfNecessary方法对这个object进行转换。
示例
下面是一个单播的测试方法,通过构造一个map对象来存放需要发送的信息,之后使用convertAndSend发送给RabbitMq中匹配路由键的队列。

/**
* 1.单播(点对点)
*/
@Test
public void sendMessage01() {
	Map<String,Object> map = new HashMap<>();
	map.put("msg", "这是第一个信息");
	map.put("data", Arrays.asList("HelloWorld", 123, true));
	rabbitTemplate.convertAndSend("exchange.direct","atguigu.news",map);
}

登录到RabbitMq后台,在绑定了atguigu.news路由键的队列中可以看到序列化后的数据信息。数据信息之所以呈现这种格式是因为使用的是RabbitTemplate默认的序列化方法。

SpringBoot整合RabbitMQ_第1张图片

如果想将数据信息序列化成我们可读的,比如json数据。可以将默认的MessageConverter(消息转换器)切换成jackson2JsonMessageConverter来将数据序列化成json格式。

@Configuration
public class RabbitmqConfig {
    @Bean
    public MessageConverter messageConverter() {
        return new Jackson2JsonMessageConverter();
    }
}

再次发送消息,可以看到在切换消息转换器后,数据已经被序列化为json格式。

SpringBoot整合RabbitMQ_第2张图片
接收方法
  1. 使用RabbitTemplate.receiveAndConvert方法获取指定队列中的消息。
public Object receiveAndConvert(String queueName, long timeoutMillis) throws AmqpException {
	Message response = timeoutMillis == 0L ? this.doReceiveNoWait(queueName) : this.receive(queueName, timeoutMillis);
	return response != null ? this.getRequiredMessageConverter().fromMessage(response) : null;
}

示例
取出上一步发送至RabbitMq队列中的数据信息。

@Autowired
RabbitTemplate rabbitTemplate;

@Test
public void getMessage(){
    Object o = rabbitTemplate.receiveAndConvert("atguigu.news");
    System.out.println(o);
}

可以看到在控制台正常打印了从队列中取得的信息,注:取得的队列中最早接收到的消息。
在这里插入图片描述

2.RabbitListener方式

  1. 首先需要在主配置类中开启基于注解的RabbitMq。
@EnableRabbit
@SpringBootApplication
public class SpringBootRabbitmqTestApplication {
...
  1. 使用SpringBoot提供的@RabbitListener注解监听指定队列,获取我们需要的消息。
@Service
public class BookService {
	@RabbitListener(queues = "队列名")
	public void receive01(Object object){
		System.out.println(object);
	}
	
	@RabbitListener(queues = "atguigu")
    public void receive02(Message message){
        System.out.println(message.getBody());
        System.out.println(message.getMessageProperties());
    }
}

对于一些特殊的需求,message可以用来获得消息头,使用getBodygetMessageProperties来获得消息内容和消息头信息。类似下图所示:

SpringBoot整合RabbitMQ_第3张图片

3.AmqpAdmin方式

在AmqpAdmin类中封装了许多操作交换器,队列的方法。

public interface AmqpAdmin {
    void declareExchange(Exchange var1);

    boolean deleteExchange(String var1);

    Queue declareQueue();

    String declareQueue(Queue var1);

    boolean deleteQueue(String var1);

    void deleteQueue(String var1, boolean var2, boolean var3);

    void purgeQueue(String var1, boolean var2);

    void declareBinding(Binding var1);

    void removeBinding(Binding var1);

    Properties getQueueProperties(String var1);
}
  1. declareExchange方法为列,这个方法可以声明一个交换器,交换器其有多种类型,这里我以DirectExchange为例。
    SpringBoot整合RabbitMQ_第4张图片

示例
创建一个amqpadmin.exchange交换器,再创建一个amqpadmin.queue队列,最后我们将他们用amqp.haha路由键绑定起来,就实现了一个完整消息队列的创建。

@Test
public void createExchange(){
	amqpAdmin.declareExchange(new DirectExchange("amqpadmin.exchange"));
	amqpAdmin.declareQueue(new Queue("amqpadmin.queue"));
	amqpAdmin.declareBinding(new Binding("amqpadmin.queue", Binding.DestinationType.QUEUE,"amqpadmin.exchange","amqp.haha",null));
}

以下是对Binding参数的分析。我们可以看到第一个参数是目标队列或交换器,第二个参数是目标类型,如果为队列则为Binding.DestinationType.QUEUE,第三个参数是交换器名,第四个参数为参数:

public Binding(String destination, Binding.DestinationType destinationType, String exchange, String routingKey, Map<String, Object> arguments) {
    this.destination = destination;
    this.destinationType = destinationType;
    this.exchange = exchange;
    this.routingKey = routingKey;
    this.arguments = arguments;
}

运行测试方法,登录RabbitMq后台可以看到我们创建的队列,交换器和路由键。

SpringBoot整合RabbitMQ_第5张图片

你可能感兴趣的:(SpringBoot)