沉梦听雨的编程指南 沉梦听雨的编程指南
首页
  • 基础篇
  • 集合篇
  • 并发篇
  • JVM
  • 新特性
  • 计算机网络
  • 操作系统
  • 数据结构与算法
  • 基础篇
  • MySql
  • Redis
  • 达梦数据库
  • Spring
  • SpringBoot
  • Mybatis
  • Shiro
  • 设计须知
  • UML画图
  • 权限校验
  • 设计模式
  • API网关
  • RPC
  • 消息队列
  • SpringCloud
  • 分布式事务
  • 云存储
  • 搜索引擎
  • 多媒体框架
  • 虚拟机
  • 开发工具篇
  • 工具库篇
  • 开发技巧篇
  • 工具类系列
  • 随笔
  • 前端环境搭建
  • HTML与CSS
  • JS学习
  • Axios入门
  • Vue Router入门
  • Pinia入门
  • Vue3入门
  • Vue3进阶
  • 黑马Vue3
  • 脚手架搭建
  • 瑞吉外卖
  • 黑马点评
  • vue-blog
  • 沉梦接口开放平台
  • 用户中心
  • 聚合搜索平台
  • 仿12306项目
  • 壁纸小程序项目
  • RuoYi-Vue
  • 博客搭建
  • 网站收藏箱
  • 断墨寻径摘录
  • 费曼学习法
Github (opens new window)

沉梦听雨

时间是最好的浸渍剂,而沉淀是最好的提纯器🚀
首页
  • 基础篇
  • 集合篇
  • 并发篇
  • JVM
  • 新特性
  • 计算机网络
  • 操作系统
  • 数据结构与算法
  • 基础篇
  • MySql
  • Redis
  • 达梦数据库
  • Spring
  • SpringBoot
  • Mybatis
  • Shiro
  • 设计须知
  • UML画图
  • 权限校验
  • 设计模式
  • API网关
  • RPC
  • 消息队列
  • SpringCloud
  • 分布式事务
  • 云存储
  • 搜索引擎
  • 多媒体框架
  • 虚拟机
  • 开发工具篇
  • 工具库篇
  • 开发技巧篇
  • 工具类系列
  • 随笔
  • 前端环境搭建
  • HTML与CSS
  • JS学习
  • Axios入门
  • Vue Router入门
  • Pinia入门
  • Vue3入门
  • Vue3进阶
  • 黑马Vue3
  • 脚手架搭建
  • 瑞吉外卖
  • 黑马点评
  • vue-blog
  • 沉梦接口开放平台
  • 用户中心
  • 聚合搜索平台
  • 仿12306项目
  • 壁纸小程序项目
  • RuoYi-Vue
  • 博客搭建
  • 网站收藏箱
  • 断墨寻径摘录
  • 费曼学习法
Github (opens new window)
  • Spring

    • Spring基础小结
    • 聊聊Spring IoC 和 AOP
    • AOP实战
    • 元注解知识小结
    • SpringCache小记
      • 基础知识
        • 常用注解
        • 常用注解属性
        • 清理全部缓存
        • SpEL表达式
      • Caffeine 缓存设置及代码实践
        • 1. 引入依赖
        • 2. 编写配置类
        • 3. 编写字典业务类
        • 注解解析
        • 4. 编写抽象字典转换器
        • 5. 继承使用
      • 注意事项
      • 学习参考
    • 异步注解相关
    • ThreadPoolTaskExecutor与ThreadPoolExecutor的区别
    • 讲讲Spring事务
  • SpringBoot

  • Mybatis

  • Shiro

  • 常用框架
  • Spring
沉梦听雨
2023-10-27
1.8k
7.3m
目录
基础知识
常用注解
常用注解属性
清理全部缓存
SpEL表达式
Caffeine 缓存设置及代码实践
1. 引入依赖
2. 编写配置类
3. 编写字典业务类
注解解析
4. 编写抽象字典转换器
5. 继承使用
注意事项
学习参考

SpringCache小记

# Spring Cache 小记

官方文档:https://springdoc.cn/spring-cache-tutorial/ (opens new window)

# 基础知识

# 常用注解

@EnableCaching:开启缓存功能,一般放在启动类上。

  1. @Cacheable:表示该方法支持缓存。当调用被注解的方法时,如果对应的键已经存在缓存,则不再执行方法体,而从缓存中直接返回。当方法返回 null 时,将不进行缓存操作。(一般用于查询方法上)

  2. @CachePut:表示执行该方法后,其值将作为最新结果更新到缓存中,每次都会执行该方法。(一般用于新增方法上)

  3. @CacheEvict:表示执行该方法后,将触发缓存清除操作。(一般用于更新或删除方法上)

  4. @Caching:用于组合前三个注解,例如:

    @Caching(cacheable = @Cacheable("CacheConstant.GET_USER"),
             evict = {@CacheEvict("CacheConstant.GET_DYNAMIC", allEntries = true)}
    public User find(Integer id) {
        return null;
    }
    // 使用参数 allEntries 与要清空的缓存结合使用;这将清除缓存 CacheConstant.GET_DYNAMIC 中的所有条目。
    // cacheable -- @Cacheable
    // put       -- @CachePut
    // evict     -- @CacheEvict
    
    1
    2
    3
    4
    5
    6
    7
    8
    9

# 常用注解属性

  1. value/cacheNames:缓存名称(必填),指定缓存的命名空间;

  2. key:用于设置在命名空间中的缓存 key 值,默认使用方法参数值,也可以使用 SpEL 表达式定义;

  3. keyGenerator:缓存 Key 的生成策略,它和 key 属性互斥使用(只能二选一)

  4. unless:条件符合则不缓存;

    使用 unless 时可以在调用的方法获取到结果之后再进行判断(如 #result == null,表示如果结果为 nu11 时不缓存)

  5. condition:条件符合则缓存;

  6. cacheManager:指定使用的缓存管理器;

  7. cacheResolver:作用和 cacheManager 属性一样(只能二选一)

  8. sync:是否使用同步模式。若使用同步模式,在多个线程同时对一个 key 进行 load 时,其他线程将被阻塞。默认值是 false。

缓存同步模式:

sync 开启或关闭,在 Cache 和 LoadingCache 中的表现是不一致的:

  • Cache 中,sync 表示是否需要所有线程同步等待
  • LoadingCache 中,sync 表示在读取 不存在/已驱逐 的 key 时,是否执行被注解方法

# 清理全部缓存

通过 allEntries、beforeInvocation 属性可以来清除全部缓存数据,

  1. 不过 allEntries 是方法调用后清理,
  2. beforeInvocation 是方法调用前清理。

# SpEL表达式

SpEL 表达式的语法

img

Spring Cache 可用的变量

img

# Caffeine 缓存设置及代码实践

# 1. 引入依赖

				<!-- 引入Caffeine缓存依赖 -->
			  <dependency>
            <groupId>com.github.ben-manes.caffeine</groupId>
            <artifactId>caffeine</artifactId>
        </dependency>
1
2
3
4
5

注释:选择使用 Caffeine 作为缓存依赖,是因为它是一款性能卓越的本地缓存库,具有快速、高效和可配置的特点。

# 2. 编写配置类

@Configuration
@EnableCaching
public class CacheConfig {

    /**
     * 配置Caffeine缓存管理器
     */
    @Bean
    public CacheManager cacheManager() {
        CaffeineCacheManager cacheManager = new CaffeineCacheManager();
        cacheManager.setCaffeine(Caffeine.newBuilder()
            // 设置缓存过期时间为30分钟
            .expireAfterWrite(30, TimeUnit.MINUTES)
            // 设置最大缓存条目数
            .maximumSize(1000)
            .recordStats()
        );
        return cacheManager;
    }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 3. 编写字典业务类

@Service
public class DictionaryService {

    @Resource
    private DocumentExpiredMapper documentExpiredMapper;

    /**
     * 通过@Cacheable注解将字典数据存入缓存
     * @param dictionaryType 字典类型
     * @return 字典数据的HashMap
     */
    @Cacheable(value = "dictionaryCache", key = "#dictionaryType")
    public HashMap<String, String> getDict(String dictionaryType) {
        List<DictDTO> dictList = documentExpiredMapper.getDict(dictionaryType);
        HashMap<String, String> dictMap = new HashMap<>(16);
        for (DictDTO dictDTO : dictList) {
            dictMap.put(dictDTO.getDictValue(), dictDTO.getDictName());
        }
        return dictMap;
    }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 注解解析

@Cacheable 是 Spring 框架中用于声明一个方法要被缓存处理的注解。在上面这段代码中,它的用法是为 getDict 方法添加了缓存的支持。

具体到这个注解的属性解释如下:

  • value:指定缓存的名称,可以理解为给缓存起一个名字,这样你可以在不同地方使用相同名字的缓存。在你的例子中,缓存的名称是 "dictionaryCache"。
  • key:指定缓存的键。缓存的键决定了缓存的唯一性。在你的例子中,"#dictionaryType" 表示缓存的键是方法的参数 dictionaryType 的值。这样就能够通过不同的 dictionaryType 值来区分不同的缓存数据。

综合起来,@Cacheable(value = "dictionaryCache", key = "#dictionaryType") 的含义是:

  • 这个方法的执行结果将会被缓存起来。
  • 缓存的名称是 "dictionaryCache"。
  • 缓存的键是方法的参数 dictionaryType 的值。

流程解析

当这个方法被调用时,Spring 会先检查缓存中是否已经存在了相同键的缓存数据,如果存在就直接返回缓存的结果,而不执行方法体;如果不存在,就执行方法体,并将方法的结果缓存起来,以备后续相同参数的方法调用直接使用缓存数据,提高执行效率。这样,对于相同的 dictionaryType 参数,方法的执行结果只需要计算一次,之后就可以直接从缓存中获取,避免了重复计算。

# 4. 编写抽象字典转换器

public abstract class AbstractDictConverter implements Converter<String> {

	/**
	 * 获取字典类型
	 * 使用protected修饰符可以将方法或变量限制在同一包中的类和子类中访问。
	 * @return
	 */
	protected abstract String getDictType();

	@Override
	public Class<?> supportJavaTypeKey() {
		return String.class;
	}

	@Override
	public CellDataTypeEnum supportExcelTypeKey() {
		return CellDataTypeEnum.STRING;
	}

	@Override
	public String convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
		return cellData.getStringValue();
	}

	@Override
	public WriteCellData<?> convertToExcelData(WriteConverterContext<String> context) {
		DictionaryService bean = SpringUtil.getBean(DictionaryService.class);
		HashMap<String, String> dictMap = bean.getDict(getDictType());
		String convertedValue = dictMap.get(context.getValue());
		if (convertedValue != null) {
			return new WriteCellData<>(convertedValue);
		} else {
			return new WriteCellData<>(context.getValue());
		}
	}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

注意事项:

  1. 因为这个转换器是一个 抽象类,而且通常是 手动 new 出来的,而不是由 Spring 容器管理的,所以无法自动注入 @Autowired 依赖。
  2. 因此,需要使用 SpringUtil.getBean() 手动获取 DictionaryService。

# 5. 继承使用

第一个转换器:

public class AlertTypeConvert extends AbstractDictConverter {

	@Override
	protected String getDictType() {
		return ALERT_TYPE;
	}

}
1
2
3
4
5
6
7
8

第二个转换器:

public class DocumentDictConverter extends AbstractDictConverter {

	@Override
	protected String getDictType() {
		return CERTIFICATE;
	}

}
1
2
3
4
5
6
7
8

# 注意事项

💡 注意:在线上环境可能会遇到问题,比如测试环境正常运行,但在生产环境中无法进行字典转换,可能导致转换失败。为了解决这个问题,我们可以考虑使用自定义的静态变量 HashMap 来实现该功能,确保字典数据在各个环境中都能正确加载。

其他实现方式阅读:

文件导出之自定义字典映射转换器 (opens new window)

# 学习参考

  • Java 本地缓存之王Caffeine - 掘金 (juejin.cn) (opens new window)

  • 程序员必备的Spring集成缓存知识:深入浅出的教程分享 - 掘金 (juejin.cn) (opens new window)

  • SpringBoot缓存注解@Cacheable之自定义key策略及缓存失效时间指定 - 掘金 (juejin.cn) (opens new window)

  • 深入浅出@Cacheable-CSDN博客 (opens new window)

  • Spring之缓存注解@Cacheable-CSDN博客 (opens new window)

  • https://juejin.cn/post/6844904094545477640?searchId=202407011552082E85C3497B3684283B5D (opens new window)

上次更新: 2025/3/24 17:36:04
元注解知识小结
异步注解相关

← 元注解知识小结 异步注解相关→

Theme by Vdoing | Copyright © 2023-2025 沉梦听雨 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式