Mars‘s docMars‘s doc
🏠主页
  • 🍻Activiti

    • 01-核心API
    • 02-监听
    • 03-数据库表介绍
    • 04-常见问题
  • 📊JasperReport

    • 01-JaspersoftStudio工具使用
    • 02-JasperReport集成
    • 03-JasperReport常见问题
  • 🎬JavaScript

    • 01-Node
    • 02-VuePress
    • 03-Vue组件高度宽度
    • 04-显示器和屏幕高度
    • 05-页面地址
    • 06-归纳总结
  • 🍵Java

    • 01-Java8特性
    • 02-多线程
    • 03-Jar包
    • 04-Util
    • 05-validation注解
    • 06-反编译
    • 07-try-with-resource
    • 08-ThreadLocal内存泄漏
    • 09-Jvm
    • 10-Excel
    • 11-Lombook
    • 12-条件注解
    • 13-WebMvcConfigurationSupport
    • 14-WebMvcConfigurer
    • 15-分布式锁
    • 16-Caffeine
    • 17-DynamicDatasource
    • 18-MybatisPlus
    • 19-Swagger
    • 20-BeanPostProcessor
    • 21-Bean初始化
    • 22-ConfigurableApplicationContext
    • 23-常用注解
    • 24-ApplicationListener
    • 25-JavaDoc
    • 26-Spring-Cache
    • 27-StopWatch耗时统计
    • 28-Word
    • 29-Druid
    • 30-OpenFeign
    • 31-反射相关
    • 32-Fastjson
    • 33-Yaml
  • 💻Linux

    • 01-Linux常用命令
    • 02-Linux脚本汇总
    • 03-Yum源
    • 04-Debian
    • 05-Ubuntu
  • 🐋Docker

    • 01-Docker常用命令
    • 02-Dockerfile
    • 03-Swarm
    • 04-Stack
    • 05-Docker常见问题
    • 06-DockerCompose
    • 07-Docker应用用汇总
    • 08-Kasm
    • 09-Rustdesk
  • 🌐Nginx

    • 01-Nginx
  • 📈数据库

    • 01-Mysql
    • 02-Clickhouse
    • 03-Doris
    • 04-DRDS
  • 📉Kettle

    • 01-入门
    • 02-js脚本
    • 03-优化
    • 04-连接组件
    • 05-参数
    • 06-工具
    • 07-日志
    • 08-流程组件
    • 09-输入组件
    • 10-输出组件
    • 11-转换组件
    • 12-驱动
  • 🎨Git

    • 01-Git使用
  • 📝Maven

    • 01-Maven使用
    • 02-Maven配置
  • 🎯Jenkins

    • 01-Jenkins部署
    • 02-Jenkisn常见问题
  • 01-设计模式之禅
  • 02-领域驱动设计
  • 03-JavaScript高级程序设计
  • 🍓树莓派

    • 01-RaspBerry
  • 📘Markdown

    • 01-Markdown语法
    • 02-Markdown表情
    • 03-Markdown代码块语言对照
  • 📇其他

    • 01-HTML XML 转义
    • 02-GitHub
    • 03-Idea
    • 04-Nmon
    • 05-Windows
    • 06-WinSw
GitHub
🏠主页
  • 🍻Activiti

    • 01-核心API
    • 02-监听
    • 03-数据库表介绍
    • 04-常见问题
  • 📊JasperReport

    • 01-JaspersoftStudio工具使用
    • 02-JasperReport集成
    • 03-JasperReport常见问题
  • 🎬JavaScript

    • 01-Node
    • 02-VuePress
    • 03-Vue组件高度宽度
    • 04-显示器和屏幕高度
    • 05-页面地址
    • 06-归纳总结
  • 🍵Java

    • 01-Java8特性
    • 02-多线程
    • 03-Jar包
    • 04-Util
    • 05-validation注解
    • 06-反编译
    • 07-try-with-resource
    • 08-ThreadLocal内存泄漏
    • 09-Jvm
    • 10-Excel
    • 11-Lombook
    • 12-条件注解
    • 13-WebMvcConfigurationSupport
    • 14-WebMvcConfigurer
    • 15-分布式锁
    • 16-Caffeine
    • 17-DynamicDatasource
    • 18-MybatisPlus
    • 19-Swagger
    • 20-BeanPostProcessor
    • 21-Bean初始化
    • 22-ConfigurableApplicationContext
    • 23-常用注解
    • 24-ApplicationListener
    • 25-JavaDoc
    • 26-Spring-Cache
    • 27-StopWatch耗时统计
    • 28-Word
    • 29-Druid
    • 30-OpenFeign
    • 31-反射相关
    • 32-Fastjson
    • 33-Yaml
  • 💻Linux

    • 01-Linux常用命令
    • 02-Linux脚本汇总
    • 03-Yum源
    • 04-Debian
    • 05-Ubuntu
  • 🐋Docker

    • 01-Docker常用命令
    • 02-Dockerfile
    • 03-Swarm
    • 04-Stack
    • 05-Docker常见问题
    • 06-DockerCompose
    • 07-Docker应用用汇总
    • 08-Kasm
    • 09-Rustdesk
  • 🌐Nginx

    • 01-Nginx
  • 📈数据库

    • 01-Mysql
    • 02-Clickhouse
    • 03-Doris
    • 04-DRDS
  • 📉Kettle

    • 01-入门
    • 02-js脚本
    • 03-优化
    • 04-连接组件
    • 05-参数
    • 06-工具
    • 07-日志
    • 08-流程组件
    • 09-输入组件
    • 10-输出组件
    • 11-转换组件
    • 12-驱动
  • 🎨Git

    • 01-Git使用
  • 📝Maven

    • 01-Maven使用
    • 02-Maven配置
  • 🎯Jenkins

    • 01-Jenkins部署
    • 02-Jenkisn常见问题
  • 01-设计模式之禅
  • 02-领域驱动设计
  • 03-JavaScript高级程序设计
  • 🍓树莓派

    • 01-RaspBerry
  • 📘Markdown

    • 01-Markdown语法
    • 02-Markdown表情
    • 03-Markdown代码块语言对照
  • 📇其他

    • 01-HTML XML 转义
    • 02-GitHub
    • 03-Idea
    • 04-Nmon
    • 05-Windows
    • 06-WinSw
GitHub
  • 🏫技术相关

    • 🍻Activiti

      • 01-核心API
      • 02-监听
      • 03-数据库表介绍
      • 04-常见问题
    • 📊JasperReport

      • 01-JaspersoftStudio工具使用
      • 02-JasperReport集成
      • 03-JasperReport常见问题
    • 🎬JavaScript

      • 01-Node
      • 02-VuePress
      • 03-Vue组件高度宽度
      • 04-显示器和屏幕高度
      • 05-页面地址
      • 06-归纳总结
    • 🍵Java

      • 01-Java8特性
      • 02-多线程
      • 03-Jar包
      • 04-Util
      • 05-validation注解
      • 06-反编译
      • 07-try-with-resource
      • 08-ThreadLocal内存泄漏
      • 09-Jvm
      • 10-Excel
      • 11-Lombook
      • 12-条件注解
      • 13-WebMvcConfigurationSupport
      • 14-WebMvcConfigurer
      • 15-分布式锁
      • 16-Caffeine
      • 17-DynamicDatasource
      • 18-MybatisPlus
      • 19-Swagger
      • 20-BeanPostProcessor
      • 21-Bean初始化
      • 22-ConfigurableApplicationContext
      • 23-常用注解
      • 24-ApplicationListener
      • 25-JavaDoc
      • 26-Spring-Cache
      • 27-StopWatch耗时统计
      • 28-Word
      • 29-Druid
      • 30-OpenFeign
      • 31-反射相关
      • 32-Fastjson
      • 33-Yaml
  • 🏢服务器

    • 💻Linux

      • 01-Linux常用命令
      • 02-Linux脚本汇总
      • 03-Yum源
      • 04-Debian
      • 05-Ubuntu
    • 🐋Docker

      • 01-Docker常用命令
      • 02-Dockerfile
      • 03-Swarm
      • 04-Stack
      • 05-Docker常见问题
      • 06-DockerCompose
      • 07-Docker应用用汇总
      • 08-Kasm
      • 09-Rustdesk
    • 🌐Nginx

      • 01-Nginx
  • 🏩数据相关

    • 📈数据库

      • 01-Mysql
      • 02-Clickhouse
      • 03-Doris
      • 04-DRDS
    • 📉Kettle

      • 01-入门
      • 02-js脚本
      • 03-优化
      • 04-连接组件
      • 05-参数
      • 06-工具
      • 07-日志
      • 08-流程组件
      • 09-输入组件
      • 10-输出组件
      • 11-转换组件
      • 12-驱动
  • 🏬管理工具

    • 🎨Git

      • 01-Git使用
    • 📝Maven

      • 01-Maven使用
      • 02-Maven配置
    • 🎯Jenkins

      • 01-Jenkins部署
      • 02-Jenkisn常见问题
  • 🏯书籍笔记

    • 01-设计模式之禅
    • 02-领域驱动设计
    • 03-JavaScript高级程序设计
  • 🏦其他

    • 🍓树莓派

      • 01-RaspBerry
    • 📘Markdown

      • 01-Markdown语法
      • 02-Markdown表情
      • 03-Markdown代码块语言对照
    • 📇其他

      • 01-HTML XML 转义
      • 02-GitHub
      • 03-Idea
      • 04-Nmon
      • 05-Windows
      • 06-WinSw

Caffeine本地缓存

缓存在日常开发中启动至关重要的作用,由于是存储在内存中,数据的读取速度是非常快的,能大量减少对数据库的访问,减少数据库的压力。相较于Redis,本地缓存无法解决分布式缓存同步问题,但是可以节约网络开销,从而降低时耗。

目录

  • 如何实现
  • 如何使用
  • 附录
    • Caffeine 组件
    • Java中四种引用类型

如何实现

  1. pom.xml 依赖

version 版本跟随 spring-boot-starter-parent 父级 spring-boot-dependencies 管理的版本。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
     <groupId>com.github.ben-manes.caffeine</groupId>
     <artifactId>caffeine</artifactId>
</dependency>
  1. configuration 配置
@EnableCaching
@Configuration
public class CaffeineConfig {

    /**
     * 方式一 : 使用 SpringCache 注解方法实现缓存
     *
     * @return
     */
    @Bean("caffeineCacheManager")
    public CacheManager cacheManager() {
        CaffeineCacheManager cacheManager = new CaffeineCacheManager();
        cacheManager.setCaffeine(Caffeine.newBuilder()
                                         // 设置最后一次写入或访问后经过固定时间过期
                                         .expireAfterAccess(60, TimeUnit.MINUTES)
                                         // 初始的缓存空间大小
                                         .initialCapacity(100)
                                         // 缓存的最大条数
                                         .maximumSize(1000));
        return cacheManager;
    }

    /**
     * 方式二 : 使用 Caffeine 方法实现缓存
     *
     * @return
     */
    @Bean("caffeineCache")
    public Cache<String, Object> caffeineCache() {
        return Caffeine.newBuilder()
                       // 设置最后一次写入或访问后经过固定时间过期
                       .expireAfterWrite(60, TimeUnit.SECONDS)
                       // 初始的缓存空间大小
                       .initialCapacity(100)
                       // 缓存的最大条数
                       .maximumSize(1000)
                       .build();
    }
    
}
  1. Caffeine 参数

    • initialCapacity=[integer]: 相当于配置 Caffeine.initialCapacity 初始的缓存空间大小
    • maximumSize=[long]: 相当于配置 Caffeine.maximumSize 缓存的最大条数
    • maximumWeight=[long]: 相当于配置 Caffeine.maximumWeight 缓存的最大权重
    • expireAfterAccess=[持续时间]: 相当于配置 Caffeine.expireAfterAccess 最后一次写入或访问后经过固定时间过期
    • expireAfterWrite=[持续时间]: 相当于配置 Caffeine.expireAfterWrite 最后一次写入后经过固定时间过期
    • refreshAfterWrite=[持续时间]: 相当于配置 Caffeine.refreshAfterWrite 创建缓存或者最近一次更新缓存后经过固定的时间间隔,刷新缓存
    • weakKeys: 相当于配置 Caffeine.weakKeys 打开key的弱引用
    • weakValues: 相当于配置 Caffeine.weakValues 打开value的弱引用
    • softValues: 相当于配置 Caffeine.softValues 打开value的软引用
    • recordStats: 相当于配置 Caffeine.recordStats 开发统计功能

    注意:

    • expireAfterWrite和expireAfterAccess同时存在时,以expireAfterWrite为准。
    • maximumSize和maximumWeight不可以同时使用
    • weakValues和softValues不可以同时使用

    使用时,请根据项目自身情况和使用场景,决定是否开启软/弱引用。

如何使用

使用原生springBoot+mybatisplus+h2环境模拟

  1. User4AutoCacheController SpringCache 注解自动装配
@RestController
@RequestMapping("/web/autoCache")
public class User4AutoCacheController {
    @Resource
    UserService userService;
    @Resource(name="caffeineCacheManager")
    CacheManager cacheManager;

    @GetMapping("/add")
    User addUser(User user) {
        return userService.addUserAutoCache(user);
    }

    @GetMapping("/update")
    User updateUser(User user) {
        return userService.updateUserAutoCache(user);
    }

    @GetMapping("/getUser")
    User getUser(long id) {
        return userService.getUserAutoCache(id);
    }

    @GetMapping("/delUser")
    Integer delUser(long id) {
        return userService.delUserAutoCache(id);
    }

    @GetMapping("/getUsers")
    List<User> getUsers(User user) {
        return userService.getUsersAutoCache(user);
    }

    @GetMapping("/cacheInfos")
    User getCacheInfos(String key){
        key = "cache:auto:user:"+key;
        Cache cache = cacheManager.getCache("caffeineCacheManager") ;
        assert cache != null;
        if(cache.get(key)!=null){
            return (User) Objects.requireNonNull(cache.get(key)).get();
        }else{
            return null;
        }
    }
}
  1. User4HandCacheController Caffeine 方法手动加载
@RestController
@RequestMapping("/web/handCache")
public class User4HandCacheController {
    @Resource
    UserService userService;

    @GetMapping("/add")
    User addUser(User user) {
        return userService.addUser(user);
    }

    @GetMapping("/update")
    User updateUser(User user) {
        return userService.updateUser(user);
    }

    @GetMapping("/getUser")
    User getUser(long id) {
        return userService.getUser(id);
    }

    @GetMapping("/delUser")
    Integer delUser(long id) {
        return userService.delUser(id);
    }

    @GetMapping("/getUsers")
    List<User> getUsers(User user) {
        return userService.getUsers(user);
    }
}
  1. UserService UserServiceImpl
public interface UserService extends IService<User> {

    User addUserAutoCache(User user);

    User updateUserAutoCache(User user);

    User getUserAutoCache(long id);

    Integer delUserAutoCache(long id);

    List<User> getUsersAutoCache(User user);

    User addUser(User user);

    User updateUser(User user);

    User getUser(long id);

    Integer delUser(long id);

    List<User> getUsers(User user);
}
@Service
@CacheConfig(cacheNames = "caffeineCacheManager")
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Resource(name = "caffeineCache")
    Cache<String, Object> caffeineCache;

    @Override
    @CachePut(key = "'cache:auto:user:'+#user.id", condition = "#user.id != null || #result != null ")
    public User addUserAutoCache(User user) {
        this.getBaseMapper().insert(user);
        return user;
    }

    @Override
    @CachePut(key = "'cache:auto:user:'+#user.id", condition = "#user.id != null || #result !=null ")
    public User updateUserAutoCache(User user) {
        this.getBaseMapper().updateById(user);
        return user;
    }

    @Override
    @Cacheable(key = "'cache:auto:user:'+#id", condition = "#id != null", unless = "#result== null")
    public User getUserAutoCache(long id) {
        return this.baseMapper.selectById(id);
    }

    @Override
    @CacheEvict(key = "'cache:auto:user:'+#id", condition = "#id != null && #result == 1 ")
    public Integer delUserAutoCache(long id) {
        return this.baseMapper.deleteById(id);
    }

    @Override
    @Cacheable(key = "'cache:auto:users:'+#user.id", condition = "#user.id != null", unless = "#result== null || #result.size() == 0 ")
    public List<User> getUsersAutoCache(User user) {
        return this.getBaseMapper().selectList(new QueryWrapper<>(user));
    }

    @Override
    public User addUser(User user) {
        if (this.getBaseMapper().insert(user) > 0) {
            caffeineCache.put("cache:hand:user:" + user.getId(), user);
        }
        return user;
    }

    @Override
    public User updateUser(User user) {
        if (this.getBaseMapper().updateById(user) > 0) {
            caffeineCache.put("cache:hand:user:" + user.getId(), user);
        }
        return user;
    }

    @Override
    public User getUser(long id) {
        User user = (User) caffeineCache.getIfPresent("cache:hand:user:" + id);
        if (user != null) {
            return user;
        }
        user = this.baseMapper.selectById(id);
        if (user != null) {
            caffeineCache.put("cache:hand:user:" + id, user);
        }
        return user;
    }

    @Override
    public Integer delUser(long id) {
        if (this.baseMapper.deleteById(id) == 1) {
            User user = (User) caffeineCache.getIfPresent("cache:hand:user:" + id);
            if (user != null) {
                caffeineCache.invalidate("cache:hand:user:" + id);
            }
            return 1;
        }
        return 0;
    }

    @Override
    public List<User> getUsers(User user) {
        List<User> users = (List<User>) caffeineCache.getIfPresent("cache:hand:users:" + user.getId());
        if (users != null && users.size() > 1) {
            return users;
        }
        users = this.getBaseMapper().selectList(new QueryWrapper<>(user));
        if (users != null && users.size() > 1) {
            caffeineCache.put("cache:hand:users:" + user.getId(), user);
        }
        return users;
    }
}
  1. UserMapper
public interface UserMapper extends BaseMapper<User> {

}
  1. User
@Data
@ToString
public class User {
     private Long id;
     private String name;
     private Integer age;
     private String email;
}
  1. data-h2.sql schema-h2.sql
# data-h2.sql
DELETE FROM user;

INSERT INTO user (id, name, age, email) VALUES
(1, 'neo', 18, 'smile1@ityouknow.com'),
(2, 'keep', 36, 'smile@ityouknow.com'),
(3, 'pure', 28, 'smile@ityouknow.com'),
(4, 'smile', 21, 'smile@ityouknow.com'),
(5, 'it', 24, 'smile@ityouknow.com');
#schema-h2.sql
DROP TABLE IF EXISTS user;

CREATE TABLE user
(
   id BIGINT(20) NOT NULL COMMENT '主键ID',
   name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
   age INT(11) NULL DEFAULT NULL COMMENT '年龄',
   email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
   PRIMARY KEY (id)
);

附录

Caffeine 组件

Caffeine是一个基于Java8开发的提供了近乎最佳命中率的高性能的缓存库。并且在 spring5 (springboot 2.x) 后,spring 官方放弃了 Guava,而使用了性能更优秀的 Caffeine 作为默认缓存组件。

缓存和ConcurrentMap有点相似,但还是有所区别。最根本的区别是ConcurrentMap将会持有所有加入到缓存当中的元素,直到它们被从缓存当中手动移除。但是,Caffeine的缓存Cache 通常会被配置成自动驱逐缓存中元素,以限制其内存占用。在某些场景下,LoadingCache和AsyncLoadingCache 因为其自动加载缓存的能力将会变得非常实用。

Caffeine提供了灵活的构造器去创建一个拥有下列特性的缓存:

  • 自动加载元素到缓存当中,异步加载的方式也可供选择
  • 当达到最大容量的时候可以使用基于就近度和频率的算法进行基于容量的驱逐
  • 将根据缓存中的元素上一次访问或者被修改的时间进行基于过期时间的驱逐
  • 当向缓存中一个已经过时的元素进行访问的时候将会进行异步刷新
  • key将自动被弱引用所封装
  • value将自动被弱引用或者软引用所封装
  • 驱逐(或移除)缓存中的元素时将会进行通知
  • 写入传播到一个外部数据源当中
  • 持续计算缓存的访问统计指标

Java中四种引用类型

引用类型垃圾回收用途生存时间
强引用 Strong Reference从来不会对象的一般状态jvm停止运行时终止
软引用 Soft Reference在内存不足时对象缓存内存不足时终止
弱引用 Weak Reference在垃圾回收时对象缓存gc运行后终止
虚引用 Phantom Reference从来不会跟踪对象被垃圾回收器回收的活动,当一个虚引用关联的对象被垃圾收集器回收之前会收到一条系统通知jvm停止运行时终止
Edit this page
Last Updated:
Contributors: wangxiaoquan
Prev
15-分布式锁
Next
17-DynamicDatasource