配置并使用阿里云服务的消息队列RabbitMQ消息中间件

RabbitMQ简介

MQ全称是Message Queue,可以理解为消息队列的意思,简单来说就是消息以管道的方式进行传递,RabbitMQ是一个实现了AMQP(Advanced Message Queuing Protocol)高级消息队列协议的消息队列服务,用Erlang语言的。

使用阿里云rabbitmq的优势

相比自己手动linux系统搭建rabbitmq, 使用阿里云提供的rabbitmq可免去Linux安装的各种流程,直接在阿里控制台配置路由交换机队列,更为方便,且只需将工作重心放到代码逻辑编写上来,更为方便快捷。免去系统安全性mq稳定性等等操作。

使用场景

电商平台预支付订单延迟付款操作,用户下单后五分钟内需付款,若用户各种情况未付款的话,则自动取消预支付订单,则执行将库存等数据返回数据库等操作。

代码逻辑中的各种异步操作,将必须执行但可异步延迟执行的逻辑放到队列里面。通过交换机路由分发至对应的队列执行逻辑操作。

在我们秒杀抢购商品的时候,系统会提醒我们稍等排队中,而不是像几年前一样页面卡死或报错给用户。像这种排队结算就用到了消息队列机制,放入通道里面一个一个结算处理,而不是某个时间断突然涌入大批量的查询新增把数据库给搞宕机,所以RabbitMQ本质上起到的作用就是削峰填谷,为业务保驾护航。

ConnectionFactory(连接管理器):应用程序与Rabbit之间建立连接的管理器,程序代码中使用;

Channel(信道):消息推送使用的通道;

Exchange(交换器):用于接受、分配消息;

Queue(队列):用于存储生产者的消息;

RoutingKey(路由键):用于把生成者的数据分配到交换器上;

BindingKey(绑定键):用于把交换器的消息绑定到队列上;


实际操作:

进入阿里云服务器mq管理控制台界面:

 

实例ID, 代理接入点url,AK管理(用户名和密码) 等信息在代码中配置文件会用到。

点击左边导航栏vhost,在对应实例下创建一个vhost

然后我们点击左边Exchange管理创建路由,路由的类型有如下几种:

fanout:该类型路由规则非常简单,会把所有发送到该Exchange的消息路由到所有与它绑定的Queue中,相当于广播功能。

topic:与direct类型相似,只是规则没有那么严格,可以模糊匹配和多条件匹配。

direct:该类型路由规则会将消息路由到Bindingkey与Routingkey完全匹配的Queue中。

 

headers:该类型与direct类型相似,只是Headers Exchange使用Headers属性代替Routing Key进行路由匹配,在绑定Headers Exchange和Queue时,设置绑定属性的键值对;在向Headers Exchange发送消息时,设置消息的Headers属性键值对,使用消息Headers属性键值对和绑定属性键值对比较的方式将消息路由至绑定的Queue。

x-jms-topic:适用于通过消息队列RabbitMQ版提供的JMS接口接入消息队列RabbitMQ版的JMS应用,该类型路由规则会将消息路由到Binding Key与Routing Key通配符匹配的Queue中。

我们创建一个常用的fanout广播类型路由当示例,  名称叫aaa

还可以自定义创建死信延迟队列及路由(也挺常用,用来处理延迟订单)等,想做的私我。 

路由创建好了我们需要创建一个queue队列,用来接收从exchange路由中分配匹配而来的消息,将消息按顺序放到匹配的队列中,执行对应的代码逻辑处理。 queue名称就叫bbb

接下来我们需要将创建的queue队列和 exchange路由绑定在一起,需要用到自定义的Bingkey。

如图绑定即可。

到这里我们控制台的操作基本就弄完了,接下来我们开始配置代码中的配置文件。

java代码示例,首先在pom文件中导入依赖

        <dependency>
            <groupId>com.rabbitmq</groupId>
            <artifactId>amqp-client</artifactId>
            <version>5.5.0</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba.mq-amqp</groupId>
            <artifactId>mq-amqp-client</artifactId>
            <version>1.0.5</version>
        </dependency>

配置文件

#阿里AMQP 配置
spring.rabbitmq.host=amqp-cn-*****************************aliyuncs.com
spring.rabbitmq.port=5672
spring.rabbitmq.username=**************
spring.rabbitmq.password=***********
spring.rabbitmq.virtual-host=*********
# 触发returnedMessage回调必须设置mandatory=true, 否则Exchange没有找到Queue就会丢弃掉消息, 而不会触发回调
spring.rabbitmq.template.mandatory=true
# 是否启用【发布确认】
spring.rabbitmq.publisher-confirms=true 
# 是否启用【发布返回】
spring.rabbitmq.publisher-returns=true
#消费者消费失败,自动重新入队
# spring.rabbitmq.listener.simple.default-requeue-rejected=true

#消息推送相关创建路由
aaa=aaa #路由
bbb=bbb #队列
aaabbb-key=aaabbb-key #Bingkey

 

然后将官方提供的工具类代码导入项目中

package com.*********.rabbitmq;

import com.alibaba.mq.amqp.utils.UserUtils;
import com.rabbitmq.client.impl.CredentialsProvider;
import org.apache.commons.lang3.StringUtils;

import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

/**
 * 阿里云 UserName、Password 生成类(动态变化)
 */
public class AliyunCredentialsProvider implements CredentialsProvider {
    /**
     * Access Key ID.
     */
    private final String accessKeyId;
    /**
     * Access Key Secret.
     */
    private final String accessKeySecret;
    /**
     * security temp token. (optional)
     */
    private final String securityToken;
    /**
     * 实例 id(从阿里云 AMQP 版控制台获取)
     */
    private final String instanceId;
    public AliyunCredentialsProvider(final String accessKeyId, final String accessKeySecret,
                                     final String instanceId) {
        this(accessKeyId, accessKeySecret, null, instanceId);
    }
    public AliyunCredentialsProvider(final String accessKeyId, final String accessKeySecret,
                                     final String securityToken, final String instanceId) {
        this.accessKeyId = accessKeyId;
        this.accessKeySecret = accessKeySecret;
        this.securityToken = securityToken;
        this.instanceId = instanceId;
    }
    @Override
    public String getUsername() {
        if(StringUtils.isNotEmpty(securityToken)) {
            return UserUtils.getUserName(accessKeyId, instanceId, securityToken);
        } else {
            return UserUtils.getUserName(accessKeyId, instanceId);
        }
    }

    @Override
    public String getPassword() {
        try {
            return UserUtils.getPassord(accessKeySecret);
        } catch (InvalidKeyException e) {
            //todo
        } catch (NoSuchAlgorithmException e) {
            //todo
        }
        return null;
    }
}
package com.************.rabbitmq;

import com.jianlet.constant.Configure;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.boot.autoconfigure.amqp.RabbitProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.Resource;

@Configuration
public class RabbitConfig {

    @Resource
    private RabbitProperties rabbitProperties;

    @Bean
    public ConnectionFactory getConnectionFactory() {
        com.rabbitmq.client.ConnectionFactory rabbitConnectionFactory =
                new com.rabbitmq.client.ConnectionFactory();
        rabbitConnectionFactory.setHost(rabbitProperties.getHost());
        rabbitConnectionFactory.setPort(rabbitProperties.getPort());
        rabbitConnectionFactory.setVirtualHost(rabbitProperties.getVirtualHost());

        AliyunCredentialsProvider credentialsProvider = new AliyunCredentialsProvider(
                rabbitProperties.getUsername(), rabbitProperties.getPassword(), Configure.getInstanceId());
        rabbitConnectionFactory.setCredentialsProvider(credentialsProvider);
        rabbitConnectionFactory.setAutomaticRecoveryEnabled(true);
        rabbitConnectionFactory.setNetworkRecoveryInterval(5000);
        ConnectionFactory connectionFactory = new CachingConnectionFactory(rabbitConnectionFactory);
        ((CachingConnectionFactory)connectionFactory).setPublisherConfirms(rabbitProperties.isPublisherConfirms());
        ((CachingConnectionFactory)connectionFactory).setPublisherReturns(rabbitProperties.isPublisherReturns());
        return connectionFactory;
    }
}
package com.****.rabbitmq;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;


/**
 * 生产者端将消息发送出去,消息到达RabbitMQ之后,会返回一个到达确认。
 * 这个确认实际上就是官方常说的ConfirmCallback,我们通过在生产者端使用一个回调类来监听RabbiMQ返回的消息确认。
 * Spring AMQP中我们通过设置RabbitTemplate的ConfirmCallback属性来实现消息确认回调,通过一个实现了ConfirmCallback的类来实现回调逻辑。
 */
public class RabbitConfirmCallback implements RabbitTemplate.ConfirmCallback {

    Logger log= LoggerFactory.getLogger(RabbitConfirmCallback.class);
    @Override
    public void confirm(CorrelationData correlationData, boolean ack, String cause) {
        log.info("MessageConfirm correlationData:"+correlationData+",ack:"+ack+",cause:"+cause);
    }
}
package com.**********.rabbitmq;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.core.RabbitTemplate;

/**
 * 设置 ReturnCallback 回调
 * 如果发送到交换器成功,但是没有匹配的队列,就会触发这个回调   在ConfirmCallback之前执行
 */
public class RabbitReturnCallback implements RabbitTemplate.ReturnCallback {

    Logger log= LoggerFactory.getLogger(RabbitReturnCallback.class);
    @Override
    public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
        log.info("message return message:"+message+",replyCode:"+replyCode+",replyText:"+replyText+",exchange:"+exchange+",routingKey:"+routingKey);
    }
}
package com.*********.rabbitmq;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;


@Component
public class SenderWithCallback {
    Logger log= LoggerFactory.getLogger(SenderWithCallback.class);
    @Resource
    private  RabbitTemplate rabbitTemplate;

    @PostConstruct
    public void initRabbitTemplate() {
        // 设置生产者消息确认
        rabbitTemplate.setConfirmCallback(new RabbitConfirmCallback());
        rabbitTemplate.setReturnCallback(new RabbitReturnCallback());
    }
}

在代码逻辑中创建消息发送者,将消息发送至路由交换机,接着由交换机匹配至对应的队列执行你要处理的代码操作。 注意这里创建的发送者这几行代码是异步操作,所以即使报错也不会影响正常流程。

    @Resource
    private RabbitTemplate rabbitTemplate;

    @RequestMapping(value = "/rabbitmqtest")
    @ResponseBody
    public void rabbitmqtest(@RequestParam Map<String, Object> map) {
        rabbitTemplate.convertAndSend(env.getProperty("aaa"), 
           env.getProperty("aaa-bbb-key"),"你要发送的String类型数据,会在消息接收者里接收,然后进行后续逻辑判断",
           new CorrelationData("unRouting-" + UUID.randomUUID().toString()));
    }

创建消息接收者,用来接收消息处理异步逻辑

package com.*;
@Component
public class RabbitmqPeceiver {
    @RabbitListener(queues = "${bbb}")
    public void process(String msg) {
        JSONObject jsonObject = JSONObject.parseObject(msg);
        //获取需要的参数进行你的逻辑处理

    }
}

到这儿大致的主要流程就创建完了,基本的流程操作就这些,如果不行的话私我。

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
阿里云是一家知名的云计算服务提供商,提供了丰富的云产品和解决方案。RabbitMQ是一个开源的消息队列中间件,用于在分布式系统中进行消息传递。下面是在阿里云Linux服务器上部署RabbitMQ的步骤: 1. 登录阿里云控制台,创建一台Linux服务器实例,并确保已经打开了相关端口(例如5672和15672)。 2. 使用SSH工具连接到Linux服务器。 3. 在服务器上安装Erlang运行时环境,RabbitMQ依赖于Erlang。可以使用以下命令安装Erlang: ``` sudo apt-get update sudo apt-get install erlang ``` 4. 添加RabbitMQ的APT存储库到服务器的源列表中。可以使用以下命令: ``` echo 'deb http://www.rabbitmq.com/debian/ testing main' | sudo tee /etc/apt/sources.list.d/rabbitmq.list ``` 5. 导入RabbitMQ的公钥,以确保软件包的完整性。可以使用以下命令: ``` wget -O- https://www.rabbitmq.com/rabbitmq-release-signing-key.asc | sudo apt-key add - ``` 6. 更新软件包列表并安装RabbitMQ。可以使用以下命令: ``` sudo apt-get update sudo apt-get install rabbitmq-server ``` 7. 启动RabbitMQ服务。可以使用以下命令: ``` sudo service rabbitmq-server start ``` 8. 验证RabbitMQ服务是否已经成功启动。可以使用以下命令: ``` sudo service rabbitmq-server status ``` 9. 配置RabbitMQ的管理界面。可以使用以下命令: ``` sudo rabbitmq-plugins enable rabbitmq_management ``` 10. 重启RabbitMQ服务以使配置生效。可以使用以下命令: ``` sudo service rabbitmq-server restart ``` 11. 现在可以通过浏览器访问RabbitMQ的管理界面,使用服务器的IP地址和默认端口15672进行访问。例如:http://服务器IP地址:15672/ 12. 使用默认的用户名和密码(guest/guest)登录到RabbitMQ管理界面。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值