1-RabbitMQ入门Helloworld多模块项目Fanout模式实现生产者消费者模型模拟解耦注册服务

1. 文章内容

​ 本文的目的就是在SpringBoot项目中使用RabbitMQ解耦一个模拟的用户注册服务, 进而熟悉RabbitMQ的Fanout模式.

完整代码仓库地址 GoGoGo>>>

2. 环境搭建(多模块工程)

  • 关键词: JDK1.8 + IDEA + Maven + SpringBoot + RabbitMQ(在腾讯云服务器中)

  • 主模块: rabbitmq

    • 子模块一: producer-server(生产者服务)

    • 子模块二: consumer-server(消费者服务)

2.1 主模块搭建- rabbitmq

创建主模块, 填写项目名, java版本等信息点击Next

主模块创建

选择项目所需依赖Web服务和RabbitMQ支持, 这里我选择的SpringBoot版本是2.5.3, 点击Finish

模块依赖

项目创建成功后我们就可以吧主模块的src目录删除, 简化项目结构

删除Src目录

在主工程中的pom文件中我们需要加入两个标签, model后面需要填入子模块项目名

加入标签

2.2 子模块搭建 - producer-server

鼠标右键主模块 --> New–> Module

子模块创建

再次创建SpringBoot项目, 作为子模块

SpringBoot项目子模块

子模块一般无需勾选任何依赖, 直接点击Finish

在这里插入图片描述

创建好子模块后将子模块pom文件中的parent信息替换为父模块pom文件的信息

在这里插入图片描述

同时在父模块中的Model标签中加入子模块的name

在这里插入图片描述

2.3 子模块搭建 - consumer-server

子模块consumer-server的搭建也和 producer-server的搭建一样, 大家可以跟着上一步操作进行搭建

最后只需要改改两个子模块的端口即可

在这里插入图片描述

当两个子模块服务都能顺利运行就说明我们的多模块搭建成功了

在这里插入图片描述

3. 代码实现 解耦注册服务

3.1 Service实现分析

当我们引入任何消息中间件我们的注册服务应该是这样实现的:

普通service服务

​ 因此我们的程序应该是先 发送短信 --> 再将用户信息入库 --> 最后发送邮件这样串行执行的; 我们发现这样编写注册服务会让我们的register方法耦合, 耗时长, 用户体验差, 而且后期若是要加入微信通知等附属服务又得加代码, 扩展性差; 而且我们可以发现, 其实注册服务的实现只有用户信息入库才是我们的根本目的, 万一邮件服务或者短信服务抛出异常我们的服务回滚会造成注册失败, 得不偿失, 因此我们才需要引入RabbitMQ为我们的程序解耦.

新的架构:

改进的服务

优点: 横向扩扩展, 服务独立, 异步执行

3.2 代码实现

在SpringBoot中应用RabbitMQ的fanout模式很简单

  • 配置连接RabbitMQ信息
  • 编写生产者, 只需进行用户入库的核心任务, 再通过交换机将信息发送到对应的栈中
  • 配置交换机和目标栈的关系, 信息是由特定的交换机发送到指定的栈中的
  • 编写消费者, 短信消费者和邮件消费者自动从对应的栈中获取消息进行消费

在这里插入图片描述

1-配置两个子模块连接信息
#生产者
spring:
  application:
    name: producer
  rabbitmq:
    username: [你的RabbitMQ用户名]
    password:  [你的RabbitMQ用户密码]
    virtual-host: /
    host:  [你的RabbitMQ主机]
    port: 5672

## 消费者
spring:
  application:
    name: producer
  rabbitmq:
    username: [你的RabbitMQ用户名]
    password:  [你的RabbitMQ用户密码]
    virtual-host: /
    host:  [你的RabbitMQ主机]
    port: 5672

特别注意:

  • 远程RabbitMQ服务是否已经启动

  • 远程RabbitMQ服务一定要在云服务器安全组中开发对应的端口 5672

  • 你注册的RabbitMQ用户要赋予响应的权限(administrator)以及允许访问的虚拟端口 /

# 启动rabbitmq
systemctl start rabbitmq-server

# 设置用户角色,分配操作权限
rabbitmqctl set_user_tags jinchange administrator

# 为用户添加资源权限(授予访问虚拟机根节点的所有权限)
rabbitmqctl set_permissions -p / jinchange ".*" ".*" ".*"
  • 若发生连接异常或IO异常请检查以上几点原因
2-生产者代码

注册业务service实现

@Service
public class FanoutRegisterServer {

    @Resource
    private RabbitTemplate rabbitTemplate;

    public void register(String phone, String userInfo) {
        // 1. 将用户信息入库, 完成注册
        System.out.println(phone + " 用户已入库 " + userInfo);
		
        // 2. 将用户信息发送给指定交换机(注册的交换机名, 广播的信息)
        String routingKey = "";// 匹配条件, Fanout模式无需
        rabbitTemplate.convertAndSend(RabbitMQConfig.exchangeName, routingKey, userInfo);
    }
}

交换机和栈的定义及绑定

@Configuration
public class RabbitMQConfiguration {

    /**
     * Fanout模式的交换机/向绑定的所有的栈进行广播
     */
    public static final String exchangeName = "login_fanout_exchange";

    /**
     * 类型为Fanout(广播), 持久化, 非自动删除的交换机
     * @return FanoutExchange
     */
    @Bean
    public FanoutExchange fanoutExchange() {
        return new FanoutExchange(exchangeName,true,false);
    }

    /**
     * 创建短信队列 sms.fanout.queue
     */
    @Bean
    public Queue smsQueue() {
        return new Queue("sms.fanout.queue");
    }
    /**
     * 创建邮件队列
     */
    @Bean
    public Queue mailQueue() {
        return new Queue("mail.fanout.queue");
    }

    /**
     * 将交换机和队列进行绑定
     */
    @Bean
    public Binding smsBinding() {
        return BindingBuilder.bind(smsQueue()).to(fanoutExchange());
    }

    @Bean
    public Binding mailBinding() {
        return BindingBuilder.bind(mailQueue()).to(fanoutExchange());
    }
}

生产者测试代码(使用定义的交换机广播信息)

@SpringBootTest
class ProducerServerApplicationTests {

    @Resource
    private FanoutRegisterServer fanoutRegisterServer;

    /**
     * 测试Fanout模式广播信息到绑定的所有队列
     */
    @Test
    void contextLoads() {
        fanoutRegisterServer.register("110", "这是110用户的用户信息");
    }

}

生产者通过交换机向队列中发送了消息:

在这里插入图片描述

3-消费者代码

短信消费服务

@Service
@RabbitListener(queues = {"sms.fanout.queue"})
public class SMSService {
    /**
     * 对短信分发消息进行消费
     */
    @RabbitHandler
    public void sandSMS(String message) {
        System.out.println("向 "+message+" 发送了短信");
    }
}

邮件消费服务

@Service
@RabbitListener(queues = {"mail.fanout.queue"})
public class MailService {
    /**
     * 对邮件分发消息进行消费
     */
    @RabbitHandler
    public void sandMail(String message) {
        System.out.println("向 "+message+" 发送了邮件");
    }
}

消费者执行效果:

在这里插入图片描述

4. 总结

​ 到此我们使用RabbitMQ基于Fanout模式实现了对消息的发布和消费, 将我们的服务结构进行了解耦, 提高了扩展性和提高了系统性能.

完整项目代码-码云仓库地址

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值