记 ==> 首次使用rabbitMQ优化项目

2023-10-29

昨天刚学习完了rabbitMQ,刚好我的项目有个模块挺符合使用rabbitMQ进行异步处理的。

这个模块大概功能是:用户发送的所有帖子都会添加到他的发件箱,当有个新用户关注了他,他发件箱内所有的博客都会被添加到关注他的用户的收件箱里

比如:A关注B,A的收件箱内添加B的所有帖子

后续B再发帖子,直接推送到A的收件箱

有点类似抖音,当我们关注了一个up主,我们可以在关注列表里刷到这个up主的视频,并且是按新发布时间降序排序的

接下来看看我的代码,(ps:本人小白勿喷)

当用户关注一个博主后,利用redis的Zset集合完成feed流TimeLine模式的读扩散(拉模式),从博主的收件箱内拉取所有帖子到用户收件箱。当博主后续再新发帖子,才用写扩散(推模式)推送到收件箱

当用户取关后,从用户收件箱内移除掉被取关博主的帖子

我的理解是,这个接口的功能就是单纯的实现用户关注和取关,并不关注帖子的拉取和删除,并不该把这两个功能冗杂在一个方法里。

于是我便打算用rabbitMQ的directExchange模式进行消息发送,关注或者取关后把消息发布出去,不关注对帖子的拉取的行为,让监听者去慢慢的拉。

修改代码~~

把当前用户和被关注取关的用户ID一起当做消息发送出去

引入AMQP依赖

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

yml内添加rabbitmq配置

更改序列化规则,后续消息使用map发送

写一个config,配置一下交互机,队列,并完成绑定

然后写两个方法分别接听拉取帖子和取消帖子这两个queue

拉取队列

取关队列

我把源码贴出来,献丑啦

package com.brrbaii.mqListener;

import com.brrbaii.dto.Result;
import com.brrbaii.dto.UserDTO;
import com.brrbaii.utils.UserHolder;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.Set;

import static com.brrbaii.common.MQConstants.*;
import static com.brrbaii.common.RedisConstants.*;
import static com.brrbaii.utils.SystemConstants.ALREADY_FOLLOW;

@Component
public class FollowListener {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    /**
     * 用户关注后,把被关注用户发件箱内的所有BLOG添加到当前用户的收件箱
     * @param map:被关注的用户ID和当前用户ID
     */
    @RabbitListener(queues = PULL_BLOG_QUEUE)
    public void pullBlog2UserBox(Map<String,String> map){
        if( map == null){
            return;
        }
        String followerId = map.get("followedUserId");
        String userId = map.get("userId");
        //被关注的用户key
        String followBox = FEED_USER_KEY + followerId;

        //功能:关注后,把该用户的发件箱内数据拷贝到粉丝收件箱
        //获取被关注用户所有博客--从0到当前时间就是获取全部,并按照降序排序
        Set<ZSetOperations.TypedTuple<String>> typedTuples = stringRedisTemplate.opsForZSet()
                .reverseRangeByScoreWithScores(followBox, 0, System.currentTimeMillis());

        //用户没有博客,不用获取
        if (typedTuples==null || typedTuples.isEmpty()){
            return;
        }
        //获取当前用户的key
        String userBOx = FEED_PUSH_KEY + userId;

        //把被关注用户的blog添加到“我”的收件箱
        for(ZSetOperations.TypedTuple<String> tuple:typedTuples){
            stringRedisTemplate.opsForZSet().add(
                    userBOx,
                    tuple.getValue(),
                    tuple.getScore()
            );
        }
    }

    /**
     * 用户取关后,从用户的收件箱内清除被取关用户的BLOG
     * @param map:被关注的用户ID和当前用户ID
     */
    @RabbitListener(queues = PUSH_BLOG_QUEUE)
    public void pushBlogFromUserBox(Map<String,String> map){
        if( map == null){
            return;
        }
        String followerId = map.get("followedUserId");
        String userId = map.get("userId");

        String cancelFollower = FEED_USER_KEY + followerId;
        //获取被取关用户的所有blog,这里无需关注score
        Set<String> cancelFollowerBox = stringRedisTemplate.opsForZSet().range(cancelFollower, 0, -1);

        //没有BLOG,直接结束
        if(cancelFollowerBox == null || cancelFollowerBox.isEmpty()){
            return;
        }

        //获取当前用户收件箱
        String userBox = FEED_PUSH_KEY + userId;

        //从当前用户的收件箱里,把被取关用户的博客删除
        for(String blogId : cancelFollowerBox){
            stringRedisTemplate.opsForZSet().remove(userBox,blogId);
        }
    }

}
package com.brrbaii.config;

import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static com.brrbaii.common.MQConstants.*;

@Configuration
public class MQConfig {
    //拉取blog队列
    @Bean
    public Queue pullBlogQueue(){
        System.out.println("为什么没给我创建队列?");
        return new Queue(PULL_BLOG_QUEUE);
    }

    //移出blog队列
    @Bean
    public Queue pushBlogQueue(){
        return new Queue(PUSH_BLOG_QUEUE);
    }

    //声明交换机
    @Bean
    public DirectExchange blogDirectExchange(){
        return new DirectExchange(DIRECT_EXCHANGE_BLOG);
    }

    @Bean
    public Binding pullBlogBinding(Queue pullBlogQueue, DirectExchange blogDirectExchange){
        return BindingBuilder
                .bind(pullBlogQueue)
                .to(blogDirectExchange)
                .with(PULL_BLOG_ROUTING_KEY);
    }
    @Bean
    public Binding pushBlogBinding(Queue pushBlogQueue, DirectExchange blogDirectExchange){
        return BindingBuilder
                .bind(pushBlogQueue)
                .to(blogDirectExchange)
                .with(PUSH_BLOG_ROUTING_KEY);
    }

}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

记 ==> 首次使用rabbitMQ优化项目 的相关文章

随机推荐

  • Linux Ubuntu 设置脚本开机启动

    主要参考下面这个博客 ubuntu18开机启动脚本 但是要注意 有的ubuntu里面并不存在这个目录 在一开始的 vim etc systemd system rc local service 这一步就会失败 比如我的系统 最后我使用fin
  • runtime engine VM的一些随想

    这篇文章还是我在写作的新书 新时期的Node js 入门的一部分 一些比喻 我们可以通过一些现实的比喻来理解接下来要讲述的概念 苏联是社会主义的一种运行时 这大概是我这辈子能想到的最贴切的比喻了 笑 社会主义只是一种思想 可以看做是一门编程
  • 控制流图怎么画

    一 什么是控制流图 控制流图 Control Flow Graph CFG 也叫控制流程图 是一个过程或程序的抽象表现 是用在编译器中的一个抽象数据结构 由编译器在内部维护 代表了一个程序执行过程中会遍历到的所有路径 它用图的形式表示一个过
  • FPGA实现图像二值形态学滤波——腐蚀膨胀

    一 二值图像 二值图像 Binary Image 是指图像上的每一个像素只有两种可能的取值或灰度等级状态 简言之 在图像中灰度等级只有两种0或255 黑或白 二 形态学 形态学 即数学形态学 Mathematical Morphology
  • 解决 required a single bean, but 2 were found的spring注入bean错误

    背景介绍 个人定义了一个interface 为了抽象与规范使用泛型进行约束 名字举例为 ITestService java public interface ITestService
  • 希沃展台如何使用_气化街小学开展希沃触摸一体机使用方法培训

    为进一步推进气化街小学信息化教学 帮助教师熟悉希沃教学触摸一体机设备的使用功能 掌握希沃教学触摸式一体机的基本操作技巧 充分发挥触摸一体机的教学辅助作用 5月29日上午10点 万柏林区气化街小学组织一 二 三年级全体任课老师 在王学光老师的
  • 老生常谈session,cookie的区别,安全性

    老生常谈session cookie的区别 安全性 张映 发表于 2010 07 25 分类目录 php 一 为什么session cookie经常会有人提到 做web开发的人基本上都会用session和cookie 但是仅仅只是会用 并不
  • 《五分钟科普ChatGPT》系列专栏---介绍 ChatGPT未来的发展方向

    VI ChatGPT未来的发展方向 聊天机器人技术的未来发展方向包括以下几个方面 6 1 强化学习和自主学习能力 强化学习是一种让机器代理通过与环境的交互学习并改进自身策略的方法 ChatGPT未来可能会融合强化学习技术 使其能够从与用户的
  • 开放定址法(线性探测),拉链法 -Hash算法

    总结 哈希别名为 Hash 或者 散列表 开放定址法是为了解决hash值碰撞后的处理 哈希表查找 杂凑法 http c biancheng net cpp html 1031 html 查找 http blog csdn net yang
  • 如何在Android Studio中添加RecyclerView-v7支持包

    一直知道RecyclerView可以代替ListView GridView使用 听说功能很强大 但还没有去学习过 今天想学习 没想到还没开始便撞墙了 输入Recycler 只有这两个东西 没有提示RecyclerView 说明支持包中没有
  • git命令合并分支代码

    合并步骤 例 dev分支合并到master分支 1 git checkout master 进入要合并的分支 2 git pull 拉取最新代码 3 git branch a 查看所有分支是否都pull下来了 4 git merge dev
  • Linux性能监控工具sysstat的cron文件

    简单来讲sysstat就是检测系统性能的工具 安装 yum install sysstat 查看生成的相关文件 rpm ql sysstat etc cron d sysstat etc sysconfig sysstat etc sysc
  • 如何使用Linux Top命令

    Linux中的top命令允许您监视当前正在运行的进程及其使用的系统资源 作为系统管理员 它可能是工具箱中最有用的工具 特别是如果您知道如何使用它的话 所有Linux发行版都预装了top实用程序 通过这个交互式命令 您可以自定义如何浏览进程列
  • node 版本管理工具 nvm,node版本升级、降级

    不同项目需要的 nodejs 版本不一致 需要在电脑上安装多个 node 版本 此时知道有一个 nvm 版本管理工具就非常必要了 NVM 下载安装 nvm 安装地址 https github com coreybutler nvm wind
  • 【数据结构】双向链表

    前面我们已经学完了单向链表 知道了单向链表如何进行增删查改等基本功能 而今天 我们将要学习双向链表 目录 1 链表的分类 2 双向链表定义 3 双向链表接口的实现 所有接口函数一览 创建返回链表头节点 初始化链表 双向链表打印 双向链表尾插
  • 在钉钉上怎么手写_钉钉直播上课可以写字吗_钉钉直播写字板功能介绍_玩游戏网...

    钉钉直播上课已经有很多学校在使用了 这个时候就有人问了 能不能在钉钉上用手写字 在学习资料上做笔记 目前发下来钉钉的很多功能 不过关于写字这个功能暂且还没有 那么想要用写字的方式教学要怎么做呢 这就让我们一起来看一看吧 当然了小编也给大家准
  • 第六章 课后习题(P171-P172)

    习题 一 填空题 1 运算符的重载实际上是 函数 的重载 2 运算符函数必须被重载为 非静态成员函数 或被重载为 友元函数 3 成员函数重载运算符需要的参数的个数总比它的操作数 少 一个 4 重载赋值运算符时 通常返回调用该运算符的 对象的
  • VScode SSH远程登陆到服务器阅读代码

    1 背景介绍 在工作中经常使用ssh远程访问服务阅读代码 但是通过ssh远程访问后没有图形界面 阅读代码非常不方便 本文向大家介绍使用VScode通过ssh远程登陆到服务器 本地可视化阅读查看服务器的代码文件 2 安装VS Code Vis
  • springboot打包成maven仓库中的sdk

    springboot打包成maven仓库中的sdk 首先将pom文件中的关于该项目继承springboot父项目的依赖去除 再去除一些不相干的依赖 插件也去除 在新项目中导入这个jar sdk 需要新建一个配置类 使用注解扫描这个jar中的
  • 记 ==> 首次使用rabbitMQ优化项目

    昨天刚学习完了rabbitMQ 刚好我的项目有个模块挺符合使用rabbitMQ进行异步处理的 这个模块大概功能是 用户发送的所有帖子都会添加到他的发件箱 当有个新用户关注了他 他发件箱内所有的博客都会被添加到关注他的用户的收件箱里 比如 A