缓存 - Spring Boot 整合 Caffeine 不完全指北

这篇具有很好参考价值的文章主要介绍了缓存 - Spring Boot 整合 Caffeine 不完全指北。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

缓存 - Spring Boot 整合 Caffeine 不完全指北,【Redis-入门到精通】,缓存,spring boot,caffeine


Pre

缓存 - Caffeine 不完全指北


名词解释

  • @Cacheable:表示该方法支持缓存。当调用被注解的方法时,如果对应的键已经存在缓存,则不再执行方法体,而从缓存中直接返回。当方法返回null时,将不进行缓存操作。
  • @CachePut:表示执行该方法后,其值将作为最新结果更新到缓存中,每次都会执行该方法。
  • @CacheEvict:表示执行该方法后,将触发缓存清除操作。
  • @Caching:用于组合前三个注解,比如
    @Caching(cacheable = @Cacheable("CacheConstants.GET_USER"),
             evict = {@CacheEvict("CacheConstants.GET_DYNAMIC",allEntries = true)}
    public User find(Integer id) {
        return null;
    }
    
    

注解属性

缓存 - Spring Boot 整合 Caffeine 不完全指北,【Redis-入门到精通】,缓存,spring boot,caffeine

  • cacheNames/value:缓存组件的名字,即cacheManager中缓存的名称。
  • key:缓存数据时使用的key。默认使用方法参数值,也可以使用SpEL表达式进行编写。
  • keyGenerator:和key二选一使用。
  • cacheManager:指定使用的缓存管理器。
  • condition:在方法执行开始前检查,在符合condition的情况下,进行缓存
  • unless:在方法执行完成后检查,在符合unless的情况下,不进行缓存
  • sync:是否使用同步模式。若使用同步模式,在多个线程同时对一个key进行load时,其他线程将被阻塞。

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

缓存 - Spring Boot 整合 Caffeine 不完全指北,【Redis-入门到精通】,缓存,spring boot,caffeine

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

指导步骤

要在Spring Boot中整合Caffeine缓存,可以按照以下步骤进行操作:

步骤 1:添加依赖

pom.xml文件中添加Caffeine依赖项。确保选择与您的Spring Boot版本兼容的Caffeine版本。以下是一个示例依赖项:

<dependency>
    <groupId>com.github.ben-manes.caffeine</groupId>
    <artifactId>caffeine</artifactId>
    <version>2.9.0</version>
</dependency>

步骤 2:配置缓存

在Spring Boot的配置文件(例如application.propertiesapplication.yml)中添加Caffeine缓存的配置。以下是一个示例配置:

application.properties:

spring.cache.type=caffeine
spring.cache.cache-names=myCache
spring.cache.caffeine.spec=maximumSize=100,expireAfterAccess=600s

application.yml:

spring:
  cache:
    type: caffeine
    cache-names: myCache
    caffeine:
      spec: maximumSize=100,expireAfterAccess=600s

这将配置一个名为myCache的Caffeine缓存,最大容量为100,访问后在600秒内过期。

步骤 3:使用缓存

在需要使用缓存的地方,使用@Cacheable注解标记方法。例如,以下是一个使用缓存的示例:

import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

@Service
public class MyService {

    @Cacheable("myCache")
    public String getDataFromCache(String key) {
        // 如果缓存中存在数据,则直接返回
        // 如果缓存中不存在数据,则执行相应的业务逻辑,并将结果放入缓存
        return fetchDataFromDatabase(key);
    }

    private String fetchDataFromDatabase(String key) {
        // 执行获取数据的业务逻辑
        return "Data for key: " + key;
    }
}

在上面的示例中,getDataFromCache方法使用了@Cacheable("myCache")注解,表示该方法的结果将被缓存到名为myCache的缓存中。

现在,当调用getDataFromCache方法时,首先会检查缓存中是否存在与给定参数对应的数据。如果存在,将直接返回缓存的数据;如果不存在,则会执行方法体内的业务逻辑,并将结果放入缓存。

这就是在Spring Boot中整合Caffeine缓存的基本步骤。我们可以根据自己的需求进行进一步的配置和定制。


Code

缓存 - Spring Boot 整合 Caffeine 不完全指北,【Redis-入门到精通】,缓存,spring boot,caffeine

接下来我们使用另一种方式来实现


pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.13</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.artisan</groupId>
    <artifactId>caffeine-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>caffeine-demo</name>
    <description>caffeine-demo</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>


        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>


        <dependency>
            <groupId>com.github.ben-manes.caffeine</groupId>
            <artifactId>caffeine</artifactId>
            <!-- Java 8 users can continue to use version 2.x, which will be supported -->
            <version>2.9.3</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>


    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

Config

package com.artisan.caffeinedemo.spring.config;

import com.artisan.caffeinedemo.spring.enums.CacheEnum;
import com.github.benmanes.caffeine.cache.Caffeine;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.caffeine.CaffeineCache;
import org.springframework.cache.support.SimpleCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author 小工匠
 * @version 1.0
 * @mark: show me the code , change the world
 */
@Configuration
@EnableCaching
public class CacheConfig {
    /**
     * Caffeine配置说明:
     * initialCapacity=[integer]: 初始的缓存空间大小
     * maximumSize=[long]: 缓存的最大条数
     * maximumWeight=[long]: 缓存的最大权重
     * expireAfterAccess=[duration]: 最后一次写入或访问后经过固定时间过期
     * expireAfterWrite=[duration]: 最后一次写入后经过固定时间过期
     * refreshAfterWrite=[duration]: 创建缓存或者最近一次更新缓存后经过固定的时间间隔,刷新缓存
     * weakKeys: 打开key的弱引用
     * weakValues:打开value的弱引用
     * softValues:打开value的软引用
     * recordStats:开发统计功能
     * 注意:
     * expireAfterWrite和expireAfterAccess同事存在时,以expireAfterWrite为准。
     * maximumSize和maximumWeight不可以同时使用
     * weakValues和softValues不可以同时使用
     */
    @Bean
    public CacheManager cacheManager() {
        SimpleCacheManager cacheManager = new SimpleCacheManager();
        List<CaffeineCache> list = new ArrayList<>();
        //循环添加枚举类中自定义的缓存,可以自定义
        for (CacheEnum cacheEnum : CacheEnum.values()) {
            list.add(new CaffeineCache(cacheEnum.getName(),
                    Caffeine.newBuilder()
                            .initialCapacity(50)
                            .maximumSize(1000)
                            .expireAfterAccess(cacheEnum.getExpireTime(), TimeUnit.SECONDS)
                            .build()));
        }
        cacheManager.setCaches(list);
        return cacheManager;
    }
}

Service

package com.artisan.caffeinedemo.spring.service;

import com.artisan.caffeinedemo.spring.constants.CacheConstants;
import com.artisan.caffeinedemo.spring.domains.Artisan;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

/**
 * @author 小工匠
 * @version 1.0
 * @mark: show me the code , change the world
 */

@Service
@Slf4j
public class ArtisanService {

    /**
     * @Cacheable注解是 通过 Spring AOP机制进行的,因此类内的调用将无法触发缓存操作,必须由外部进行调用,之前也算是踩了一遍坑,特别提醒一下
     */

    /**
     * cacheNames/value:缓存组件的名字,即cacheManager中缓存的名称。
     * key:缓存数据时使用的key。默认使用方法参数值,也可以使用SpEL表达式进行编写。
     * keyGenerator:和key二选一使用。
     * cacheManager:指定使用的缓存管理器。
     * condition:在方法执行开始前检查,在符合condition的情况下,进行缓存
     * unless:在方法执行完成后检查,在符合unless的情况下,不进行缓存
     * sync:是否使用同步模式。若使用同步模式,在多个线程同时对一个key进行load时,其他线程将被阻塞。
     */
    @Cacheable(value = CacheConstants.GET_USER, key = "'user'+#userId", sync = true)
    public Artisan getUserByUserId(Integer userId) {
        log.info("----------------触发DB查询----------------------------");
        // 模拟从DB查询数据
        Artisan artisan = Artisan.builder().id(userId).name("artisan-" + userId).address("China-" +  userId).build();
        return artisan;
    }


    @CacheEvict(value = CacheConstants.GET_USER, key = "'user'+#userId")
    public Integer cacheEvictTest(Integer userId) {
        log.info("cacheEvictTest 清除 {} 对应的缓存", userId);
        return 1;
    }

    @CachePut(value = CacheConstants.GET_USER, key = "'user'+#userId")
    public Artisan cachePut(Integer userId) {
        log.info("cachePut execute -------------------");
        Artisan artisan = Artisan.builder().id(userId).name("artisan1").address("China").build();
        return artisan;
    }

}
    

缓存名枚举 & 常量

package com.artisan.caffeinedemo.spring.enums;

import com.artisan.caffeinedemo.spring.constants.CacheConstants;
import lombok.Getter;

/**
 * @author 小工匠
 * @version 1.0
 * @mark: show me the code , change the world
 */
@Getter
public enum CacheEnum {

    MY_CACHE_1("工匠1", CacheConstants.DEFAULT_EXPIRES),
    MY_CACHE_2("工匠2", CacheConstants.EXPIRES_5_MIN),
    MY_CACHE_3(CacheConstants.GET_USER, CacheConstants.EXPIRES_10_MIN);

    private String name;
    private Integer expireTime;

    CacheEnum(String name, Integer expireTime) {
        this.name = name;
        this.expireTime = expireTime;
    }


}
    
package com.artisan.caffeinedemo.spring.constants;

/**
 * @author 小工匠
 * @version 1.0
 * @mark: show me the code , change the world
 */
public class CacheConstants {
    /**
     * 默认过期时间(配置类中使用的时间单位是秒,所以这里如 3*60 为3分钟)
     */
    public static final int DEFAULT_EXPIRES = 3 * 60;
    public static final int EXPIRES_5_MIN = 5 * 60;
    public static final int EXPIRES_10_MIN = 10 * 60;

    public static final String GET_USER = "GET:USER";
    public static final String GET_DYNAMIC = "GET:DYNAMIC";

}

创建缓存常量类,把公共的常量提取一层,复用,这里也可以通过配置文件加载这些数据,例如@ConfigurationProperties和@Value

package com.artisan.caffeinedemo.spring.domains;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * @author 小工匠
 * @version 1.0
 * @mark: show me the code , change the world
 */
@Slf4j
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Data
public class Artisan {
    private Integer id;
    private String name;
    private String address;
}
    

测试入口

package com.artisan.caffeinedemo.spring.controller;

import com.artisan.caffeinedemo.spring.domains.Artisan;
import com.artisan.caffeinedemo.spring.service.ArtisanService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;

/**
 * @author 小工匠
 * @version 1.0
 * @mark: show me the code , change the world
 */
@Slf4j
@RestController
@RequestMapping("/testCache")
public class CacheController {


    @Resource
    private ArtisanService artisanService;

    @RequestMapping("/get/{id}")
    @ResponseBody
    public String getArtisanById(@PathVariable Integer id) {
        Artisan artisan = artisanService.getUserByUserId(id);
        log.info("--------->{}", artisan.toString());
        return artisan.toString();
    }


    @RequestMapping("/evit/{id}")
    @ResponseBody
    public String cacheEvit(@PathVariable Integer id) {
        artisanService.cacheEvictTest(id);

        return "cacheEvit";
    }


    @RequestMapping("/put/{id}")
    @ResponseBody
    public String cachePut(@PathVariable Integer id) {
        Artisan artisan = artisanService.cachePut(id);

        return artisan.toString();
    }
}
    

测试

根据以下的访问,可以得到如下结论

http://127.0.0.1:8080/testCache/get/1  ----->  查询DB ,加入缓存

http://127.0.0.1:8080/testCache/get/1 ------>  直接从缓存中读取  


http://127.0.0.1:8080/testCache/evit/1 ------> 清除缓存的id=1的数据   


http://127.0.0.1:8080/testCache/get/1  ----->  查询DB ,加入缓存



http://127.0.0.1:8080/testCache/put/1  ----->  操作DB ,加入缓存

http://127.0.0.1:8080/testCache/put/2  ----->  操作DB ,加入缓存


http://127.0.0.1:8080/testCache/get/2 ------>  直接从缓存中读取  

缓存 - Spring Boot 整合 Caffeine 不完全指北,【Redis-入门到精通】,缓存,spring boot,caffeine文章来源地址https://www.toymoban.com/news/detail-568461.html

到了这里,关于缓存 - Spring Boot 整合 Caffeine 不完全指北的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • spring boot整合cache使用Ehcache 进行数据缓存

    之前的文章 spring boot整合 cache 以redis服务 处理数据缓存 便捷开发 带着大家通过spring boot整合了 cache 缓存 那么 我们就来说说 其他服务的缓存 而spring boot默认的缓存方案就是 cache 用simple模式 spring boot的强大在于它的整合能力 它将其他缓存技术整合 统一了接口 简单说 所有的

    2024年02月19日
    浏览(41)
  • Spring Boot整合Redis

    Redis是一个开源(BSD许可)的、内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件,并提供多种语言的API。 Redis支持多种类型的数据结构,如 字符串(strings)、散列(hashes)、列表(lists)、集合(sets)、有序集合(sorted sets)与范围查询、bitmaps、 hyperlo

    2024年02月09日
    浏览(38)
  • 21 Spring Boot整合Redis

        目录 一、Redis简介 二、创建springboot整合redis工程 三、添加依赖 四、配置Yml 五、创建Redis配置类  六、创建Redis工具类,封装Redis的api 七、操作Redis  八、验证       简单来说 Redis 就是一个使用 C 语言开发的数据库,不过与传统数据库不同的是 Redis 的数据是存在内存中的

    2024年02月09日
    浏览(30)
  • spring boot 简单整合 Redis

    2024年02月12日
    浏览(45)
  • 【Redis系列】Spring Boot 集成 Redis 实现缓存功能

    💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学习,不断总结,共同进步,活到老学到老 导航 檀越剑指大厂系列:全面总

    2024年04月10日
    浏览(55)
  • LRU算法与Caffeine、Redis中的缓存淘汰策略

    在现代计算机系统中,缓存是提高系统性能的关键技术之一。为了避免频繁的IO操作,常见的做法是将数据存储在内存中的缓存中,以便快速访问。然而,由于内存资源有限,缓存的大小是有限的,因此需要一种策略来淘汰缓存中的数据,以便为新的数据腾出空间。本文将介

    2024年02月12日
    浏览(39)
  • Spring Boot 整合Redis实现消息队列

      本篇文章主要来讲Spring Boot 整合Redis实现消息队列,实现redis用作消息队列有多种方式,比如: 基于 List 的 rpush+lpop 或 lpush+rpop 基于 List 的 rpush+blpop 或 lpush+brpop (阻塞式获取消息) 基于 Sorted Set 的优先级队列 Redis Stream (Redis5.0版本开始) Pub/Sub 机制   不过这里讲的是

    2024年02月13日
    浏览(44)
  • Spring Framework 提供缓存管理器Caffeine

    Spring Framework 提供了一个名为 Caffeine 的缓存管理器。Caffeine 是一个基于 Java 的高性能缓存库,被广泛用于处理大规模缓存数据。 使用 Caffeine 缓存管理器,可以轻松地在 Spring 应用程序中添加缓存功能。它提供了以下主要特性: 快速响应:Caffeine 使用内存作为缓存存储,相较

    2024年02月15日
    浏览(37)
  • Spring Boot整合Redis实现订单超时处理

    🎉欢迎来到架构设计专栏~Spring Boot整合Redis实现订单超时处理 ☆* o(≧▽≦)o *☆嗨~我是IT·陈寒🍹 ✨博客主页:IT·陈寒的博客 🎈该系列文章专栏:架构设计 📜其他专栏:Java学习路线 Java面试技巧 Java实战项目 AIGC人工智能 数据结构学习 🍹文章作者技术和水平有限,如果文

    2024年02月03日
    浏览(44)
  • Spring Boot Security认证:Redis缓存用户信息

    🎉欢迎来到架构设计专栏~Spring Boot Security认证:Redis缓存用户信息 ☆* o(≧▽≦)o *☆嗨~我是IT·陈寒🍹 ✨博客主页:IT·陈寒的博客 🎈该系列文章专栏:架构设计 📜其他专栏:Java学习路线 Java面试技巧 Java实战项目 AIGC人工智能 数据结构学习 🍹文章作者技术和水平有限,如

    2024年02月04日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包