消息中间件RabbitMQ

RabbitMQ

Posted by 王明高 on December 3, 2019

1 RabbitMQ 安装与启动

  • 下载并安装 Eralng(以管理员身份运行安装)

    https://www.erlang.org/downloads

  • 下载并安装rabbitmq

    https://www.rabbitmq.com/download.html

    双击安装,注意不要安装在包含中文和 空格的目录下!安装后window服务中就存在rabbitMQ了,并且是启动状态。

  • 安装管理界面(插件)

    进入rabbitMQ安装目录的sbin目录,输入命令

    rabbitmq‐plugins enable rabbitmq_management
    
  • 重新启动服务

  • 打开浏览器,地址栏输入http://127.0.0.1:15672

  • 输入用户名和密码,都为guest 进入主界面:

2 RabbitMQ 三种模式

2.1 直连模式(Direct)

我们需要将消息发给唯一一个节点时使用这种模式,这是最简单的一种形式。

有如下特点:

  • 一般情况可以使用rabbitMQ自带的Exchange:” “(该Exchange的名字为空字符串,下文称其为default Exchange)。
  • 这种模式下不需要将Exchange进行任何绑定(binding)操作
  • 消息传递时需要一个“RouteKey”,可以简单的理解为要发送到的队列名字。
  • 如果vhost中不存在RouteKey中指定的队列名,则该消息会被抛弃。

2.2 分列模式(Fanout)

当我们需要将消息一次发给多个队列时,需要使用这种模式。

有如下特点:

  • 可以理解为路由表的模式
  • 这种模式不需要RouteKey
  • 这种模式需要提前将Exchange与Queue进行绑定,一个Exchange可以绑定多个 Queue,一个Queue可以同多个Exchange进行绑定。
  • 如果接受到消息的Exchange没有与任何Queue绑定,则消息会被抛弃。

2.3 主题模式(Topic)

任何发送到Topic Exchange的消息都会被转发到所有关心RouteKey中指定话题的Queue 上

有如下特点:

  • 这种模式较为复杂,简单来说,就是每个队列都有其关心的主题,所有的消息都带有一 个“标题”(RouteKey),Exchange会将消息转发到所有关注主题能与RouteKey模糊匹配的 队列。
  • 这种模式需要RouteKey,也许要提前绑定Exchange与Queue。
  • 在进行绑定时,要提供一个该队列关心的主题,如“#.log.#”表示该队列关心所有涉及 log的消息(一个RouteKey为”MQ.log.error”的消息会被转发到该队列)。
  • “#”表示0个或若干个关键字,“”表示一个关键字。如“log.”能与“log.warn”匹配,无法 与“log.warn.timeout”匹配;但是“log.#”能与上述两者匹配。
  • 同样,如果Exchange没有发现能够与RouteKey匹配的Queue,则会抛弃此消息

3 RabbitMQ 使用场景

  • 用户注册,发送手机验证码,先存入Redis并再发送到RabbitMQ。
  • 订单生成后手机短信通知、物流安排等。

4 RabbitMQ 代码实现

4.1 用户服务实现

4.1.1 引入redis和amqp依赖

...
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring‐boot‐starter‐data‐redis</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring‐boot‐starter‐amqp</artifactId>
</dependency>
...

4.1.2 修改application.yml

...
spring:
	redis:
		host: 192.168.184.134
	rabbitmq:
    	host: 192.168.184.134
...    	

4.1.3 UserService中新增方法,用于发送短信验证码

...
public class UserService{
    
    ...
    
    @Autowired
    private RedisTemplate redisTemplate;
    
    @Autowired
    private RabbitTemplate rabbitTemplate;
    
    ...
    
    /**
     * 发送短信验证码
     * @param mobile 手机号
     */
    public void sendSms(String mobile){
    	//1.生成6位短信验证码
        Random random=new Random();
        int max=999999;//最大数
        int min=100000;//最小数
        int code = random.nextInt(max);//随机生成
        if(code<min){
            code=code+min;
        }
        System.out.println(mobile+"收到验证码是:"+code);
        //2.将验证码放入redis
        redisTemplate.opsForValue().set("smscode_"+mobile, code+"" ,5,TimeUnit.MINUTES );//五分钟过期
        //3.将验证码和手机号发动到rabbitMQ中
        Map<String,String> map=new HashMap();
        map.put("mobile",mobile);
        map.put("code",code+"");
        rabbitTemplate.convertAndSend("sms",map);
    }
    
    /**
     * 增加
     * @param user 用户
     * @param code 用户填写的验证码
     */
    public void add(User user,String code) {
        //判断验证码是否正确
        String syscode = (String)redisTemplate.opsForValue().get("smscode_" + user.getMobile());
        //提取系统正确的验证码
        if(syscode==null){
            throw new RuntimeException("请点击获取短信验证码");
        }
        if(!syscode.equals(code)){
            throw new RuntimeException("验证码输入不正确");
        }
        user.setId(idWorker.nextId()+"");
        user.setFollowcount(0);//关注数
        user.setFanscount(0);//粉丝数
        ...
        userDao.save(user);
    }
    ...
}

4.2 消息服务实现

4.2.1 引入amqp依赖

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

4.2.1 修改application.yml

...
spring:
	rabbitmq:
    	host: 192.168.184.134
...    	

4.3 消息监听类

/**
 * 短信监听类
 */
@Component
@RabbitListener(queues = "sms")
public class SmsListener {
   
    /**
     * 发送短信
     * @param message
     */
    @RabbitHandler
    public void sendSms(Map<String,String> message){
        System.out.println("手机号:"+message.get("mobile"));
        System.out.println("手机号:"+message.get("mobile"));
        //调用阿里云通讯接口
        ...
    }
}