CaffeineCache详解

一、CaffeineCache排序

CaffeineCache是一个高性能的本地缓存工具,它作为一个新兴的缓存框架,性能表现高于Guava Cache等前辈,其中缓存项的排序也是CaffeineCache比较显著的特点,下面是一个简单的使用代码实例:

Cache cache = Caffeine.newBuilder().maximumSize(10)
            .expireAfterWrite(5, TimeUnit.MINUTES)
            .removalListener((key, value, cause) ->
                    log.info("key:{} value:{} 被移除,原因:{}", key, value, cause))
            .build();
cache.put("a", 10);
cache.put("b", 20);
cache.put("c", 30);
Map map = cache.asMap();
List<Entry> entries = new ArrayList(map.entrySet());
entries.sort(Entry.comparingByValue());

这里我们使用了Java的Map数据结构,通过将Map转化成List,利用Java8的stream API进行排序。当然,CaffeineCache也可以自定义比较器实现排序。

二、CaffeineCache Spring Boot

当然,CaffeineCache也可以和Spring Boot集成,实现更便捷的使用方式,并可以利用Spring Boot提供的一些特性。具体的使用步骤如下:

1、首先在pom.xml中引入相关依赖:

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

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

2、在Spring Boot项目的配置文件中配置CaffeineCache属性:

spring.cache.type=caffeine
spring.cache.caffeine.spec=maximumSize=100,expireAfterAccess=5s

3、在需要启用CaffeineCache的Bean上添加@Cacheable注解即可:

@Cacheable(value="user-key")
public User getUserById(String userId) {
    log.info("UserServiceImpl.getUserById() id: "+ userId);
    return userDao.queryUserById(userId);
}

三、CaffeineCache使用

CaffeineCache的使用非常简单,只需要按照下面的步骤操作即可:

1、我们需要创建一个CaffeineCache对象:

LoadingCache cache = Caffeine.newBuilder()
        .maximumSize(100)
        .expireAfterAccess(1, TimeUnit.DAYS)
        .build(new CacheLoader<String, String>() {
            public String load(String key) throws Exception {
                return createExpensiveGraph(key);
            }
        });

2、我们可以访问缓存中的对象:

try {
    String result = cache.get(key);
    // Do something with result
} catch (ExecutionException e) {
    throw new RuntimeException(e);
}

3、我们也可以手动刷新缓存中的对象:

cache.refresh(key);

四、CaffeineCache源码

CaffeineCache的源码具有一定的复杂性,主要是由于其采用了CAS等技术实现了高性能以及线程安全等特性。下面是CaffeineCache的一个简单单例模式实现代码:

public class CaffeineCache {
    private static Cache cache;

    public static synchronized Cache getInstance() {
        if (cache == null) {
            cache = Caffeine.newBuilder()
                    .maximumSize(1000)
                    .build();
        }
        return cache;
    }
}

五、CaffeineCacheLoad

CaffeineCache的加载机制也是其性能表现优异的原因之一,与Guava Cache类似,CaffeineCache也支持自定义加载机制,只需要实现CacheLoader接口即可:

LoadingCache graphs = Caffeine.newBuilder()
        .maximumSize(10_000)
        .build(key -> createExpensiveGraph(key));

private Graph createExpensiveGraph(Key key) {
    return new Graph(key);
}

六、CaffeineCacheManager

CaffeineCache的管理器CaffeineCacheManager实现了Spring CacheManager的接口,可以与Spring Boot集成,由Spring Boot自动装配。下面是CaffeineCacheManager的代码示例:

@Bean
public CacheManager cacheManager() {
    CaffeineCacheManager cacheManager = new CaffeineCacheManager();
    cacheManager.setCaffeine(Caffeine.newBuilder().expireAfterWrite(2, TimeUnit.HOURS));
    return cacheManager;
}

七、CaffeineCache线程安全

CaffeineCache支持线程安全,通过重载CacheLoader和RemovalListener接口实现:

LoadingCache graphs = Caffeine.newBuilder()
        .maximumSize(10_000)
        .executor(Runnable::run)  // DirectExecutor
        .removalListener((key, graph, cause) -> {
            if (cause.wasEvicted()) {
                log.info("Graph with key {} was evicted ({})", key, cause.getCause());
            }
        })
        .build(new CacheLoader() {
            public Graph load(Key key) throws AnyException {
                return createExpensiveGraph(key);
            }
        });

八、CaffeineCacheManager Redis

与Redis集成,需要引入以下依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>com.github.ben-manes.caffeine</groupId>
    <artifactId>caffeine</artifactId>
    <version>2.8.8</version>
</dependency>
<dependency>
    <groupId>io.lettuce</groupId>
    <artifactId>lettuce-core</artifactId>
</dependency>

然后在Spring Boot项目的配置文件中增加如下配置:

spring.cache.cache-names=cache_a,cache_b
spring.cache.type=redis
spring.redis.host=localhost
spring.redis.password=password
spring.redis.port=6379
spring.redis.database=1
spring.cache.redis.use-key-prefix=true
spring.cache.redis.key-prefix=my_app_prefix
spring.cache.redis.cache-null-values=true

最后,我们可以创建RedisCache对象并设置CaffeineCache为其CacheLoader:

CacheLoader<Object, Object> myCacheLoader = new CacheLoader<Object, Object>() {
    public Object load(Object key) {
        // do something to load cache
        ...
    }
};
RedisCache myCache = new RedisCache("cacheName", lettuceConnectionFactory, myCacheConfig);
LoadingCache<Object, Object> cache = Caffeine.newBuilder().maximumSize(10000).build(myCacheLoader);
myCache.setCaffeineCache(cache);

九、CaffeineCache本地调试不生效

如果我们在本地调试时,发现CaffeineCache不生效,可以尝试以下方式进行解决:

1、确认是否注入了CaffeineCacheManager,以及是否配置了有效的属性。

@Bean
public CacheManager cacheManager() {
    CaffeineCacheManager cacheManager = new CaffeineCacheManager();
    cacheManager.setCaffeine(Caffeine.newBuilder().expireAfterWrite(2, TimeUnit.HOURS));
    return cacheManager;
}

2、确认是否在启动类中添加@EnableCaching注解。

@SpringBootApplication
@EnableCaching
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

3、如果使用了Spring Boot,可以在application.yml或者application.properties中增加如下代码:

management:
  endpoints:
    web:
      exposure:
        include: "*"

以上就是对CaffeineCache的详细介绍,我们可以根据不同的需求,选择不同的使用方式以及相关配置,并可以利用其提供的高性能、线程安全等特性,优化我们的应用程序性能。

原创文章,作者:XTMJA,如若转载,请注明出处:https://www.506064.com/n/317023.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
XTMJAXTMJA
上一篇 2025-01-09 12:15
下一篇 2025-01-09 12:23

相关推荐

  • 神经网络代码详解

    神经网络作为一种人工智能技术,被广泛应用于语音识别、图像识别、自然语言处理等领域。而神经网络的模型编写,离不开代码。本文将从多个方面详细阐述神经网络模型编写的代码技术。 一、神经网…

    编程 2025-04-25
  • Linux sync详解

    一、sync概述 sync是Linux中一个非常重要的命令,它可以将文件系统缓存中的内容,强制写入磁盘中。在执行sync之前,所有的文件系统更新将不会立即写入磁盘,而是先缓存在内存…

    编程 2025-04-25
  • Python输入输出详解

    一、文件读写 Python中文件的读写操作是必不可少的基本技能之一。读写文件分别使用open()函数中的’r’和’w’参数,读取文件…

    编程 2025-04-25
  • git config user.name的详解

    一、为什么要使用git config user.name? git是一个非常流行的分布式版本控制系统,很多程序员都会用到它。在使用git commit提交代码时,需要记录commi…

    编程 2025-04-25
  • 详解eclipse设置

    一、安装与基础设置 1、下载eclipse并进行安装。 2、打开eclipse,选择对应的工作空间路径。 File -> Switch Workspace -> [选择…

    编程 2025-04-25
  • MPU6050工作原理详解

    一、什么是MPU6050 MPU6050是一种六轴惯性传感器,能够同时测量加速度和角速度。它由三个传感器组成:一个三轴加速度计和一个三轴陀螺仪。这个组合提供了非常精细的姿态解算,其…

    编程 2025-04-25
  • C语言贪吃蛇详解

    一、数据结构和算法 C语言贪吃蛇主要运用了以下数据结构和算法: 1. 链表 typedef struct body { int x; int y; struct body *nex…

    编程 2025-04-25
  • Linux修改文件名命令详解

    在Linux系统中,修改文件名是一个很常见的操作。Linux提供了多种方式来修改文件名,这篇文章将介绍Linux修改文件名的详细操作。 一、mv命令 mv命令是Linux下的常用命…

    编程 2025-04-25
  • Java BigDecimal 精度详解

    一、基础概念 Java BigDecimal 是一个用于高精度计算的类。普通的 double 或 float 类型只能精确表示有限的数字,而对于需要高精度计算的场景,BigDeci…

    编程 2025-04-25
  • nginx与apache应用开发详解

    一、概述 nginx和apache都是常见的web服务器。nginx是一个高性能的反向代理web服务器,将负载均衡和缓存集成在了一起,可以动静分离。apache是一个可扩展的web…

    编程 2025-04-25

发表回复

登录后才能评论