当前位置: 首页 > news >正文

ThreadLocal加切面实现线程级别的方法缓存

1、实现效果

当一个请求线程多次请求A方法时,只会触发一次A方法的实际调用,会将方法结果缓存起来,避免多次调用。

2、实现过程

1. 需要一个注解ThreadLocalCache,在需要缓存的方法上加上该注解
2. 需要一个切面,借助ThreadLocal,将结果缓存起来,利用环绕通知来实现方法拦截从缓存中返回方法执行结果

3、代码实现

3.1、ThreadLocalCache注解创建

作用于方法级别

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ThreadLocalCache {
}

3.2、ThreadLocalTestAspect切面创建

@Aspect
@Component
public class ThreadLocalTestAspect {private ThreadLocal<Map<Object, Object>> threadLocal = new ThreadLocal<>();@Around("@annotation(com.example.test.ThreadLocalCache)")private Object myPointcut(ProceedingJoinPoint proceedingJoinPoint) {//获取方法的入参Object[] args = proceedingJoinPoint.getArgs();Signature signature = proceedingJoinPoint.getSignature();//获取目标方法名String name = signature.getName();//获取目标方法的类的完全限定名String declaringTypeName = signature.getDeclaringTypeName();//生成缓存keyObject key = SimpleKeyGenerator.generateKey(args, declaringTypeName, name);if (Objects.isNull(threadLocal.get())) {threadLocal.set(new HashMap<>(8));}try {if (!threadLocal.get().containsKey(key)) {threadLocal.get().put(key, proceedingJoinPoint.proceed());}} catch (Throwable e) {//日志记录e.printStackTrace();}return threadLocal.get().get(key);}public void removeThreadLocal(){threadLocal.remove();}}

4、测试过程

  1. 创建一个接口及实现
public interface ThreadLocalTestService {Long getParentIdByName(String name);
}
@Service
public class ThreadLocalTestServiceImpl implements ThreadLocalTestService{@ThreadLocalCache@Overridepublic Long getParentIdByName(String name) {//根据name查询父级IDSystem.out.println("com.example.test.ThreadLocalTestServiceImpl.getParentIdByName 执行了");return 666L;}
}
  1. 方法调用
@RestController
@RequestMapping("/ThreadLocalTest")
public class ThreadLocalTest {@Autowiredprivate ThreadLocalTestService threadLocalTestService;@Autowiredprivate ThreadLocalTestAspect threadLocalTestAspect;@GetMapping("getParentIdByName")public Long getParentIdByName(String name){System.out.println(Thread.currentThread().getName());threadLocalTestService.getParentIdByName(name);threadLocalTestService.getParentIdByName(name);Long parentId = threadLocalTestService.getParentIdByName(name);threadLocalTestAspect.removeThreadLocal();return parentId;}}

3.执行结果

http-nio-8087-exec-1
com.example.test.ThreadLocalTestServiceImpl.getParentIdByName 执行了
http-nio-8087-exec-2
com.example.test.ThreadLocalTestServiceImpl.getParentIdByName 执行了
http-nio-8087-exec-4
com.example.test.ThreadLocalTestServiceImpl.getParentIdByName 执行了
http-nio-8087-exec-5
com.example.test.ThreadLocalTestServiceImpl.getParentIdByName 执行了
http-nio-8087-exec-6
com.example.test.ThreadLocalTestServiceImpl.getParentIdByName 执行了
http-nio-8087-exec-7
com.example.test.ThreadLocalTestServiceImpl.getParentIdByName 执行了
http-nio-8087-exec-8
com.example.test.ThreadLocalTestServiceImpl.getParentIdByName 执行了
http-nio-8087-exec-10
com.example.test.ThreadLocalTestServiceImpl.getParentIdByName 执行了
http-nio-8087-exec-9
com.example.test.ThreadLocalTestServiceImpl.getParentIdByName 执行了
http-nio-8087-exec-3
com.example.test.ThreadLocalTestServiceImpl.getParentIdByName 执行了
http-nio-8087-exec-1
com.example.test.ThreadLocalTestServiceImpl.getParentIdByName 执行了
http-nio-8087-exec-2
com.example.test.ThreadLocalTestServiceImpl.getParentIdByName 执行了

http-nio-8087-exec-是线程名字,可以看到http-nio-8087-exec-1执行了两次,每次都调用四次getParentIdByName 方法,但getParentIdByName 方法实际至执行了一次,剩下的三次是从缓存中获取的。
这里需要注意的是:线程每次结束的时候都需要调用threadLocalTestAspect.removeThreadLocal();为的是把当前线程threadLocal里的缓存抹掉,因为同一个线程可能会被重复使用,所以不抹掉,可能会导致多次请求使用同一个线程,目标方法只会执行一次,和我们的最初的实现效果是违背的。
下面是不调用threadLocalTestAspect.removeThreadLocal();的执行结果

http-nio-8087-exec-1
com.example.test.ThreadLocalTestServiceImpl.getParentIdByName 执行了
http-nio-8087-exec-3
com.example.test.ThreadLocalTestServiceImpl.getParentIdByName 执行了
http-nio-8087-exec-8
com.example.test.ThreadLocalTestServiceImpl.getParentIdByName 执行了
http-nio-8087-exec-5
com.example.test.ThreadLocalTestServiceImpl.getParentIdByName 执行了
http-nio-8087-exec-6
com.example.test.ThreadLocalTestServiceImpl.getParentIdByName 执行了
http-nio-8087-exec-7
com.example.test.ThreadLocalTestServiceImpl.getParentIdByName 执行了
http-nio-8087-exec-4
com.example.test.ThreadLocalTestServiceImpl.getParentIdByName 执行了
http-nio-8087-exec-9
com.example.test.ThreadLocalTestServiceImpl.getParentIdByName 执行了
http-nio-8087-exec-10
com.example.test.ThreadLocalTestServiceImpl.getParentIdByName 执行了
http-nio-8087-exec-2
com.example.test.ThreadLocalTestServiceImpl.getParentIdByName 执行了
http-nio-8087-exec-1
http-nio-8087-exec-3
http-nio-8087-exec-8
http-nio-8087-exec-5

可以很清楚的看到http-nio-8087-exec-1、3、5、8再次请求的时候getParentIdByName 方法并没有执行了,因为之前的threadlocal缓存没有被remove导致的。

相关文章:

ThreadLocal加切面实现线程级别的方法缓存

1、实现效果 当一个请求线程多次请求A方法时,只会触发一次A方法的实际调用,会将方法结果缓存起来,避免多次调用。 2、实现过程 1. 需要一个注解ThreadLocalCache,在需要缓存的方法上加上该注解 2. 需要一个切面,借助ThreadLocal,将结果缓存起来,利用环绕通知来实现方法拦截从…...

使用 Flume 将 CSV 数据导入 Kafka:实现实时数据流

使用 Flume 将 CSV 数据导入 Kafka&#xff1a;实现实时数据流 文介绍了如何使用 Apache Flume 将 CSV 格式的数据从本地文件系统导入到 Apache Kafka 中&#xff0c;以实现实时数据流处理。通过 Flume 的配置和操作步骤&#xff0c;我们可以轻松地将数据从 CSV 文件中读取并发…...

对代理模式的理解

目录 一、前言二、案例1 代码2 自定义代理类【静态代理】2.1 一个接口多个实现&#xff0c;到底注入哪个依赖呢&#xff1f;2.1.1 Primary注解2.1.2 Resource注解&#xff08;指定name属性&#xff09;2.1.3 Qualifier注解 2.2 面向接口编程2.3 如果没接口咋办呢&#xff1f;2.…...

#QT项目实战(天气预报)

1.IDE&#xff1a;QTCreator 2.实验&#xff1a; 3.记录&#xff1a; &#xff08;1&#xff09;调用API的Url a.调用API获取IP whois.pconline.com.cn/ipJson.jsp?iphttp://whois.pconline.com.cn/ipJson.jsp?ip if(window.IPCallBack) {IPCallBack({"ip":&quo…...

数据挖掘|关联分析与Apriori算法详解

数据挖掘|关联分析与Apriori算法 1. 关联分析2. 关联规则相关概念2.1 项目2.2 事务2.3 项目集2.4 频繁项目集2.5 支持度2.6 置信度2.7 提升度2.8 强关联规则2.9 关联规则的分类 3. Apriori算法3.1 Apriori算法的Python实现3.2 基于mlxtend库的Apriori算法的Python实现 1. 关联分…...

ChatGPT Excel 大师

原文&#xff1a;ChatGPT Excel Mastery 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 序言 欢迎来到 Excel 掌握的变革之旅&#xff0c;在这里&#xff0c;尖端技术和永恒专业知识在“ChatGPT Excel 掌握&#xff1a;释放专家技巧和窍门的力量”中融合。在当今快节…...

C 语言中的 end, _end 符号

使用 man 3 end 可以看到相关符号的解释 这些符号不是在 C 语言文件和头文件中定义的&#xff0c;它们是 ld 在链接所有 .o 文件的时候自己添加的。 end 和 _end 的地址&#xff0c;就是最终程序的堆的起始地址 要打印它们的话&#xff0c;一个样例程序在下面&#xff1a; …...

绿联 安装PDF工具

这是一个强大的本地托管的基于 Web 的 PDF 操作工具&#xff0c;使用 docker&#xff0c;允许您对 PDF 文件执行各种操作&#xff0c;例如拆分、合并、转换、重组、添加图像、旋转、压缩等。这个本地托管的 Web 应用程序最初是 100% ChatGPT 制作的应用程序&#xff0c;现已发展…...

备战蓝桥杯---数论相关问题

目录 一、最大公约数和最小公倍数 二、素数判断 三、同余 四、唯一分解定理 五、约数个数定理 六、约数和定理 五、快速幂 六、费马小定理 七、逆元 一、最大公约数和最小公倍数 文章链接&#xff1a;最大公约数和最小公倍数 二、素数判断 文章链接&#xff1a;在J…...

苹果手表Apple Watch录了两个半小时的录音,却只能播放4秒,同步到手机也一样,还能修复好吗?

好多人遇到这个情况&#xff0c;用苹果手表Apple Watch录音&#xff0c;有的录1个多小时&#xff0c;有的录了3、4小时&#xff0c;甚至更长时间&#xff0c;因为手表没电&#xff0c;忘记保存等原因造成录音损坏&#xff0c;都是只能播放4秒&#xff0c;同步到手机也一样&…...

RGB三通道和灰度值的理解

本文都是来自于chatGPT的回答!!! 目录 Q1:像素具有什么属性?Q2:图像的色彩是怎么实现的?Q3:灰度值和颜色值是一个概念吗?Q4:是不是像素具有灰度值&#xff0c;也有三个颜色分量RGB&#xff1f;Q5:灰度图像是没有色彩的吗&#xff1f;Q6: 彩色图像是既具有灰度值也具有RGB三…...

ARM、X86、RISC-V三分天下

引入&#xff1a; 简单的介绍一下X86、ARM、RISC-V三种cpu架构的区别和应用场景。 目录 简单概念讲解 1. X86架构 2. ARM架构 3. RISC-V架构 应用场景 X86、ARM和RISC-V是三种不同的CPU架构&#xff0c;它们在设计理念、指令集和应用场景上有一些区别。 简单概念讲解 1. X…...

力控机器人原理及力控制实现

力控机器人原理及力控制实现 力控机器人是一种能够感知力量并具有实时控制能力的机器人系统。它们可以在与人类进行精准协作和合作时&#xff0c;将力传感技术&#xff08;Force Sensing Technology&#xff09;和控制算法&#xff08;Control Algorithm&#xff09;结合起来&a…...

最小生成树

最小生成树问题是指给定一个带权的无向图&#xff0c;删除一些边使得这个无向图变成一棵树&#xff0c;并且权值之和最小。 解决此类问题的方法主要有两种&#xff1a;Prim算法&#xff0c;Kruskal算法 Prim 算法 从一个点开始&#xff0c;逐步扩展&#xff0c;每次选择权值…...

二维动画制作软件 Animate 2024 for mac激活版

Animate 2024 for Mac是一款功能强大的二维动画制作软件&#xff0c;专为Mac用户打造。它提供了丰富的动画编辑功能&#xff0c;使用户能够轻松创建出生动逼真的动画作品。无论是短片、广告还是游戏等应用领域&#xff0c;Animate 2024都能发挥出出色的表现。 软件下载&#xf…...

相对论中关于光速不变理解的补充

近几个月在物理直播间聊爱因斯坦相对论&#xff0c;发现好多人在理解爱因斯坦相对论关于基本假设&#xff0c;普遍认为光速是不变的&#xff0c;质能方程 中光速的光速不变的&#xff0c;在这里我对这个假设需要做一个补充&#xff0c;他是基于质能方程将光速C 在真是光速变化曲…...

面试(04)————JavaWeb

1、网络通讯部分 1.1、 TCP 与 UDP 区别&#xff1f; 1.2、什么是 HTTP 协议&#xff1f; 1.3、TCP 的三次握手&#xff0c;为什么&#xff1f; 1.4、HTTP 中重定向和请求转发的区别&#xff1f; 1.5、 Get 和 Post 的区别&#xff1f; 2、cookie 和 session 的区别&am…...

Debian12 使用 nginx 与 php8.2 使用 Nextcloud

最近将小服务器升级了下系统&#xff0c;使用了 debian12 的版本&#xff0c;正好试试 nginx 和 php-fpm 这种方式运行 Nextcloud 这个私有云的配置。 一、基本系统及应用安装 系统&#xff1a;debian12 x86_64 位版本最小安装&#xff0c;安装后可根据自己需求安装一些工具&…...

Java设计模式:代理模式的静态和动态之分(八)

码到三十五 &#xff1a; 个人主页 心中有诗画&#xff0c;指尖舞代码&#xff0c;目光览世界&#xff0c;步履越千山&#xff0c;人间尽值得 ! 在软件设计中&#xff0c;代理模式是一种常用的设计模式&#xff0c;它为我们提供了一种方式来控制对原始对象的访问。在Java中&a…...

【论文通读】AgentStudio: A Toolkit for Building General Virtual Agents

AgentStudio: A Toolkit for Building General Virtual Agents 前言AbstractMotivationFramework评估GUI GroudingReal-World Cross-Application Benchmark Suite Conclusion 前言 来自昆仑万维的一篇智能体环境数据大一统框架工作&#xff0c;对未来计算机智能体的发展具有指…...

wordvect嵌入和bert嵌入的区别

Word2Vec 嵌入和 BERT 嵌入之间有几个关键区别&#xff1a; 训练方式&#xff1a; Word2Vec&#xff1a;Word2Vec 是一个基于神经网络的词嵌入模型&#xff0c;它通过训练一个浅层的神经网络来学习单词的分布式表示。它有两种训练方式&#xff1a;连续词袋模型&#xff08;CBOW…...

渗透测试练习题解析 5(CTF web)

1、[安洵杯 2019]easy_serialize_php 1 考点&#xff1a;PHP 反序列化逃逸 变量覆盖 【代码审计】 通过 GET 的方式获取参数 f 的值&#xff0c;传递给变量 function 定义一个过滤函数&#xff0c;过滤掉特定字符&#xff08;用空字符替换&#xff09; 下面的代码其实没什么用…...

PCA(Principal Component Analysis,主成分分析)

PCA&#xff08;Principal Component Analysis&#xff0c;主成分分析&#xff09;是一种在数据分析中广泛应用的统计方法&#xff0c;主要用于数据降维、可视化和去噪。以下是对PCA的发展史、工作原理以及理论基础的详细解释&#xff1a; Principal Component Analysis 一、PC…...

干货 | 探索CUTTag:从样本到文库,实验步步为营!

CUT&Tag&#xff08;Cleavage Under Targets and Tagmentation&#xff09;是一种新型DNA-蛋白互作研究技术&#xff0c;主要用于研究转录因子或组蛋白修饰在全基因组上的结合或分布位点。相比于传统的ChIP-seq技术&#xff0c;CUT&Tag反应在细胞内进行&#xff0c;创新…...

提质不增本,降本不降质

#公益巡讲# #质量万里行# 公开课、沙龙活动...

数据结构---顺序表实现

目录 1.顺序表 2.动态顺序表的实现 &#xff08;4&#xff09;顺序表初始化 &#xff08;5&#xff09;顺序表销毁 &#xff08;6&#xff09;顺序表的插入 a.尾插 b.头插 &#xff08;7&#xff09;顺序表的删除 a.尾删 b.头删 &#xff08;8&#xff09;指定位置之…...

python docx 添加动态表格

在Python中&#xff0c;使用python-docx库可以创建Word文档并添加动态表格。以下是一个简单的例子&#xff0c;演示如何创建一个包含动态内容的表格&#xff1a; from docx import Document# 创建一个Word文档 document Document()# 添加一个标题 document.add_heading(动态表…...

git配置多SSH

目的&#xff1a; 一台电脑可以让github、gitee等账号同时存在&#xff0c;让不同账号配置不同的密钥 第一步&#xff1a;创建不同平台的SSH公钥 执行命令&#xff1a; ssh-keygen -t rsa -C "对应仓库邮箱地址" -f ~/.ssh/id_rsa.github 如果执行上面的命令&…...

IDEA连接SqlServer数据库

目录 下载jar包 下载sqljdbc_12.6压缩包 解压 导入IDEA 新建文件夹 复制粘贴进JDBC文件夹并设为library 编写类及方法 代码 下载jar包 以sqljdbc_12.6为例 下载sqljdbc_12.6压缩包 最新地址&#xff1a;sqljdbc 官方最新地址 解压 解压即用 导入IDEA 新建文件夹 复制…...

LeetCode 378 有序矩阵中第K小的元素

题目信息 LeetoCode地址: . - 力扣&#xff08;LeetCode&#xff09; 题解内容大量转载于&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 题目理解 题意很直观&#xff0c;就是求二维矩阵中所有元素排序后第k小的数。 最小堆写法 该写法不再赘述&#xff0c;维护…...

网站建设款属不属于无形资产/网站用户体验优化

1.概述 Cookie&#xff08;客户端&#xff0c;不是内置对象&#xff09;&#xff1a;Cookie是由服务器生成的&#xff0c;在发送给客户端保存。 相当于本地缓存的作用&#xff1a;客户端——>服务端 比如你在线看视频&#xff0c;你看视频是从服务端读取的&#xff0c;看完…...

网站成功案例怎么做/什么是关键词

在postman中&#xff0c;大家都使用过断言&#xff0c;但是我们使用的断言都是针对每一个接口或者是每一个用例添加的&#xff0c;那么是否有可以同时对多个用例或接口添加断言呢 &#xff1f; 答案是肯定有的。 那么接下来我就带领大家认识下Postman中的批量断言&#xff0c;…...

汕头第一网告别单身/seo外链工具

2019uni-app前后端全栈实战仿糗事百科app 关注公众号&#xff1a;码农那些年 回复“uni-app百科”&#xff0c;免费获取。 微信公众号&#xff1a; 打开微信扫一扫...

建网站知乎/全网热搜关键词排行榜

第一种方法&#xff1a; 记得有一本书上介绍 说 0权限重启手机&#xff0c;原理是 在android 系统中&#xff0c;当显示一个toast,其实是将该toast挂载到窗体上&#xff0c; 而窗体又是系统的一个服务&#xff0c; 如果单位时间内不断地向窗体上挂载toast,就会不断的申请系统内…...

阿里巴巴的免费b2b网站/北京网站优化步骤

zDiaLog弹出层 立即下载插件描述&#xff1a;zDiaLog弹出层弹出框&#xff1a; 代替window.open、window.alert、window.confirm&#xff1b;提供良好的用户体验&#xff1b;水晶质感&#xff0c;设计细腻&#xff0c;外观漂亮&#xff1b;兼容ie6/7/8、firefox2/3、Opera&…...

有哪些好的做网站/软文是什么意思

https://blog.csdn.net/marywbrown/article/details/62059231 一、背景介绍 Modularity(模块度), 这个概念是2003年一个叫Newman的人提出的。这个人先后发表了很多关于社区划分的论文&#xff0c;包括2002年发表的著名的Girvan-Newman(G-N)算法&#xff0c;和2004发表的Fast Ne…...