百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术资源 > 正文

SpringBootCache源码解析:默认Cache配置

moboyou 2025-09-29 07:36 11 浏览

默认 Cache 配置

当使用@EnableCachina 启动 Spring Boot 的缓存机制但又未添加其他缓存类库时,SpringBoot 会默认提供一个基 于 ConcurrentHashMap 实现的缓存组件
--ConcurrentMap-CacheManager。 但官方文档已经明确提示,不建议在生产环境中使用该缓存组件。但它却是一个很好的学习缓存特性的工具。

这个默认的缓存组件是通过 SimpleCacheConfiguration 来完成自动配置的。下面,我们简单了解一下它的自动配置以及 ConcurrentMapCacheManager 的实现。

@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(CacheManager.class)
@Conditional(CacheCondition. class)
class SimpleCacheConfiguration {
@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);}
}

该 自 动 配 置 文 件 很 简 单 , 当 容 器 中 不 存 在 CacheManager 的 Bean, 同 时 满 足CacheCondition 中指定的条件时,则进行自动配置。关于 CacheCondition 中的业务逻辑实现已经在上一节进行了详细地讲解,不再赘述。

在 cacheManager 方法中首先创建了- -个 ConcurrentMapCacheManager 对象,然后通过配置属性类获得缓存名称列表,如果列表内容不为空,则赋值给上述对象 cacheManager。

最后调用 CacheManagerCustomizers 的 customize 方法对 cacheManager 进行定制化处理并返回。

下面我们重点看 cacheManager 方法中 ConcurrentMapCacheManager 类的内部实现。通过名字就可以看出它是基于 ConcurrentHashMap 来实现的,它是接口 CacheManager 的实现类,同时也实现了 BeanClassLoaderAware 接口用来获取 SerializationDelegate 及进行一些初始化操作。

首先看 ConcurrentMapCacheManager 的成员变量部分源代码。

public class ConcurrentMapCacheManager implements CacheManager, BeanClassLo
aderAware {
// ConcurrentMapCacheManager 缓存的基础数据结构,用于存储缓存数据 private final
ConcurrentMap<String, Cache> cacheMap = new ConcurrentHashMap<>(16);
//是否为动态创建缓存
private boolean dynamic = true;
//是否允许 null 值
private boolean allowNullValues = true;
//是否存储 value 值
private boolean storeByValue = false;
//用于序列化的委托类,通过实现 BeanClassLoaderAware 接口注入,用子值的序列化和反
序列号
@Nullable
private SerializationDelegate serialization;
}

在 ConcurrentMapCacheManager 中定义了 ConcurrentMap<String,Cache>的成员变量,用于存储 Cache,无论后面是获取还是存储缓存类(Cache) ,都围绕该成员变量来进行操作。

这里采用的 ConcurrentHashMap 是 Java 中的一个线程安全且高效的 HashMap 实现。

dynamic 属性定义了缓存是动态创建还是静态创建,true 表示动态创建 ,false 表示静态创建,后面在涉及具体的方法功能时会用到; allowNullValues 用来表示是否允许 nul 值;

storeByValue 表示是否需要存储值, 如果需要存储值则需配合 serialization 顺序性进行序列化和反序列号操作。这里的存储值指的是复制的 value 值,与存储引用相对,存储值(复制的 value 值)时才会进行序列化和反序列化。

下面从 ConcurrentMapCacheManager 的构造方法开始来进行相关方法的讲解。

public class ConcurrentMapCacheManager implements CacheManager, BeanClassLoaderAware.
//实现为空的构造方法,用于构建.
动态的 ConcurrentMapCacheManager,
//当缓存实例被请求时进行懒加裁
public ConcurrentMapCacheManager() {
//构建一个静态的 ConcurrentMapCacheManager, 仅管理捐定缓存名称的缓存
public ConcurrentMapCacheManager(Stri
, cacheNames) {
setCacheNames (Arrays . aslist(cacheNames));
/设置缓存名称或重置缓存模式
public void setCacheNames (@Nullable Collection<String> cacheNames) {
if (cacheNames != null)
for (String name : cacheNames){
this . cacheMap. put(name, createConcurrentMapCache(name));
this.dynamic = false;
} else
this . dynamic = true;
}
}
}

ConcurrentMapCacheManager 提供了两个构造方法,第一-个构造方法用于构建一个动态的 ConcurrentMapCacheManager, 构造方法实现为空。在自动配置中便是采用的该构造方法,默认情况下,dynamic 属 性的为 true,即动态构建,当缓存实例被请求时进行懒加载。

另外一个构造方法的参数为不定参数,构造方法内的核心操作就是调用 setCacheNames 方法。在 setCacheNames 方法内部, 如果 cacheNames 不为 null,也就是采用“静态”模式,会遍历缓存名称,并初始化 cacheMap 中的值。这里需要注意的是,一旦进入该业务逻辑操作,也就意味着缓存的属性及名称将被固定,运行时不会再创建其他缓存区域。

那么,如果想改变这种“不变"的情况该如何处理?还是调用该方法,设置参数 cacheNames为 null,此时执行 else 中的逻辑,将 dynamic 设置 为 true,即静态模式重置为动态模式,从而允许再次创建缓存区域。setCacheNames 方法为 public,因此不仅构造方法可以调用,其实例化对象也可以直接调用进行设置。

在第二个构造方法中调用了当前类的 createConcurrentMapCache 方法,代码如下。

protected Cache createConcurrentMapCache(String name) {
SerializationDelegate actualSerialization = (isStoreByValue() ? this.seri
alization : null);
return new ConcurrentMapCache(name, new ConcurrentHashMap<> (256),
isAllowNullValues(),actualSerialization);
}

createConcurrentMapCache 方法的主要作用就是创建一个 ConcurrentMapCache,它是Cache 接口的简单实现。该方法内,首先根据属性 storeByValue 的值判断是否需要Serializa-tionDelegate 来进行序列化操作,如果不需要则将 SerializationDelegate 设置为null。然后,将缓存名称、缓存值、是否允许 Nul1 值和序列化委托类当作构造参数创建Concurrent-MapCache 类并返回。

在 ConcurrentMapCacheManager 中有-个私有的 recreateCaches 方法,在满足条件的情况下会遍历 cacheMap 并调用上面 createConcurrentMapCache 方法进行缓存的重置操作。

private void recreateCaches() {
for (Map. Entry<String, Cache> entry : this. cacheMap .entrySet()) {
entry . setValue(createConcurrentMapCache(entry . getKey()));
}

当 allowNullValues 或 storeByValue 的值通过 set 方法改变时,均会调用 recreateCaches方法进行缓存的重置。

最后看 ConcurrentMapCacheManager 对 getCacheNames 和 getCache 方法的实现。

@Override
public Collection<String> getCacheNames() {
return Collections . unmodifiableSet(this . cacheMap. keySet());
@Override
@Nullable
public Cache getCache(String name) {
Cache cache = this. cacheMap . get(name);
if (cache == null && this. dynamic) {
synchronized (this . cacheMap) {cache = this. cacheMap . get(name);
if (cache == null) {
cache = createConcurrentMapCache(name);
this. cacheMap . put(name, cache);
}
}
}
return cache; }

getCacheNames 方法直接获取 cacheMap 中 name 的 Set,并通过 Collections 类将其设置为不可变的集合并返回。

getCache 方法首先根据 name 从 cacheMap 中获取 Cache 值,如果值为 null 并且是动态模式,则对 cacheMap 加锁同步, 重新获取判断,如果 cache 依旧为 null,则调用create-ConcurrentMapCache 方 法创建并给 cacheMap 赋值。否则,直接返回 cache 值。

至此,关于 ConcurrentMapCacheManager 的基本功能也讲解完毕。 在此提醒一下,这只是一一个简单的 CacheManager,并没有缓存配置项,仅可用于测试环境和简单的缓存场景。

对于高级的本地缓存需求建议使用 JCacheCacheManager、EhCacheCacheManager、CaffeineCacheManager 等方法。

最后,我们再稍微拓展一下上面提到的 ConcurrentMapCache 类,该类实现了 Cache 接口,提供了缓存值的存储和获取等实现。而这些功能的实现就是围绕上面提到构造该类时传入的参数展开的。

以 ConcurrentMapCache 的 put 方法及相关方法为例,我们简单说一下它的实现过程。

@Override
public void put(0bject key, @Nullable object value) {
this . store. put(key, toStoreValue(value));
@Override
protected object toStoreValue (@Nullable object userValue) {
//父类的 toStoreValue 方法实现,用于检查是否允许 null。如果值为 null 且允许为 null,则返
@NullValue.
INSTANCE
Object storeValue = super . toStoreValue(userValue);
if (this. serialization != null) {
try {
//对质进行序列化
return serializeValue(this . serialization, storeValue);
catch (Throwable ex) {throw new IllegalArgumentException("Failed to serialize cache valueuserValue +
"'. Does it implement Serializabl
e?", ex);
} else {
return storeValue;
//通过传入的 Serial izationDelegate 序列化缓存值为 byte 数组
private object serializeValue(SerializationDelegate serialization, object s
toreValue) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
try {
serialization. serialize(storeValue, out);
return out. toByteArray();
} finally {
out. close();
}

上面为 put 方法涉及的操作,基本步骤是如下。

.判断待设置的 userValue 的值是否为 mull,如果为 mull 且允许存储 mull 值,返回NullValue.INSTANCE。 否则,直接返回 userValue 值。 以上值均赋值给 storeValue。

如果序列化委托类(serialization )不为 null, 则通过 SerializationDelegate 对 storeValue 值进行序列化操作。如果为 mull,则直接返回 store Value。

.无论经过以上步骤获得的是原始传入值、NullValue.INSTANCE 或是经过序列化的字节数组 , 都 通 过 store 的 put 方 法 将 其 存 储 。 store 的数 据 结 构 为Concurrent-Map<Object,Object>,就是我们创建 ConcurrentMapCache 时传入的参数之一。

其中第一个 Object 为缓存的 key,第二个 Object 为缓存的具体数据。

至此,Spring Boot 默认,的。Cache 配置就讲解完毕了,关于滚动鼠标轴或单击,开始截长图 ConcurrentMapCache 类的其他方法实现,读者朋友可自行阅读相关源码,不过基本上都是围绕上面提到的一-些属性和数据结构展开的。

小结

本章重点介绍了 Spring Boot 中缓存的自动配置以及基于 ConcurrentHashMap 实现的最简单 的 缓 存 功 能 。 涉 及 的 缓 存 实 现 都 只 是 基 于 Java 提 供 的 数 据 结 构 (Collection 、ConcurrentHashMap) 存储来实现的。而在实战过程中,根据不同的场景会使用不同的三方缓存组件,比如 JCache、EhCache、Caffeine、 Redis 等。 但基本的实现原理一致,读者朋友可参照本章内容进行具体的分析学习。

本文给大家讲解的内容是SpringBootCache源码解析:默认Cache配置

  1. 下篇文章给大家讲解的是Spring Boot 日志源码解析;
  2. 觉得文章不错的朋友可以转发此文关注小编;
  3. 感谢大家的支持!

相关推荐

Excel技巧:SHEETSNA函数一键提取所有工作表名称批量生产目录

首先介绍一下此函数:SHEETSNAME函数用于获取工作表的名称,有三个可选参数。语法:=SHEETSNAME([参照区域],[结果方向],[工作表范围])(参照区域,可选。给出参照,只返回参照单元格...

Excel HOUR函数:“小时”提取器_excel+hour函数提取器怎么用

一、函数概述HOUR函数是Excel中用于提取时间值小时部分的日期时间函数,返回0(12:00AM)到23(11:00PM)之间的整数。该函数在时间数据分析、考勤统计、日程安排等场景中应用广泛。语...

Filter+Search信息管理不再难|多条件|模糊查找|Excel函数应用

原创版权所有介绍一个信息管理系统,要求可以实现:多条件、模糊查找,手动输入的内容能去空格。先看效果,如下图动画演示这样的一个效果要怎样实现呢?本文所用函数有Filter和Search。先用filter...

FILTER函数介绍及经典用法12:FILTER+切片器的应用

EXCEL函数技巧:FILTER经典用法12。FILTER+切片器制作筛选按钮。FILTER的函数的经典用法12是用FILTER的函数和切片器制作一个筛选按钮。像左边的原始数据,右边想要制作一...

office办公应用网站推荐_office办公软件大全

以下是针对Office办公应用(Word/Excel/PPT等)的免费学习网站推荐,涵盖官方教程、综合平台及垂直领域资源,适合不同学习需求:一、官方权威资源1.微软Office官方培训...

WPS/Excel职场办公最常用的60个函数大全(含卡片),效率翻倍!

办公最常用的60个函数大全:从入门到精通,效率翻倍!在职场中,WPS/Excel几乎是每个人都离不开的工具,而函数则是其灵魂。掌握常用的函数,不仅能大幅提升工作效率,还能让你在数据处理、报表分析、自动...

收藏|查找神器Xlookup全集|一篇就够|Excel函数|图解教程

原创版权所有全程图解,方便阅读,内容比较多,请先收藏!Xlookup是Vlookup的升级函数,解决了Vlookup的所有缺点,可以完全取代Vlookup,学完本文后你将可以应对所有的查找难题,内容...

批量查询快递总耗时?用Excel这个公式,自动计算揽收到签收天数

批量查询快递总耗时?用Excel这个公式,自动计算揽收到签收天数在电商运营、物流对账等工作中,经常需要统计快递“揽收到签收”的耗时——比如判断某快递公司是否符合“3天内送达”的服务承...

Excel函数公式教程(490个实例详解)

Excel函数公式教程(490个实例详解)管理层的财务人员为什么那么厉害?就是因为他们精通excel技能!财务人员在日常工作中,经常会用到Excel财务函数公式,比如财务报表分析、工资核算、库存管理等...

Excel(WPS表格)Tocol函数应用技巧案例解读,建议收藏备用!

工作中,经常需要从多个单元格区域中提取唯一值,如体育赛事报名信息中提取唯一的参赛者信息等,此时如果复制粘贴然后去重,效率就会很低。如果能合理利用Tocol函数,将会极大地提高工作效率。一、功能及语法结...

Excel中的SCAN函数公式,把计算过程理清,你就会了

Excel新版本里面,除了出现非常好用的xlookup,Filter公式之外,还更新一批自定义函数,可以像写代码一样写公式其中SCAN函数公式,也非常强大,它是一个循环函数,今天来了解这个函数公式的计...

Excel(WPS表格)中多列去重就用Tocol+Unique组合函数,简单高效

在数据的分析和处理中,“去重”一直是绕不开的话题,如果单列去重,可以使用Unique函数完成,如果多列去重,如下图:从数据信息中可以看到,每位参赛者参加了多项运动,如果想知道去重后的参赛者有多少人,该...

Excel(WPS表格)函数Groupby,聚合统计,快速提高效率!

在前期的内容中,我们讲了很多的统计函数,如Sum系列、Average系列、Count系列、Rank系列等等……但如果用一个函数实现类似数据透视表的功能,就必须用Groupby函数,按指定字段进行聚合汇...

Excel新版本,IFS函数公式,太强大了!

我们举一个工作实例,现在需要计算业务员的奖励数据,右边是公司的奖励标准:在新版本的函数公式出来之前,我们需要使用IF函数公式来解决1、IF函数公式IF函数公式由三个参数组成,IF(判断条件,对的时候返...

Excel不用函数公式数据透视表,1秒完成多列项目汇总统计

如何将这里的多组数据进行汇总统计?每组数据当中一列是不同菜品,另一列就是该菜品的销售数量。如何进行汇总统计得到所有的菜品销售数量的求和、技术、平均、最大、最小值等数据?不用函数公式和数据透视表,一秒就...