【Spring】十,Spring Boot整合RabbitMQ

RabbitMQ

RabbitMQ可以说是AMQP最杰出的实现,它提供了比JMS更高级的消息路由策略。JMS消息使用目的地名称来寻址,接收者要从这里检索消息,而AMQP消息使用Exchange和routing key来寻址,这样消息就与接收者要监听的队列解耦了。
在这里插入图片描述
当消息抵达RabbitMQ代理的时候,它会进入为其设置的Exchange上。Exchange负责将它路由到一个或多个队列中,这个过程会根据Exchange的类型、Exchange和队列之间的binding以及消息的routing key进行路由。
这方面有多个不同类型的Exchange,包括以下内容。

  • Default:这是代理创建的特殊Exchange。它会将消息路由至名字与消息routing key相同的队列。所有的队列都会自动绑定至Default Exchange。
  • Direct:如果消息的routing key与队列的binding key相同,那么消息将会路由到该队列上。
  • Topic:如果消息的routing key与队列binding key(可能会包含通配符)匹配,那么消息将会路由到一个或多个这样的队列上。
  • Fanout:不管routing key和binding key是什么,消息都将会路由到所有绑定队列上。
  • Headers:与Topic Exchange类似,只不过要基于消息的头信息进行路由,而不是routing key。
  • Dead letter:捕获所有无法投递(也就是它们无法匹配所有已定义的Exchange和队列的binding关系)的消息。

最简单的Exchange形式是Default和Fanout,因为它们大致对应了JMS中的队列和主题,但是其他的Exchange允许我们定义更加灵活的路由模式。

在Spring Boot中使用RabbitMQ

安装RabbitMQ

通过docker快速安装一个RabbitMQ的实验环境,请查阅相关资料。

引入所需依赖

创建一个Spring Boot 的 web 项目,然后引入所需依赖

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

添加AMQP starter到构建文件中之后,将会触发自动配置功能,这样会为我们创建一个AMQP连接工厂和RabbitTemplate bean,以及其他的一些支撑组件。

配置基本属性

spring:
  rabbitmq:
    host: localhost
    port: 5672
    username: admin
    password: admin
    template:
      # 当没有明确指明exchange和routing-key的时候,会默认使用如下的配置。
      exchange: boot.integrate.rabbit.orders
      routing-key: rk.orders

通过RabbitTemplate发送消息

Spring 对 RabbitMQ 消息支持的核心是 RabbitTemplate。RabbitTemplate 与JmsTemplate类似,提供了一组相似的方法。
RabbitTemplate会按照Exchanges和routing key来发送消息。

// 发送原始的消息
void send(Message message) throws AmqpException;
void send(String routingKey, Message message) throws AmqpException;
void send(String exchange, String routingKey, Message message)
                    throws AmqpException;

// 发送根据对象转换而成的消息
void convertAndSend(Object message) throws AmqpException;
void convertAndSend(String routingKey, Object message)
                    throws AmqpException;
void convertAndSend(String exchange, String routingKey,
                    Object message) throws AmqpException;

// 发送根据对象转换而成的消息并且带有后期处理的功能
void convertAndSend(Object message, MessagePostProcessor mPP)
                    throws AmqpException;
void convertAndSend(String routingKey, Object message,
                    MessagePostProcessor messagePostProcessor)
                    throws AmqpException;
void convertAndSend(String exchange, String routingKey,
                    Object message,
                    MessagePostProcessor messagePostProcessor)
                    throws AmqpException;

前3个send()方法都是发送原始的Message对象。
接下来的3个convertAndSend()方法会接受一个对象,这个对象会在发送之前在幕后转换成Message。
最后的3个convertAndSend()方法与前面的3个方法类似,但是它们还会接受一个MessagePostProcessor对象,这个对象能够在Message发送至代理之前对其进行操作。

没有接受Exchange参数的方法会将消息发送至Default Exchange。与之类似,没有指定routing key的方法会把消息路由至默认的routing key。

示例一

@Service
public class RabbitOrderMessageService implements OrderMessageService {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Override
    public void sendOrderMessage(Order order) {
        MessageConverter converter = rabbitTemplate.getMessageConverter();
        MessageProperties properties = new MessageProperties();
        //设置消息的属性
        properties.setHeader("X_ORDER_SOURCE", "WEB");
        Message message = converter.toMessage(order, properties);
        rabbitTemplate.send(message);
    }

}

示例二

String s = JSON.toJSONString(order);
rabbitTemplate.convertAndSend(s, message -> {
    MessageProperties messageProperties = message.getMessageProperties();
    messageProperties.setHeader("X_ORDER_SOURCE", "WEB");
    return message;
});

接收来自RabbitMQ的消息

接收来自RabbitMQ队列的消息也与JMS没有太大差别。与JMS类似,我们有两个可选方案。

  • 使用RabbitTemplate从队列拉取消息。
  • 将消息推送至带有@RabbitListener注解的方法。

拉取消息

RabbitTemplate提供了多个从队列拉取消息的方法。其中,最有用的方法如下所示:

// 接收消息
Message receive() throws AmqpException;
Message receive(String queueName) throws AmqpException;
Message receive(long timeoutMillis) throws AmqpException;
Message receive(String queueName, long timeoutMillis) throws AmqpException;

// 接收由消息转换而成的对象
Object receiveAndConvert() throws AmqpException;
Object receiveAndConvert(String queueName) throws AmqpException;
Object receiveAndConvert(long timeoutMillis) throws AmqpException;
Object receiveAndConvert(String queueName, long timeoutMillis) throws
     AmqpException;

// 接收由消息转换而成的类型安全的对象
<T> T receiveAndConvert(ParameterizedTypeReference<T> type) throws
     AmqpException;
<T> T receiveAndConvert(String queueName, ParameterizedTypeReference<T> type)
     throws AmqpException;
<T> T receiveAndConvert(long timeoutMillis, ParameterizedTypeReference<T>
     type) throws AmqpException;
<T> T receiveAndConvert(String queueName, long timeoutMillis,
     ParameterizedTypeReference<T> type)
    throws AmqpException;

这些方法对应于前文所述的send()和convertAndSend()方法。send()用于发送原始的Message对象,而receive()则会接收来自队列的原始Message对象。与之类似,receiveAndConvert()接收消息并且在返回之前使用一个消息转换器将它们转换为领域对象。

消费消息的应用本身并不需要关心Exchange和routing key。消费消息的应用只需要知道队列信息就可以了。

你可能会注意到,很多方法都接收一个long类型的参数,用来指定接收消息的超时时间。默认情况下,接收消息的超时时间是0毫秒。也就是说,调用receive()会立即返回,如果没有可用消息,那么返回值是null。这是与JmsTemplate的receive()的一个显著差异。通过传入一个超时时间的值,我们就可以让receive()和receiveAndConvert()阻塞,直到消息抵达或者超时时间过期。但是,即便我们设置了非零的超时时间,在代码中依然要处理null返回值的场景。

示例一
@Slf4j
@Service
public class RabbitOrderMessageService implements OrderMessageService {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Override
    public void receiveOrderMessage() {
        Message message = rabbitTemplate.receive("boot.integrate.rabbit.orders.queue");
        byte[] body = message.getBody();
        String s = new String(body);
        log.info("{}",s);
    }
}
示例二
@Slf4j
@Service
public class RabbitOrderMessageService implements OrderMessageService {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Override
    public void receiveOrderMessage() {
        Object o = rabbitTemplate.receiveAndConvert("boot.integrate.rabbit.orders.queue");
        if (o != null){
            String s = o.toString();
            log.info("{}",s);
        }
    }
}

消息推送

使用监听器处理RabbitMQ的消息

@Slf4j
@Component
public class RabbitOrderMessageListener {

    @RabbitListener(queues = "boot.integrate.rabbit.orders.queue")
    public void receiveOrderMessage(String s){
        log.info("{}",s);
    }

}

完整的示例程序请参考:boot-integrate-rabbitmq

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值