SpringBoot缓存技术详解

news2024/11/27 11:52:12

文章目录

  • 一、 缓存技术介绍
    • 1. 缓存技术简介
    • 2. JSR107核心接口
    • 3. JSR107 图示
    • 3. SpringBoot缓存抽象
    • 4. 缓存常用注解和接口
  • 一、 缓存技术实战
    • 1. @Cacheable注解
    • 2. 缓存的工作原理
    • 4. @Cacheable注解的工作流程

一、 缓存技术介绍

1. 缓存技术简介

缓存技术主要分为两大类缓存可分为2大类:

  • 本地缓存:速度快、效率高,但分布式环境下容易出现数据不一致的问题、且缓存的数据量一般不能太大,常见的比如guava、ehcache、caffeine
  • 分布式缓存:速度比本地缓存慢,常用于多个服务、应用之间的数据共享,常见的比如redis、memcached

Spring Boot提供了对多种本地缓存技术的支持,例如Caffeine、Ehcache、Guava等。本地缓存技术常用于提高应用程序的性能,避免频繁地访问数据库或其他外部资源,同时也可以降低系统的负载。JSR是Java Specification Requests 的缩写 ,Java规范请求,故名思议提交Java规范, JSR-107呢就是关于如何使用缓存的规范,是java提供的一个接口规范,类似于JDBC规范,没有具体的实现,具体的实现就是reds等这些缓存。

2. JSR107核心接口

Java Caching(JSR-107)定义了5个核心接口,分别是CachingProvider、CacheManager、Cache、Entry和Expiry。

  • CachingProvider(缓存提供者):创建、配置、获取、管理和控制多个CacheManager
  • CacheManager(缓存管理器):创建、配置、获取、管理和控制多个唯一命名的Cache,Cache存在于CacheManager的上下文中。一个CacheManager仅对应一个CachingProvider
  • Cache(缓存):是由CacheManager管理的,CacheManager管理Cache的生命周期,Cache存在于CacheManager的上下文中,是一个类似map的数据结构,并临时存储以key为索引的值。一个Cache仅被一个CacheManager所拥有
  • Entry(缓存键值对):是一个存储在Cache中的key-value对
  • Expiry(缓存时效):每一个存储在Cache中的条目都有一个定义的有效期。一旦超过这个时间,条目就自动过期,过期后,条目将不可以访问、更新和删除操作。缓存有效期可以通过ExpiryPolicy设置

3. JSR107 图示

在这里插入图片描述

一个应用里面可以有多个缓存提供者(CachingProvider),一个缓存提供者可以获取到多个缓存管理器(CacheManager),一个缓存管理器管理着不同的缓存(Cache),缓存中是一个个的缓存键值对(Entry),每个entry都有一个有效期(Expiry)。缓存管理器和缓存之间的关系有点类似于数据库中连接池和连接的关系。

使用JSR107需要导入依赖:

<dependency>
	<groupId>javax.cache</groupId>
	<artifactId>cache-api</artifactId>
</dependency>	

3. SpringBoot缓存抽象

Spring从3.1开始定义了org.springframework.cache.Cache和org.springframework.cache.CacheManager接口来统一不同的缓存技术,并支持使用JCache(JSR-107)注解来简化缓存开发
在这里插入图片描述

  • Cache接口为缓存的组件规范定义,包含缓存的各种操作集合。
  • Cache接口下Spring提供了各种xxxCache的实现,如RedisCache、EhCacheCache等。
  • 每次调用需要缓存功能的方法时,Spring会检查指定参数的目标方法是否已经被调用过,如果已经被调用过就直接从缓存中获取方法调用后的结果;如果没有调用过就调用方法并缓存结果后返回给用户,下次调用直接从缓存中获取。
  • 使用Spring缓存抽象的时候我们需要关注:
    • 确定方法需要被缓存以及它们的缓存策略。
    • 从缓存中读取数据之前需要缓存存储的数据

4. 缓存常用注解和接口

在这里插入图片描述

一、 缓存技术实战

1. @Cacheable注解

  • 将方法运行的结果进行缓存,以后再要相同的数据,直接从缓存中获取,不需要再调用方法。
  • CacheManager管理多个Cache组件,对缓存真正的CRUD操作在Cache组件中,每一个缓存组件都有自己唯一的名称。
  • 属性:
    ■ value/cacheNames:指定缓存组件的名称
    ■ key:缓存数据使用的key,默认是方法参数的值(如果传入的参数是1,那么值就是1对应的返回的返回值。),支持SPEL表达式。
    ■ keyGenerator:key的生成器,可以自己指定key的生成器的组件id。key和keyGenerator只能二选一。
    ■ cacheManager:指定缓存管理器。
    ■ cacheResolver:指定缓存解析器。
    ■ condition:指定符合条件的情况下才缓存。支持SPEL表达式。
    ■ unless:否定缓存。当unless指定的条件为true,方法的返回值就不会返回;可以获取到结果进行判断。
    ■ sync:是否同步,默认值是false,即异步,在多线程环境中需要设置为true,避免缓存击穿的问题。
  • 实战

在启动类上使用@EnableCaching注解开启缓存

package com.sunxiaping.springboot;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;

@SpringBootApplication
@MapperScan(basePackages = "com.sunxiaping.springboot.mapper")
@EnableCaching
public class SpringbootApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringbootApplication.class, args);
    }

}

使用@Cacheable注解方法返回的结果缓存:

package com.sunxiaping.springboot.service.impl;

import com.sunxiaping.springboot.domain.Employee;
import com.sunxiaping.springboot.mapper.EmployeeMapper;
import com.sunxiaping.springboot.service.EmployeeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Optional;

/**
 * @author 许威威
 * @version 1.0
 */
@Service
@Transactional
public class EmployeeServiceImpl implements EmployeeService {

    @Autowired
    private EmployeeMapper employeeMapper;
    /**
     * @Cacheable注解: 将方法的运行结果进行缓存,以后再要相同的数据,直接从缓存中获取,不需要再调用方法
     * CacheManager管理多个Cache组件,对缓存的真正CRUD操作在Cache组件中,每一个缓存组件都有自己唯一的名称
     * @Cacheable注解的属性:
     *      value/cacheNames:指定缓存组件的名称
     *      key:缓存数据使用的key,默认是方法参数的值(如果传入的参数是1,那么值就是1对应的返回的返回值。),支持SPEL表达式。
     *      keyGenerator:key的生成器,可以自己指定key的生成器的组件id。key和keyGenerator二选一。
     *      cacheManager:指定缓存管理器。
     *      cacheResolver:指定缓存解析器。
     *      condition:指定符合条件的情况下才缓存。支持SPEL表达式。
     *      unless:否定缓存。当unless指定的条件为true,方法的返回值就不会返回。
     *      sync:是否同步,默认值是false,即异步,在多线程环境中需要设置为true,避免缓存击穿的问题。
     */
    @Cacheable(cacheNames = "emp", key = "#id")
    @Override
    public Employee findEmpById(Integer id) {
        return Optional.ofNullable(employeeMapper.findEmpById(id)).orElse(new Employee());
    }
}

2. 缓存的工作原理

  • 缓存的自动配置类源码
@AutoConfiguration(after = { CouchbaseDataAutoConfiguration.class, HazelcastAutoConfiguration.class,
		HibernateJpaAutoConfiguration.class, RedisAutoConfiguration.class })
@ConditionalOnClass(CacheManager.class)
@ConditionalOnBean(CacheAspectSupport.class)
@ConditionalOnMissingBean(value = CacheManager.class, name = "cacheResolver")
@EnableConfigurationProperties(CacheProperties.class)
//这个注解给可以知道其向Spring容器中导入了一些组件
@Import({ CacheConfigurationImportSelector.class, CacheManagerEntityManagerFactoryDependsOnPostProcessor.class })
public class CacheAutoConfiguration {

	@Bean
	@ConditionalOnMissingBean
	public CacheManagerCustomizers cacheManagerCustomizers(ObjectProvider<CacheManagerCustomizer<?>> customizers) {
		return new CacheManagerCustomizers(customizers.orderedStream().collect(Collectors.toList()));
	}

	@Bean
	public CacheManagerValidator cacheAutoConfigurationValidator(CacheProperties cacheProperties,
			ObjectProvider<CacheManager> cacheManager) {
		return new CacheManagerValidator(cacheProperties, cacheManager);
	}

	@ConditionalOnClass(LocalContainerEntityManagerFactoryBean.class)
	@ConditionalOnBean(AbstractEntityManagerFactoryBean.class)
	static class CacheManagerEntityManagerFactoryDependsOnPostProcessor
			extends EntityManagerFactoryDependsOnPostProcessor {

		CacheManagerEntityManagerFactoryDependsOnPostProcessor() {
			super("cacheManager");
		}

	}

通过CacheAutoConfiguration上面的@Import注解,可以知道其向Spring容器中导入了一些组件,dubug后的缓存配置类如下所示

  • SimpleCacheConfiguration给容器中添加了ConcurrentMapCacheManager组件
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(CacheManager.class)
@Conditional(CacheCondition.class)
class SimpleCacheConfiguration {
	
    //给容器中添加了ConcurrentMapCacheManager组件
	@Bean
	ConcurrentMapCacheManager cacheManager(CacheProperties cacheProperties,
			CacheManagerCustomizers cacheManagerCustomizers) {
		ConcurrentMapCacheManager cacheManager = new ConcurrentMapCacheManager();
		List<String> cacheNames = cacheProperties.getCacheNames();
		if (!cacheNames.isEmpty()) {
			cacheManager.setCacheNames(cacheNames);
		}
		return cacheManagerCustomizers.customize(cacheManager);
	}

}
  • ConcurrentMapCacheManager的部分源码如下:可以获取和创建ConcurrentMapCache类型的缓存组件,并把数据保存在ConcurrentMap中
public class ConcurrentMapCacheManager implements CacheManager, BeanClassLoaderAware {

    //重写CacheManager的getCache方法
    @Override
	@Nullable
	public Cache getCache(String name) {
         //根据传入的name从CacheManager中获取Cache对象
		Cache cache = this.cacheMap.get(name);
        //如果cache不存在
		if (cache == null && this.dynamic) {
            //加锁
			synchronized (this.cacheMap) {
                //再获取一次
				cache = this.cacheMap.get(name);
                //如果依然不遵从
				if (cache == null) {
                     //创建一个新的ConcurrentMapCache并返回
					cache = createConcurrentMapCache(name);
                     //将上面创建的ConcurrentMapCache作为value放入到CacheManager中,key就是传入的name
					this.cacheMap.put(name, cache);
				}
			}
		}
		return cache;
	}
}

4. @Cacheable注解的工作流程

  • 方法运行之前,先去查询Cache(缓存组件),按照cacheNames(指定的缓存名称,可以在配置文件中指定)从CacheManager中获取相应的缓存组件。
  • 第一次获取缓存,如果没有对应的Cache组件,会自动创建Cache组件(默认为ConcurrentMapCache),然后将其保存到ConcurrentMapCacheManager中的cacheMap中,key是cacheNames,value是ConcurrentMapCache。
  • 根据指定的key,即@Cacheable注解中属性key对应的值(默认是方法传入的实际参数值),去Cache中查找缓存的内容。
    • key是按照某种策略自自动生成的,默认是使用keyGenerator(SimpleKeyGenerator)生成的。
    • 如果没有参数,key=new SimpleKey()。
    • 如果有一个参数,key=参数值。
    • 如果有多个参数,key就是new SimipleKey(params)。
  • 没有查到缓存就调用目标方法。
  • 将目标方法返回的结果,放入到缓存。

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

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

相关文章

6 进程的环境

6.1 main函数 C程序总是从main函数开始执行。main函数的原型是&#xff1a; int main(int argc, char *argv[]) 6.2 进程终止 有五种方式使进程终止&#xff1a; &#xff08;1&#xff09;正常终止&#xff1a; &#xff08;a&#xff09;从main返回。 &#xff08;b&…

Pycharm十种不为人所知的技巧,不得不知道

Pycharm是Python语言开发中的一个非常强大的IDE工具&#xff0c;其高度的定制能力、日常开发中常用的工具和各种快捷键等功能&#xff0c;都能帮助Pycharm用户提高开发效率。但是&#xff0c;Pycharm中的许多功能并不为人所知。因此&#xff0c;以下是十种Pycharm技巧&#xff…

【MCS-51】51单片机指令系统大全

指令是指挥微型计算机工作的的计算机命令&#xff0c;对于51单片机来说&#xff0c;其主要使用的指令有两种形式&#xff1a;机器语言指令和汇编语言指令。 机器语言指令是指使用二进制代码表示的指令&#xff1b; 汇编语言指令是指使用容易我们记忆的缩写符号表示的机器语言…

YOLO入门指南:理解YOLO原理及构建第一个目标检测模型

YOLO&#xff08;You Only Look Once&#xff09;是一种快速且准确的目标检测算法&#xff0c;可以在图像或视频中检测出多个对象的位置和类别。在本篇文章中&#xff0c;我们将介绍YOLO的基本原理&#xff0c;并使用TensorFlow构建第一个目标检测模型。 YOLO的基本原理 YOLO的…

linux 安装jdk、tomcat

文章目录 前言一、Linux上安装jdk1、jdk安装与配置过程2、linux查看jdk安装路径 二、Linux上安装tomcat1、tomcat安装与配置过程2、对外开放访问的端口、重启防火墙、查看日志 三、在window系统中通过浏览器访问 前言 先检察是否安装jdk java -jar ## 查看是否安装jdk java -…

K8S—Helm

一、Helm介绍 helm通过打包的方式&#xff0c;支持发布的版本管理和控制&#xff0c;很大程度上简化了Kubernetes应用的部署和管理。 Helm本质就是让k8s的应用管理&#xff08;Deployment、Service等&#xff09;可配置&#xff0c;能动态生成。通过动态生成K8S资源清单文件&a…

文笔润色-文本校对改写工具

文段改写软件 写作是一项对于很多人来说都需要频繁进行的活动&#xff0c;无论是工作中的商业写作还是学术写作&#xff0c;在完成优质内容的同时也需要付出大量的时间和精力进行语言润色和修改。然而&#xff0c;现在有了147ChatGPT改写润色软件&#xff0c;该软件可以全自动…

近期分享学习心得

1、数据类型 原始类型undefined null number string boolean symbol bigint 引用类型 对象 2、大厂为什么不允许赋值undifined&#xff1f; 必须let avoid 0;效果一样 void是关键字&#xff0c;后面跟表达式&#xff0c;无论跟啥最终制造undefined&#xff0c;但是习惯写0。…

动态规划设计

文章目录 动态规划设计一、什么是最长递增子序列&#xff1f;[300. 最长递增子序列](https://leetcode.cn/problems/longest-increasing-subsequence/)注意子序列和子串的区别&#xff1a; 二、动态规划解法2.1什么是数学归纳法&#xff1f;2.2最长递增子序列中数学归纳的实际应…

simulink电力系统仿真(1):电力系统库+(电力系统基础知识)

文章目录 基础知识仿真库搭建一个简单的电路 基础知识 ★三相交流电&#xff1a;三相电是三组幅值相等、频率相等、相位互相差120的交流电&#xff0c;由有三个绕组的三相发电机产生&#xff0c;是工业上常用的电源&#xff0c;可提供超过数千瓦或以上功率的电力。★电力系统暂…

看一看吧,面试真的卷......

大家好&#xff0c;最近有不少小伙伴在后台留言&#xff0c;今年面试实在是太卷了&#xff0c;不知道从何下手&#xff01; 不论是跳槽涨薪&#xff0c;还是学习提升&#xff01;先给自己定一个小目标&#xff0c;然后再朝着目标去努力就完事儿了&#xff01; 为了帮大家节约…

美术培训学校学生作品管理平台

本系统主要是为了美术培训学校和学生使用的&#xff0c;系统分为了前台和后台两部分&#xff0c;前台部分主要是展示美术培训学校的信息和让学生查看自己的课程信息服务的&#xff0c;后台主要是管理人员对系统进行管理使用的 前台部分功能 1. 网站首页&#xff0c;首页部分…

jar的反编译为java文件

目录 1、cfr工具下载 2、反编译指令 3、反编译说明 1、cfr工具下载 反编译插件工具比较多&#xff0c;但是我认为最后用的工具为cfr&#xff0c;基本能解决所有jar包&#xff0c;下载地址为&#xff1a;cfr官网 点击图中位置下载即可 2、反编译指令 来到你下载完成cfr目录下&…

蓝牙耳机哪个牌子好?数码粉总结学生平价蓝牙耳机推荐

蓝牙耳机这几年发展飞速&#xff0c;涌现了很多品牌和产品&#xff0c;越来越多的用户选择放弃有线耳机使用蓝牙耳机&#xff0c;学生们也不例外。前段时间看到网上很多学生在讨论蓝牙耳机哪个牌子好&#xff0c;我整理了五款口碑最好的学生平价蓝牙耳机推荐清单&#xff1a; 1…

cesium坐标系转换:经纬度地理坐标系 弧度地理坐标系 笛卡尔坐标 屏幕坐标之间的相互转换

参考了网上资料 核心就是 cesium 计算的地理数据用弧度坐标系表示&#xff08;很多公式计算出来的是弧度结果&#xff09;&#xff0c;我们采集的数据是经纬度表示的&#xff08;即我们正常的经纬度&#xff09;&#xff0c;围绕着cesium球体展示的用笛卡尔坐标系计算的其方位…

5月新刊 | MDPI版面费将全面上涨,还有哪些期刊可投?(新增多领域高性价比新刊, 含CCF-B/SSCI/EI)~

近期MDPI官方发布消息称&#xff0c;MDPI出版社旗下期刊的OA论文处理费 (APC), 价格将在2023年6月底上涨&#xff0c;超过90种OA期刊的APC涨幅在200-1200瑞士法郎 (折合人民币1560元-9300元)。 在MDPI出版的OA期刊中&#xff0c;有5种期刊处于2022年中国通迅作者发表OA论文数量…

junit如何在多模块项目中使用

文章目录 前言一、最简单的单元测试二、springboot多模块测试单元1.问题2.解决 总结 前言 相信后端的小伙伴对于junit测试应该不陌生,当我们写好了一些功能之后,由于不太放心是否会出现问题,我们会选择自测; 第一种 通过类似postman之类的,直接走接口测试第二种 由于构造数据…

Halcon 找到产品上 圆圈中的7个点

文章目录 1 关键实现环节演示2 完整代码 及 原图文章目录 1 关键实现环节演示2 完整代码 及 原图找到下图 圆圈中的7个点; 思路: 先找到圆圈外面的矩形, 再找到里面的圆圈, 最后找到圆圈里面的 圆点 1 关键实现环节演示 二值化 阈值分割止 之后,打散, read_image (im…

很多博主用Markdown格式文章?直呼真不错!

概述 Markdown 是一种轻量级标记语言&#xff0c;它可以使我们专注于写作内容&#xff0c;而不用过多关注排版&#xff0c;很多博主、作家等都用它来撰写文章~ 本文将给各位小伙伴介绍 Markdown 语法的使用&#xff0c;本篇文章索奇就是用的纯 markdown 语法来写的~ 标题 一级…

EKMA曲线绘制、MCM箱模型应用与O3形成途径、生成潜势、敏感性分析

目录 EKMA曲线及大气O3来源解析 MCM箱模型实践技术应用与O3形成途径、生成潜势、敏感性分析 一、 大气中O3形成知识基础、MCM和Atchem2原理及Linux系统安装 二、 MCM建模、数据输入、模型运行及结果输出 【讲解案例操作】 三、 O3形成途径、生成潜势及其敏感性分析 【讲解…