【本地缓存】caffeine缓存详解

目录

直接实例化的方式:快速使用

spring集成的方式:

1、配置文件中配置:

2、通过配置类配置

 3、核心参数详解

二者区别:

生命周期

参数配置灵活性

使用场景

缓存key的设计


        给大家介绍一下本地缓存的使用,因为二级缓存是开发中必须要掌握的,可以很大程度上提供数据获取的性能,本篇主要给大家介绍的是caffeine。

        什么样的数据适合存到缓存里?最简单的就一句话:读多写少的数据。数据不需要频繁更改的数据就很适合存到缓存中,因为它在缓存里读取得更快,不需要在想数据库发送网络请求。当然还有一个重要的因素就是数据的一致性问题,需强一致性的数据,如果非必要,就不用存到缓存当中。

        废话不多说,直接先教大家怎么使用,再细讲里面的配置。


直接实例化的方式:快速使用

1、引入依赖:

注意如果是jdk8的必须要引入2.x.x版本的caffeine,否则跑不了。

        <!-- 本地缓存 Caffeine jdk8用2.x版本-->
        <dependency>
            <groupId>com.github.ben-manes.caffeine</groupId>
            <artifactId>caffeine</artifactId>
            <version>2.9.3</version>
        </dependency>

2、在业务层(service层)全局变量里定义设置Caffeine,变量要用final修饰。这样每个service里的方法都能使用。

    //本地缓存配置
    private final Cache<String, String> LOCAL_CACHE =
            Caffeine.newBuilder().initialCapacity(1024) //初始容量
                    .maximumSize(10000L) //最大容量
                    // 缓存 5 分钟移除
                    .expireAfterWrite(5L, TimeUnit.MINUTES)
                    .build();

3、业务中如何使用?

    @Override
    public Page<resultVO> getVOPage(queryRequest queryRequest) {

       //...业务逻辑

         //一、构建缓存key,将请求实体转成json格式,然后经过MD5压缩作为key
        String condition = JSONUtil.toJsonStr(queryRequest);
        String hashKey = DigestUtils.md5DigestAsHex(condition.getBytes());
        String cacheKey = String.format("picture:getPictureListVO:%s", hashKey);

        //二、查本地缓存:
        Page<resultVO> cachePage;
        String cacheValue = LOCAL_CACHE.getIfPresent(cacheKey);
        if (cacheValue != null) {
            cachePage = JSONUtil.toBean(cacheValue, Page.class);
            return cachePage;
        }


        //三、本地缓存没有,去查询下一级缓存或者数据库查到数据后,将数据放到本地缓存
        String jsonStr = userDao.select() //模拟去别的地方查到了数据
        LOCAL_CACHE.put(cacheKey, jsonStr);


        //......其他业务逻辑


    }



spring集成的方式:

先引入依赖:

<!-- Spring Cache支持 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!-- Caffeine核心依赖 -->
<dependency>
    <groupId>com.github.ben-manes.caffeine</groupId>
    <artifactId>caffeine</artifactId>
</dependency>

1、配置文件中配置:

在配置文件中直接定义Caffeine的参数,适合简单场景。

application.properties示例:

# 指定缓存类型为Caffeine
spring.cache.type=caffeine

# 配置缓存名称和参数(多个缓存用逗号分隔)
spring.cache.cache-names=users,dynamics

# 配置Caffeine的参数(以逗号分隔)
spring.cache.caffeine.spec=maximumSize=500,expireAfterAccess=600s,softValues=true

application.yml示例:

spring:
  cache:
    type: caffeine
    caffeine:
      spec: maximumSize=500,expireAfterAccess=600s,softValues=true
    cache-names:
      - users
      - dynamics

2、通过配置类配置

通过@Configuration类灵活配置多个缓存实例,适合复杂场景。


@Configuration
@EnableCaching
public class CaffeineConfig {

    // 配置默认的缓存管理器
    @Bean
    public CacheManager cacheManager() {
        CaffeineCacheManager manager = new CaffeineCacheManager("users", "dynamics");
        manager.setCaffeine(caffeineConfig());
        return manager;
    }

    // 定义Caffeine的通用配置
    private Caffeine<Object, Object> caffeineConfig() {
        return Caffeine.newBuilder()
                // 最大缓存条目数
                .maximumSize(500)
                // 写入后过期时间(10分钟)
                .expireAfterWrite(10, TimeUnit.MINUTES)
                // 访问后刷新过期时间(需配合refreshAfterWrite)
                //.expireAfterAccess(5, TimeUnit.MINUTES)
                //.refreshAfterWrite(2, TimeUnit.MINUTES)
                // 使用软引用(内存不足时回收)
                .softValues(true)
                // 初始容量(根据预估调整)
                .initialCapacity(100);
    }
}


 3、核心参数详解

1.容量控制:

参数 说明 示例
maximumSize 最大缓存条目数,超过后触发淘汰策略。 .maximumSize(1000)
maximumWeight 按权重总和控制容量,需结合weigher定义权重计算逻辑。 .maximumWeight(1000)
weigher 定义每个条目的权重,例如:Weigher<String, Object> (k, v) -> v.length() .weigher((k, v) -> v.length())
initialCapacity 初始容量,避免频繁扩容。 .initialCapacity(100)

2. 过期策略

参数 说明 示例
expireAfterWrite 写入后过期时间(推荐)。 .expireAfterWrite(10, MINUTES)
expireAfterAccess 访问后过期时间(需配合refreshAfterWrite防止频繁访问不被淘汰)。 .expireAfterAccess(5, MINUTES)
refreshAfterWrite 定期刷新过期时间(需与expireAfterAccess配合使用)。 .refreshAfterWrite(2, MINUTES)

3. 内存管理

参数 说明 示例
softValues 使用软引用,内存不足时回收。 .softValues(true)
weakKeys/weakValues 使用弱引用,对象可能随时被GC回收(慎用)。 .weakKeys(true)
recordStats 开启统计功能,获取命中率、加载时间等指标。 .recordStats()

4. 完整使用示例

@Bean
public CaffeineCacheManager cacheManager() {
    CaffeineCacheManager manager = new CaffeineCacheManager("userCache");
    manager.setCaffeine(Caffeine.newBuilder()
        .maximumWeight(1000) // 总权重不超过1000
        .weigher((k, v) -> ((User)v).getSize()) // 用户对象的size属性为权重
        .expireAfterWrite(15, TimeUnit.MINUTES)
        .recordStats()
    );
    return manager;
}

@Service
public class UserService {
    @Cacheable(value = "userCache", key = "#userId")
    public User getUserById(String userId) {
        // 数据库查询逻辑
        return userRepository.findById(userId);
    }
}



二者区别:

生命周期

(1)实例化方式:

  • 作用域:缓存实例是业务类的成员变量,生命周期与业务类绑定。
  • 线程安全:Caffeine本身是线程安全的,但需注意业务逻辑中对缓存的并发访问。

(2)Spring集成方式:

  • 作用域:通过CacheManager管理的缓存实例是Spring的Bean,生命周期由Spring容器控制。
  • 线程安全:同样线程安全,但Spring会自动处理缓存的初始化和销毁。

  


参数配置灵活性

(1)实例化方式

  • 硬编码参数:修改配置需重新编译代码,不适合生产环境动态调整。
  • 无法利用Spring的占位符:如@Value("${cache.max-size}")无法直接使用。

(2)Spring集成方式

  • 支持外部化配置:可通过application.properties或@Value动态注入参数:

spring.cache.caffeine.spec=maximumSize=10000,expireAfterWrite=5m


使用场景

场景 直接实例化方式 Spring集成方式
简单缓存需求 适合(如单个缓存实例,无需注解) 适用,但可能“过度设计”
复杂缓存管理 需重复代码,难以维护 推荐,集中配置、多缓存实例支持
需要监控与统计 需手动实现 自动集成,便于监控
需要动态配置 不支持 支持通过application.properties配置
与Spring生态集成 无法利用Spring注解 完全兼容Spring的缓存抽象层



缓存key的设计

1、唯一性

  • 每个key必须唯一,避免不同业务场景或数据的key冲突。
  • 示例:user:1001:profile(用户ID+业务类型)。

2、可读性

  • key的命名需清晰表达其含义,方便维护和排查问题。
  • 示例:product:category:electronics(业务模块+数据类型+具体分类)。

3、简洁性

  • key不宜过长,减少内存占用和网络传输开销。
  • 示例:用缩写(如u:1001代替user:1001)或哈希值(如md5(业务参数))缩短长度。

4、结构化

  • 采用分层结构,通过分隔符(如:)将不同层级的信息组合起来。
  • 示例:module:entity:type:id:version。

猜你喜欢

转载自blog.csdn.net/m0_74289770/article/details/146897255
今日推荐