1. 概述

简单来说,JCache 是 Java 的标准缓存 API。本文将深入探讨 JCache 的核心概念及实际应用场景,帮助开发者快速掌握其精髓。

2. Maven 依赖

要在项目中使用 JCache,需在 pom.xml 添加以下依赖:

<dependency>
    <groupId>javax.cache</groupId>
    <artifactId>cache-api</artifactId>
    <version>1.1.1</version>
</dependency>

✅ 最新版本可在 Maven 中央仓库 查询

同时需要添加具体实现(本文以 Hazelcast 为例):

<dependency>
    <groupId>com.hazelcast</groupId>
    <artifactId>hazelcast</artifactId>
    <version>5.2.0</version>
</dependency>

✅ Hazelcast 最新版本见 Maven 中央仓库

3. 主流实现方案

JCache 已被多种缓存解决方案实现:

  • JCache 参考实现
  • Hazelcast
  • Oracle Coherence
  • Terracotta Ehcache
  • Infinispan
  • Redisson
  • Apache Ignite

⚠️ 重要提醒:JCache 参考实现存在并发问题,生产环境强烈不推荐使用

4. 核心组件

4.1. Cache 接口

提供以下核心方法:

  • get() - 根据键获取值,键不存在返回 null
  • getAll() - 批量获取多个键值对,返回 Map
  • getAndRemove() - 获取值后立即删除条目
  • put() - 插入新条目
  • clear() - 清空所有缓存
  • containsKey() - 检查键是否存在

这些方法名已具备自解释性,完整文档见 Javadoc

4.2. CacheManager

最核心的接口之一,负责:

  • 创建缓存实例
  • 配置缓存参数
  • 管理缓存生命周期

4.3. CachingProvider

用于管理 CacheManager 的生命周期:

  • 创建 CacheManager 实例
  • 控制 CacheManager 的初始化与销毁

4.4. Configuration

缓存配置接口,包含:

  • 具体实现类:MutableConfiguration
  • 子接口:CompleteConfiguration

5. 创建缓存实例

创建简单缓存的完整流程:

CachingProvider cachingProvider = Caching.getCachingProvider();
CacheManager cacheManager = cachingProvider.getCacheManager();
MutableConfiguration<String, String> config
  = new MutableConfiguration<>();
Cache<String, String> cache = cacheManager
  .createCache("simpleCache", config);
cache.put("key1", "value1");
cache.put("key2", "value2");
cacheManager.close();

执行步骤:

  1. 通过 CachingProvider 创建 CacheManager
  2. 使用 MutableConfiguration 构建配置
  3. 创建 Cache 实例
  4. 存入缓存数据
  5. 关闭 CacheManager 释放资源

踩坑提醒:若未添加 JCache 实现,会抛出以下异常:

javax.cache.CacheException: No CachingProviders have been configured

原因:JVM 无法找到 getCacheManager() 的具体实现

6. EntryProcessor 原子操作

EntryProcessor 支持原子化修改缓存条目,无需重新添加:

public class SimpleEntryProcessor
  implements EntryProcessor<String, String, String>, Serializable {
    
    public String process(MutableEntry<String, String> entry, Object... args)
      throws EntryProcessorException {

        if (entry.exists()) {
            String current = entry.getValue();
            entry.setValue(current + " - modified");
            return current;
        }
        return null;
    }
}

使用示例:

@Test
public void whenModifyValue_thenCorrect() {
    this.cache.invoke("key", new SimpleEntryProcessor());
 
    assertEquals("value - modified", cache.get("key"));
}

7. 事件监听机制

通过事件监听器可响应以下事件类型:

  • CREATED - 条目创建
  • UPDATED - 条目更新
  • REMOVED - 条目删除
  • EXPIRED - 条目过期

实现监听器示例:

public class SimpleCacheEntryListener implements
  CacheEntryCreatedListener<String, String>,
  CacheEntryUpdatedListener<String, String>,
  Serializable {
    
    private boolean updated;
    private boolean created;
    
    // 标准 getter 方法
    
    public void onUpdated(
      Iterable<CacheEntryEvent<? extends String,
      ? extends String>> events) throws CacheEntryListenerException {
        this.updated = true;
    }
    
    public void onCreated(
      Iterable<CacheEntryEvent<? extends String,
      ? extends String>> events) throws CacheEntryListenerException {
        this.created = true;
    }
}

测试用例:

@Test
public void whenRunEvent_thenCorrect() throws InterruptedException {
    this.listenerConfiguration
      = new MutableCacheEntryListenerConfiguration<String, String>(
        FactoryBuilder.factoryOf(this.listener), null, false, true);
    this.cache.registerCacheEntryListener(this.listenerConfiguration);
    
    assertEquals(false, this.listener.getCreated());
    
    this.cache.put("key", "value");
 
    assertEquals(true, this.listener.getCreated());
    assertEquals(false, this.listener.getUpdated());
    
    this.cache.put("key", "newValue");
 
    assertEquals(true, this.listener.getUpdated());
}

8. CacheLoader 读取穿透

CacheLoader 实现读取穿透模式,将缓存作为主数据源:

public class SimpleCacheLoader
  implements CacheLoader<Integer, String> {

    public String load(Integer key) throws CacheLoaderException {
        return "fromCache" + key;
    }
    
    public Map<Integer, String> loadAll(Iterable<? extends Integer> keys)
      throws CacheLoaderException {
        Map<Integer, String> data = new HashMap<>();
        for (int key : keys) {
            data.put(key, load(key));
        }
        return data;
    }
}

集成测试:

public class CacheLoaderIntegrationTest {
    
    private Cache<Integer, String> cache;
    
    @Before
    public void setup() {
        CachingProvider cachingProvider = Caching.getCachingProvider();
        CacheManager cacheManager = cachingProvider.getCacheManager();
        MutableConfiguration<Integer, String> config
          = new MutableConfiguration<>()
            .setReadThrough(true)
            .setCacheLoaderFactory(new FactoryBuilder.SingletonFactory<>(
              new SimpleCacheLoader()));
        this.cache = cacheManager.createCache("SimpleCache", config);
    }
    
    @Test
    public void whenReadingFromStorage_thenCorrect() {
        for (int i = 1; i < 4; i++) {
            String value = cache.get(i);
 
            assertEquals("fromCache" + i, value);
        }
    }
}

9. 总结

本文系统介绍了 JCache 的核心概念与实战技巧:

  • 标准化缓存 API 的优势
  • 核心组件的协作机制
  • 原子操作与事件监听实现
  • 读取穿透模式的最佳实践

完整示例代码见 GitHub 仓库


原始标题:Introduction to JCache

» 下一篇: Retrofit 介绍