广告
返回顶部
首页 > 资讯 > 前端开发 > JavaScript >SpringCache如何实现请求级别缓存
  • 584
分享到

SpringCache如何实现请求级别缓存

2024-04-02 19:04:59 584人浏览 独家记忆
摘要

这篇文章将为大家详细讲解有关springCache如何实现请求级别缓存,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。 方案分析 要将数据缓存在一次请求周期内,那我们先

这篇文章将为大家详细讲解有关springCache如何实现请求级别缓存,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。

方案分析

要将数据缓存在一次请求周期内,那我们先得区分是什么环境下的请求,以分析我们如何存储数据。

1. WEB

Web环境下的有个绝佳的数据存储位置 httpservletRequest的Attribute 。调用setAttribute和getAttribute方法就能轻易地将我们的数据用key-value的形式存储在请求上,而且每次请求都自动拥有一个干净的Request。想要获取到HttpServletRequest 也非常简单,在web请求中随时随地调用((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest() 即可。

2. rpc框架

我司所使用的rpc框架是基于finagle自研的,对外提供服务时使用线程池进行处理请求,即对于一次完整的请求,会使用同一个线程进行处理。首先想到的办法还是改动这个rpc框架服务端,增加一个可以对外暴露的、可以key-value存储的请求上下文。为了能在方便的地方获取到这个请求上下文,得将其存储在ThreadLocal中。

综合这两种环境考虑,我们最好还是实现一个统一的方案以减少维护和开发成本。Spring的RequestContextHolder.getRequestAttributes()其实也是使用ThreadLocal来实现的,那我们可以统一将数据存到ThreadLocal<Map<Object,Object>>,自己来维护缓存的清理。

存储位置有了,接下来实现SprinGCache思路就比较清晰了。

实现SpringCache

要实现SpringCache需要一个CacheManager,接口定义如下

xxxxxxxxxx
public interface CacheManager {
           Cache getCache(String name);
           Collection<String> getCacheNames();
}

可以看到其实只需要实现Cache接口就行了。 在上一篇文章中提到的SimpleCacheManager,它的Cache实现ConcurrentMapCache内部的存储是依赖ConcurrentMap<Object, Object>。我们的实现跟它非常类似,最主要的不同是我们需要使用ThreadLocal<Map<Object, Object>> 下面给出几处关键的实现,其他部分简单看下ConcurrentMapCache就能明白。

1 extends  

我们选择不直接继承Cache而是AbstractValueAdaptingCache,其被大多数缓存实现所继承,它的作用主要是包装value值以区分是没有命中缓存还是缓存的null值。

2 store

xxxxxxxxxx
private final ThreadLocal<Map<Object, Object>> store = ThreadLocal.withInitial(() -> new HashMap<>(128));

我们的缓存数据存储的地方,ThreadLocal保证缓存只会存在于这一个线程中。同时又因为只有一个线程能够访问,我们简单地使用HashMap即可。

3 get

xxxxxxxxxx
public <T> T get(Object key, Callable<T> valueLoader) {
    return (T) fromStoreValue(this.store.get().computeIfAbsent(key, r -> {
        try {
            return toStoreValue(valueLoader.call());
        } catch (Throwable ex) {
            throw new ValueRetrievalException(key, valueLoader, ex);
        }
     }));
 }

至此我们即将大功告成,只差一个步骤,ThreadLocal的清理:使用aop实现即可。

xxxxxxxxxx
    @After("bean(server)")
    public void clearThreadCache() {
        threadCacheManager.clear();
    }

记得将Cache的clear方法通过我们自定义的CacheManager暴露出来。同时也要确保切面能覆盖每个请求的结束。

总结与扩展

从以上一个简单的ThreadLocalCacheManager实现,我们对CacheManager又有了更多的理解。

同时可能也会有更多的疑问。

1. 我们实现的这些方法,从方法名和逻辑上看起来都很简单,那他们是如何配合使用的?跟@Cacheable上的sync又有什么关系呢?

再回顾Spring Cache为我们提供的@Cacheable中的sync的注释,它提到此功能的作用是: 同步化对被注解方法的调用,使得多个线程试图调用此方法时,只有一个线程能够成功调用,其他线程直接取这次调用的返回值。同时也提到这仅仅只是个hint,是否真的能成还是要看缓存提供者。

我们找到Spring Cache处理缓存调用的关键方法org.springframework.cache.interceptor.CacheAspectSupport#execute(org.springframework.cache.interceptor.CacheOperationInvoker, java.lang.reflect.Method, org.springframework.cache.interceptor.CacheAspectSupport.CacheOperationContexts) (spring-context-5.1.5.RELEASE)

经过分析,当sync = true 时, 只会调用如下代码

xxxxxxxxxx
return wrapCacheValue(method, cache.get(key, () -> unwrapReturnValue(invokeOperation(invoker))))

即我们上文实现的T get(Object key, Callable<T> valueLoader) 方法,回头一看一切都清晰了。 只要我们的this.store.get().computeIfAbsent是同步的,那这个sync = true就起作用了。 当然我们这里使用的HashMap不支持,但是我们如果换成ConcurrentMap就能够实现同步化的功能。另外简单粗暴地让方法同步也是可以的(RedisCache就是这样做的)。

当sync = false时,会组合Cache中其他的方法进行缓存的处理。逻辑较为简单清晰,自行阅读源码即可。

2. 用ThreadLocal严格来说实现的只是线程内的缓存,万一一次请求中有异步操作怎么办?

异步操作分两种情况,直接创建线程或者使用线程池。对于第一种情况我们可以简单地使用java.lang.InheritableThreadLocal 来替代ThreadLocal,创建的子进程会自然而然地共享父进程的InheritableThreadLocal;第二种情况就相对比较复杂了,建议可以参考 alibaba/transmittable-thread-local ,它实现了线程池下的ThreadLocal值传递功能。

关于“SpringCache如何实现请求级别缓存”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。

--结束END--

本文标题: SpringCache如何实现请求级别缓存

本文链接: https://www.lsjlt.com/news/91539.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • SpringCache如何实现请求级别缓存
    这篇文章将为大家详细讲解有关SpringCache如何实现请求级别缓存,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。 方案分析 要将数据缓存在一次请求周期内,那我们先...
    99+
    2022-10-19
  • SpringBoot+SpringCache实现两级缓存(Redis+Caffeine)
    1. 缓存、两级缓存 1.1 内容说明 Spring cache:主要包含spring cache定义的接口方法说明和注解中的属性说明 springboot+spring cache...
    99+
    2022-11-12
  • SpringBoot+SpringCache实现两级缓存的示例分析
    这篇文章给大家分享的是有关SpringBoot+SpringCache实现两级缓存的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。springboot是什么springboot一种全新的编程规范,其设计目...
    99+
    2023-06-14
  • Android实现图片异步请求加三级缓存
    使用xUtils等框架是很方便,但今天要用代码实现bitmapUtils 的功能,很简单, AsyncTask请求一张图片 ####AsyncTask #####AsyncT...
    99+
    2022-06-06
    异步请求 三级缓存 图片 异步 缓存 Android
  • Android使用缓存机制实现文件下载及异步请求图片加三级缓存
    首先给大家介绍Android使用缓存机制实现文件下载 在下载文件或者在线浏览文件时,或者为了保证文件下载的正确性,需要使用缓存机制,常使用SoftReference来实现。 ...
    99+
    2022-06-06
    异步请求 三级缓存 图片 异步 缓存 Android
  • 如何在Go语言中实现路由的请求缓存
    如何在Go语言中实现路由的请求缓存在Web开发中,路由是一个非常重要的概念,用于将客户端请求映射到相应的处理程序。在高并发的情况下,频繁地处理请求可能会导致服务器性能下降。为了减轻服务器的负载和提高响应速度,可以对路由的请求进行缓存。在Go...
    99+
    2023-12-17
    Go语言 路由 请求缓存
  • Spring Cloud中Hystrix的请求缓存怎么实现
    本篇内容介绍了“Spring Cloud中Hystrix的请求缓存怎么实现”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!通过方法重载开启缓存...
    99+
    2023-06-19
  • 使用MyBatis如何实现一级缓存与二级缓存
    这期内容当中小编将会给大家带来有关使用MyBatis如何实现一级缓存与二级缓存,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。MyBatis缓存我们知道,频繁的数据库操作是非常耗费性能的(主要是因为对于DB...
    99+
    2023-05-31
    mybatis 一级缓存 二级缓存
  • redis如何实现多级缓存
                                 ...
    99+
    2022-10-18
  • 如何使用Java缓存HTTP请求日志?详解实现步骤
    当今互联网时代,HTTP请求日志已经成为了系统监控和性能优化的重要指标之一。为了更好地跟踪和分析系统运行状态,我们需要对HTTP请求日志进行缓存处理。本文将详细介绍如何使用Java缓存HTTP请求日志,包括实现步骤和演示代码。 一、缓存HT...
    99+
    2023-07-24
    http 日志 缓存
  • 在Go语言中如何解决并发网络请求的请求缓存和缓存更新问题
    在Go语言中,可以使用sync.Map来实现请求缓存和缓存更新的问题。首先,我们可以创建一个全局的sync.Map来作为缓存,用于存...
    99+
    2023-10-09
    Go语言
  • 在Go语言中如何解决并发网络请求的请求缓存和缓存更新问题?
    标题:Go语言中的并发网络请求的请求缓存和缓存更新问题解决方案引言:在现代程序开发中,网络请求是非常常见的操作,而并发请求更是提高程序性能和响应速度的关键。然而,在并发网络请求中,往往会面临请求重复发送、数据不一致等问题。本文将介绍如何在G...
    99+
    2023-10-22
    Go语言 并发 解决 缓存更新 请求缓存
  • 如何自定义Egg.js的请求级别日志
    这篇文章给大家分享的是有关如何自定义Egg.js的请求级别日志的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。Egg.js 是什么Egg.js 为企业级框架和应用而生,我们希望由 ...
    99+
    2022-10-19
  • Android 中Volley二次封装并实现网络请求缓存
    Android 中Volley二次封装并实现网络请求缓存Android目前很多同学使用Volley请求网络数据,但是Volley没有对请求过得数据进行缓存,因此需要我们自己手动缓存。 一下就是我的一种思路,仅供参考具体使用方法为:HashM...
    99+
    2023-05-30
    android volley roi
  • Go应该如何实现二级缓存
    目录一、需求二、实现连接Mysql并执行查询语句三、写一个错误处理函数四、设置二级缓存一、需求 实现二级缓存 程序运行起来后提示:“请输入命令:”,如果输入geta...
    99+
    2022-11-12
  • 如何实现Ajax请求
    小编给大家分享一下如何实现Ajax请求,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!Ajax不是一种新的编程语言,而是一种用于创...
    99+
    2022-10-19
  • 如何解决ajax的get请求时的缓存处理
    这篇文章主要介绍“如何解决ajax的get请求时的缓存处理”,在日常操作中,相信很多人在如何解决ajax的get请求时的缓存处理问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”...
    99+
    2022-10-19
  • 如何实现Jquery Ajax请求
    如何实现Jquery Ajax请求,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。 jQuery确实是一个挺好的轻量级的JS框架,能帮...
    99+
    2022-10-19
  • 使用Mybatis如何实现配置二级缓存
    这篇文章给大家介绍使用Mybatis如何实现配置二级缓存,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。Mybatis的二级缓存配置相当容易,要开启二级缓存,只需要在你的Mapper 映射文件中添加一行:<...
    99+
    2023-05-31
    mybatis 二级缓存
  • vue如何实现发送websocket请求和http post请求
    这篇文章主要介绍vue如何实现发送websocket请求和http post请求,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!先给大家介绍下vue发送websocket请求和http...
    99+
    2022-10-19
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作