【开发篇】十二、缓存框架JetCache

news2024/11/24 17:47:26

文章目录

  • 0、介绍
  • 1、JetCache远程缓存
  • 2、JetCache本地缓存
  • 3、标准配置文件
  • 4、JetCache方法缓存注解--@Cached
  • 5、@Cached
  • 4、@CacheUpdate
  • 5、@CacheInvalidate
  • 6、@CacheRefresh
  • 7、缓存统计报告

上篇完成了Spring Cache底层技术的各种切换,但各个技术有各自的优缺点,因此阿里的Jetcache框架出现。 注意Jetcache是一个框架,做的是一个整合和封装,自身不是像redis一样的缓存实现技术,Jetcache框架底层还得依靠具体的缓存实现技术,它是和Spring Cache同等级的,用来替换Spring Cache的。

0、介绍

JetCache对SpringCache进行了封装,在原有功能基础上实现了多级缓存、缓存统计、自动刷新、异步调用、数据报表等功能

JetCache设定了本地缓存与远程缓存的多级缓存解决方案,其中本地缓存(local)支持:

  • LinkedHashMap
  • Caffeine

远程缓存(remote)支持:

  • Redis
  • Tair

1、JetCache远程缓存

先引入依赖

<dependency>    
	<groupId>com.alicp.jetcache</groupId>   
	<artifactId>jetcache-starter-redis</artifactId>    
	<version>2.6.2</version>
</dependency>

远程缓存的属性配置:

jetcache:  
  remote:    
    default:      
      type: redis      
      host: localhost      
      port: 6379   
      password: admin1234   
      poolConfig:        
        maxTotal: 50
    # 再定义一个缓存区域也行
    myArea:
      type: redis
      host: .......

@EnableCreateCacheAnnotation启动用注解来创建缓存,开启后就可以用@CreateCache来创建一个缓存对象。

@SpringBootApplication

@EnableCreateCacheAnnotation

public class CacheApplication {    

	public static void main(String[] args) {   
	    
		SpringApplication.run(CacheApplication.class, args);    
	}

}

使用@CreateCache注解声明一个缓存对象:

@Service
public class SMSCodeServiceImpl implements SMSCodeService {

    @CreateCache(area = "default", name = "smsCache::", expire = 3600, timeUnit = TimeUnit.SECONDS, cacheType = CacheType.REMOTE)  
    private Cache<String, String> jetSMSCache;
    //...

}

注意@CreateCache注解的属性:

  • area:用哪块存储空间,默认值为default,即配置文件里的jetcache.remote.default及其下面的配置,可以再自己定义区域
  • name:key的分组前缀,常用str::或者str_
  • expire:过期时间,单位默认秒
  • timeUnit:时间单位,默认值秒
  • cacheType:缓存类型,local即本地缓存,remote即远程缓存,all即两个都写,默认远程缓存

操作缓存:使用缓存对象.put和get

@Service
public class SMSCodeServiceImpl implements SMSCodeService {    

	@Override   
	public String sendCodeToSMS(String tele) {     
	   
		String code = this.codeUtils.generator(tele);  
		      
		jetSMSCache.put(tele,code);    //put
		    
		return code;    
	}   
	
	@Override    
	public boolean checkCode(String tele,String code) {  
	      
		String value = jetSMSCache.get(tele);     //get
		   
		return code.equals(value);
	}
}

重启服务,调用之前的缓存接口查看效果。出现了一个莫名奇妙的循环依赖,先临时解决下,跳过了:

spring:
	main:
    	allow-circular-references: true

发现接口调用正常,启动日志也输出了相关信息:

在这里插入图片描述

2、JetCache本地缓存

和远程一样,引入依赖后,配置文件不同:

jetcache:  
  local:    
    default:     
      type: linkedhashmap      
      keyConvertor: fastjson # 即key不是String时,用哪个转换器转为String

再后面一样的操作,开启缓存注解支持、声明缓存对象、put和get都一样,需要注意的是上面的CacheType属性改为Local

@CreateCache(name = "smsCache::", expire = 3600, cacheType = CacheType.LOCAL)  
private Cache<String, String> jetSMSCache;

3、标准配置文件

JetCache能同时支持本地和远程缓存,所以标准的配置文件写一起就行:

jetcache:  
  statIntervalMinutes: 15  
  areaInCacheName: false    # 即key里加不加area的名字,true时key形如default_myname::key
  
  local:    
    default:      
      type: linkedhashmap      
      keyConvertor: fastjson      
      limit: 100  
      
  remote:
    default:      
      host: localhost      
      port: 6379      
      type: redis      
      keyConvertor: fastjson      
      valueEncoder: java      
      valueDecoder: java      
      poolConfig:        
        minIdle: 5        
        maxIdle: 20       
        maxTotal: 50

关于配置的含义:

在这里插入图片描述

4、JetCache方法缓存注解–@Cached

上面写缓存得创建JetCache缓存对象后put和get,如何像@Cacheable注解一样,对整个方法的结果通过加注解来自动写查缓存?

请添加图片描述

答案是在@EnableCreateCacheAnnotation的基础上,再加注解@EnableMethodCache(basePackages = "com.mydemo"),开启对方法缓存注解的支持,basePackeages属性写需要用到方法缓存注解的包路径。

@SpringBootApplication
@EnableCreateCacheAnnotation  ####!
@EnableMethodCache(basePackages = "com.mydemo") ####!
public class JetCacheApplication {  
  
	public static void main(String[] args) { 
	       
		SpringApplication.run(JetCacheApplication.class, args);    
		
	}
}

@Cached注解加需要缓存的方法上,如此查到的Book对象就被缓存到default的Area,且是远程缓存

@Service
public class BookServiceImpl implements BookService {    

	@Autowired    
	private BookDao bookDao;   
	 
	@Cached(name = "smsCache_", key = "#id", expire = 3600) 
	@Override      
	public Book getById(Integer id) {
		return bookDao.selectById(id);    
	}
	
}

上面@Cache注解的cacheType属性没写,那就是默认的远程缓存。此时,调用接口返回正常,但接口日志有异常:

在这里插入图片描述

需要加一个配置,指定key的转换器给本地和远程缓存:

在这里插入图片描述

再重启,接口正常,但日志仍有报错NotSerializableException,这个就很明确了,Java对象存进缓存时,要转为json,而要存的对象的实体类没去实现序列化接口,实现下Serializable接口就行。

在这里插入图片描述
实现序列化接口后,别忘了要在配置中加:

valueEncoder: java      
valueDecoder: java    

即,编码时的是java对象,解码时,也要转汇Java对象。

5、@Cached

重新整理下@Cached注解,它的属性和@CreateCache的一样,但多了几个,放一起整理了:

属性默认值描述
areadefault如果在配置中配置了多个缓存area,在这里指定使用哪个area
name未定义($$undefined$$)指定缓存的唯一名称,不是必须的,如果没有指定,会使用类名+方法名。name会被用于远程缓存的key前缀。另外在统计中,一个简短有意义的名字会提高可读性。
key未定义使用SpEL来指定缓存的key值,如#id 、#p0
expire-2147483648过期时间
timeUnitTimeUnit.SECONDS过期时间的单位
cacheTypeCacheType.REMOTE缓存的类型,可选CacheType.REMOTE、CacheType.LOCAL、CacheType.BOTH。如果定义为BOTH,会使用LOCAL和REMOTE组合成两级缓存
localLimit-2147483648如果cacheType为LOCAL或BOTH,这个参数指定本地缓存的最大元素数量,以控制内存占用。如果注解上没有定义,会使用全局配置,如果此时全局配置也没有定义,则为100
localExpire-2147483648仅当cacheType为BOTH时适用,为内存中的Cache指定一个不一样的超时时间,通常应该小于expire
serialPolicy未定义指定远程缓存的序列化方式。可选值为SerialPolicy.JAVA和SerialPolicy.KRYO。如果注解上没有定义,会使用全局配置,如果此时全局配置也没有定义,则为SerialPolicy.JAVA
keyConvertor未定义指定KEY的转换方式,用于将复杂的KEY类型转换为缓存实现可以接受的类型,当前支持KeyConvertor.FASTJSON和KeyConvertor.NONE。NONE表示不转换,FASTJSON可以将复杂对象KEY转换成String。如果注解上没有定义,会使用全局配置
enabledtrue是否激活缓存。例如某个dao方法上加缓存注解,由于某些调用场景下不能有缓存,所以可以设置enabled为false,正常调用不会使用缓存,在需要的地方可使用CacheContext.enableCache在回调中激活缓存,缓存激活的标记在ThreadLocal上,该标记被设置后,所有enable=false的缓存都被激活
cacheNullValuefalse当方法返回值为null的时候是否要缓存
condition未定义使用SpEL指定条件,如果表达式返回true的时候才去缓存中查询
postCondition未定义使用SpEL指定条件,如果表达式返回true的时候才更新缓存,该评估在方法执行后进行,因此可以访问到#result

整体有点像@Cacheable注解。重点注意下area,一块一块的缓存区域。

4、@CacheUpdate

方法上加了@Cached后,方法返回值被写进缓存,但如果持久层被update,再查数据时。从缓存中拿到的数据就不对了,可通过在更新持久层的方法上加@CacheUpdate注解解决。先看这个注解属性:

属性默认值描述
areadefault缓存区域,注意和上面@Cached时所在的区域保持一致
namekey前缀,注意和上面@Cached时的name一致
key未定义SpEL表达式,根据当前方法的形参拼出@Cached时的key,如@Cached的方法形参为id,key为#id。而@CacheUpdate所在方法形参为Book对象book,则key为#book.id
value要更新的值
condition未定义使用SpEL指定条件,如果表达式返回true才执行更新,可访问方法结果#result
@Service
public class BookServiceImpl implements BookService {

    @CacheUpdate(name = "smsCache_", key = "#book.id", value = "#book")    
    public boolean update(Book book) {            
    	return bookDao.updateById(book) > 0;       
    }

}

对照上面的@Cached注解的key来看这个@CacheUpdate的key。此时,调用查询接口,返回更新后的数据,且不会查持久层,因为缓存已被更新,到不了持久层。

5、@CacheInvalidate

和更新一样,如果持久层数据被删除,如何通知到缓存呢,答案是@CacheInvalidate注解。

@Service
public class BookServiceImpl implements BookService {

	@CacheInvalidate(name = "smsCache_", key = "#id")    
	public boolean delete(Integer id) {        
		return bookDao.deleteById(id) > 0;    
	}
}

这样,当delete方法执行,持久层数据被删除时,缓存也就被删掉了。此时,调用查询接口,会去查持久层!!查持久层才合理,缓存里都没数据了,不去持久层看看停在缓存层干嘛 。这个注解属性和更新缓存注解一样,少了value,参照上文。

6、@CacheRefresh

以上,不管是更新还是删除,总在我的服务中,我自己掌握,我自己加了注解去通知缓存跟着变。但如果持久层更新的操作是在别的部门管理的服务里呢?即在缓存层无感知,如何保证数据最新,答案是@CacheRefresh,每隔一定间隔去查数据库,刷新缓存值。 先看注解属性:

属性默认值描述
refresh刷新间隔,谨慎设置,过小会导致查持久层频率太高,给数据库带来压力
timeUnitTimeUnit.SECONDS时间单位
stopRefreshAfterLastAccess-2147483648指定该key多长时间没有访问就停止刷新,如果不指定会一直刷新
refreshLockTimeout-2147483648类型为BOTH/REMOTE的缓存刷新时,同时只会有一台服务器在刷新,这台服务器会在远程缓存放置一个分布式锁,此配置指定该锁的超时时间

在这里插入图片描述
以上即,查到的Book对象缓存起来,且没10秒去数据库查一下,然后刷新缓存里的Book值

7、缓存统计报告

在服务配置文件application.yaml中加以下配置:

jetcache:
  statIntervalMinutes: 15
  # statInterval即统计间隔,也就是15分钟一统计

重启服务,控制台每隔15分钟输出一次统计数据,值为0时即不统计,(直接不写就行,不用写了又给个0值),效果如下:
在这里插入图片描述

查询26次,命中缓存21次。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1049923.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

QT窗口的设置、按钮的创建和对象树的概念

目录 设置窗口属性 按钮的创建 对象树 对象树的概念 构建和析构的顺序问题 设置窗口属性 在Qt官方手册中查找QWidget相关信息 或者在QT软件帮助一栏直接搜索QWidget 即可找到一些要寻找的设置属性的函数 将代码写在构造函数中 widget.cpp #include "widget.h"…

QT pyside2 线程嵌套子线程 实现开始运行和停止运行

文章目录 前言为什么要使用多线程 一、单个线程实现按钮方法的执行二、线程嵌套多个子线程实现按钮方法的执行三、QT GUI常用代码3.1 多线程取出队列任务循环执行&#xff0c;无停止3.2 将某个方法放在线程中执行3.3 QT pyside2 tableWidget 清除日志3.4 退出整个GUI程序(杀死进…

从入门到精通:详解SVN版本控制系统的使用方法

从入门到精通&#xff1a;详解SVN版本控制系统的使用方法 一、引言1.1、版本控制的概念和重要性1.2、流行的版本控制系统SVN 二、SVN基础知识2.1、SVN的基本概念和术语解释2.2、SVN的工作原理和架构 三、创建SVN仓库3.1、创建本地仓库3.2、配置访问权限 四、使用SVN进行版本控制…

基于AI图像识别的智能缺陷检测系统,在钢铁行业的应用-技术方案

目录 概述 废钢智能检判方案简介 废钢智能检判系统优势及价值 废钢人工检判过程 废钢等级检判标准 废钢检判结果 智能检判方案-废钢智能检判算法 算法一&#xff1a;废钢等级识别算法 算法二&#xff1a;不合格料的位置识别算法 算法三&#xff1a;不合格料的类型识别…

docker-compose 网络配置- IP 主机名 hosts配置

docker-compose 配置IP、hostname、hosts配置 配置IP version: "3" networks:bd-network: # 声明网络external: true services:kafka: # 服务名称networks:bd-network: # 连接的网络名称ipv4_address: 172.2.0.102 # 配置IP配置 主机名 version: "3&quo…

DevExpress WinForms图表组件 - 直观的数据信息呈现方式!(二)

在上文中&#xff08;点击这里回顾>>&#xff09;&#xff0c;我们为大家介绍了DevExpress WinForms图表控件的互动图表、图标设计器及可定制功能等&#xff0c;本文将继续介绍DevExpress WinForms图表控件的数据分析、大数据功能等&#xff0c;欢迎持续关注我们哦~ Dev…

数据结构与算法——17.二叉搜索树

这篇文章我们来看一下数据结构中的二叉搜索树。 目录 1.概述 2.二叉搜索树的实现 3.总结 1.概述 我们前面学到的数据结构&#xff0c;比如&#xff1a;动态数组、链表、队列、栈、堆&#xff0c;这些数据结构存储完数据后&#xff0c;我们要去查找某个数据&#xff0c;它的…

FPGA 多路视频处理:图像缩放+视频拼接显示,HDMI采集,提供2套工程源码和技术支持

目录 1、前言版本更新说明免责声明 2、相关方案推荐FPGA图像缩放方案推荐FPGA视频拼接方案推荐 3、设计思路框架视频源选择IT6802解码芯片配置及采集动态彩条缓冲FIFO图像缩放模块详解设计框图代码框图2种插值算法的整合与选择 视频拼接算法图像缓存视频输出 4、vivado工程1&am…

PIE:1979-2018年中国气温数据产品(空间分辨率为0.1º)

简介 中国气温数据产品包含1979-2018年期间中国的近地表气温数据&#xff08;单位为摄氏度&#xff09;&#xff0c;时间分辨率为每日&#xff0c;空间分辨率为0.1。本产品集成了再分析数据&#xff08;ERA5、CMFD&#xff09;、遥感数据&#xff08;MODIS&#xff09;、原位数…

RISC-V架构的函数调用规范和栈布局

1、函数调用中寄存器规范 2、函数调用规范 &#xff08;1&#xff09;函数的前8个参数使用a0-a7寄存器传递&#xff0c;如果传参多于8个&#xff0c;则除前8个参数使用寄存器来传递之外&#xff0c;后面的参数使用栈传递&#xff1b; &#xff08;2&#xff09;如果传递的参数小…

《学术小白学习之路10》论文常见方法:Doc2vec-句向量模型实现

1. 数据 用于文献的摘要的相似度的计算 ## 导包 import pandas as pd import jieba import gensim from gensim.models import Doc2Vec from gensim.models.doc2vec import TaggedDocument再定义停用词典,用于分词,还可以自己定义一个分词词典 ## 读入数据 papers = pd.&l…

TensorFlow入门(一、环境搭建)

一、下载安装Anaconda 下载地址:http://www.anaconda.comhttp://www.anaconda.com 下载完成后运行exe进行安装 二、下载cuda 下载地址:http://developer.nvidia.com/cuda-downloadshttp://developer.nvidia.com/cuda-downloads 下载完成后运行exe进行安装 安装后winR cmd进…

解密PDF密码

PDF文件有两种密码&#xff0c;一个打开密码、一个限制编辑密码&#xff0c;因为PDF文件设置了密码&#xff0c;那么打开、编辑PDF文件就会受到限制。忘记了PDF密码该如何解密&#xff1f; PDF和office一样&#xff0c;可以对文件进行加密&#xff0c;但是没有提供恢复密码的功…

解决craco启动react项目卡死在Starting the development server的问题

现象&#xff1a; 原因&#xff1a;craco.config.ts配置文件有问题 经过排查发现Dev开发模式下不能有splitChunk的配置&#xff0c; 解决办法&#xff1a; 加一个生产模式的判断&#xff0c;开发模式不加载splitChunk的配置&#xff0c;仅在生产模式才加载 判断条件代码&#…

基于微信小程的流浪动物领养小程序设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言系统主要功能&#xff1a;具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计…

安防监控产品经营商城小程序的作用是什么

安防监控产品覆盖面较大&#xff0c;监控器、门禁、对讲机、烟感等都有很高用途&#xff0c;家庭、办公单位各场景往往用量不少&#xff0c;对商家来说&#xff0c;市场高需求背景下也带来了众多生意&#xff0c;但线下门店的局限性&#xff0c;导致商家想要进一步增长不容易。…

进阶指针(二)

#国庆发生的那些事儿# ✨博客主页&#xff1a;小钱编程成长记 &#x1f388;博客专栏&#xff1a;进阶C语言 &#x1f388;推荐相关博文&#xff1a;进阶指针&#xff08;一&#xff09; 进阶指针&#xff08;二&#xff09; 6.函数指针数组6.1例子 7.指向函数指针数组的指针8.…

OpenHarmony自定义组件介绍

一、创建自定义组件 在ArkUI中&#xff0c;UI显示的内容均为组件&#xff0c;由框架直接提供的称为系统组件&#xff0c;由开发者定义的称为自定义组件。在进行 UI 界面开发时&#xff0c;通常不是简单的将系统组件进行组合使用&#xff0c;而是需要考虑代码可复用性、业务逻辑…

四、YApi的安装和配置

YApi是去哪儿网的前端技术中心的一个开源可视化接口管理平台。 创建接口项目 创建接口 编写接口

中文读唇总动员:CNVSRC 2023 视觉语音识别挑战赛启动

由 NCMMSC 2023 组委会发起&#xff0c;清华大学、北京邮电大学、海天瑞声、语音之家共同主办的 CNVSRC 2023 中文连续视觉语音识别挑战赛即日启动&#xff0c;诚邀参与报名。 赛事官网&#xff1a;http://cnceleb.org/competition 视觉语音识别&#xff0c;也称唇语识别&…