Apache Commons JCS 3.2.1 快速入门与集成示例

Apache Commons JCS 3.2.1 快速入门与集成示例:从 Maven 依赖到最小内存缓存示例,再到 cache.ccf 磁盘持久化与重启读回验证,全部代码真实编译运行并给出完整回显。

Apache Commons JCSApache Commons JCS2026/10/14

Apache Commons JCS 3.2.1 快速入门与集成示例

目标:以 0→1 主线完成 Apache Commons JCS 3.2.1 的首次集成——引入 Maven 依赖、跑通最小缓存程序、配置 cache.ccf 启用磁盘持久化,并以「写入进程退出 → 新进程读回 20/20」验证持久化闭环。以下全部命令与回显均已在 Ubuntu 22.04(x86_64)实测通过。

一、环境信息

本节固定实测基线,全文共用同一工程目录。

  • 操作系统:Ubuntu 22.04(x86_64)
  • JDK:OpenJDK 17.0.20.1(java -version 回显见《Ubuntu 22.04 安装 Apache Commons JCS 指南》4.2 节,本文工程同环境)
  • 构建工具:Apache Maven 3.6.3
  • 目标库:Apache Commons JCS 3.2.1(org.apache.commons:commons-jcs3-core:3.2.1)
  • 示例工程目录:/opt/jcs-demo
  • 源码目录:/opt/jcs-demo/src/main/java/demo
  • 配置目录:/opt/jcs-demo/conf(cache.ccf 所在,以目录加入 classpath)
  • 运行时 classpath 文件:/opt/jcs-demo/cp.txt
  • 磁盘缓存数据目录:/opt/jcs-demo/disk-cache

二、前置条件

按以下清单逐项确认,缺一项都会在后续步骤中断。

  1. root 权限:工程创建在 /opt 下。
  2. JDK 17 与 Maven 可用:验证方式与回显见《Ubuntu 22.04 安装 Apache Commons JCS 指南》4.2 节(同一环境)。
  3. 网络可达 Maven 中央仓库:第三章的 dependency:get 即为连通性实测。
  4. 磁盘预留 ≥ 100 MB:依赖 jar 与磁盘缓存文件所需。

三、依赖引入

新建 Maven 工程 /opt/jcs-demo 并声明 JCS 依赖。/opt/jcs-demo/pom.xml 完整内容:

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>demo</groupId>
  <artifactId>jcs-demo</artifactId>
  <version>1.0.0</version>
  <packaging>jar</packaging>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.release>17</maven.compiler.release>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-jcs3-core</artifactId>
      <version>3.2.1</version>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.11.0</version>
        <configuration>
          <release>17</release>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

逐项说明:dependencies 只声明核心构件 commons-jcs3-core:3.2.1;maven.compiler.release=17 与 compiler 插件 <release>17</release> 指定 JDK 17 编译;project.build.sourceEncoding=UTF-8 保证中文注释正常编译。这是缓存库 Apache Commons JCS 在 Maven 工程中的标准接入形态。

从中央仓库预拉取构件(首次下载实测约 3 分钟):

cd /opt/jcs-demo && mvn -B dependency:get -Dartifact=org.apache.commons:commons-jcs3-core:3.2.1

输出节选(实测末尾 12 行):

[INFO] Downloading from central: https://repo.maven.apache.org/maven2/org/hamcrest/hamcrest/2.2/hamcrest-2.2.jar
[INFO] Downloaded from central: https://repo.maven.apache.org/maven2/junit/junit/4.13.2/junit-4.13.2.jar (385 kB at 520 kB/s)
[INFO] Downloaded from central: https://repo.maven.apache.org/maven2/hsqldb/hsqldb/1.8.0.10/hsqldb-1.8.0.10.jar (707 kB at 666 kB/s)
[INFO] Downloaded from central: https://repo.maven.apache.org/maven2/org/apache/commons/commons-collections4/4.4/commons-collections4-4.4.jar (752 kB at 709 kB/s)
[INFO] Downloaded from central: https://repo.maven.apache.org/maven2/org/hamcrest/hamcrest/2.2/hamcrest-2.2.jar (123 kB at 60 kB/s)
[INFO] Downloaded from central: https://repo.maven.apache.org/maven2/org/apache/commons/commons-jcs3-core/3.2.1/commons-jcs3-core-3.2.1.jar (547 kB at 37 kB/s)
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  02:54 min
[INFO] Finished at: 2026-10-14T10:22:06Z
[INFO] ------------------------------------------------------------------------

验证依赖解析结果:

cd /opt/jcs-demo && mvn -B dependency:tree

输出节选(实测):

[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ jcs-demo ---
[INFO] demo:jcs-demo:jar:1.0.0
[INFO] \- org.apache.commons:commons-jcs3-core:jar:3.2.1:compile
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------

💡 技术拓展:选缓存库时值得把主流方案放在一起比一次——

方案形态特点适用场景
Apache Commons JCS进程内 Java 库Apache 出品、内存+磁盘分层、可配 LRU 淘汰、支持 JCache 标准嵌入应用的本地缓存、需磁盘持久化
Ehcache进程内 Java 库功能全、堆外缓存与 Terracotta 集群能力强Spring 生态本地缓存
Caffeine进程内 Java 库基于 W-TinyLFU、内存命中率与性能最优、仅内存纯内存高性能缓存
Redis(Jedis/Lettuce 客户端)独立缓存服务跨进程共享、数据结构丰富、需运维服务端多实例共享数据、分布式场景
Infinispan嵌入式/服务端混合数据网格、分布式模式、跨节点复制大规模数据网格与集群

本文快速入门场景需要「进程内缓存 + 重启后数据恢复」,因此实际采用 Apache Commons JCS:依赖树证明它零传递依赖(上表回显仅一行 core jar)、磁盘缓存可跨进程持久化,接入成本最低。

四、核心 API 与配置速览

写代码前先看清两件事:程序侧用哪几个 API,配置侧必须提供什么。

程序侧三个动作(完整演示见第五章):

步骤API说明
获取区域句柄JCS.getInstance("区域名")静态工厂;区域未在配置中定义时按默认属性即时创建
读写cache.put(k, v) / cache.get(k)get 未命中返回 null,不抛异常
收尾cache.dispose()(磁盘区域加 JCS.shutdown())磁盘缓存的落盘依赖 dispose 阶段

配置侧一条铁律:JCS 从 classpath 上加载名为 cache.ccf 的资源(日志显示为 /cache.ccf)。classpath 上没有 cache.ccf 时 3.2.1 直接抛 NullPointerException,不回退默认配置——第五章 5.1 将实测复现这个坑,因此先把配置目录规划好:

  • 本文做法:独立 conf/ 目录存放 cache.ccf,运行时把该目录加入 -cp(适合「配置随部署走」)。
  • 等价做法:放 src/main/resources/,随编译进 target/classes(见《CentOS 8 安装 Apache Commons JCS 指南》4.4 节实测)。

⚠️ 注意:cache.ccf 是快速入门成败的分水岭——代码可以一行不改,配置缺位程序就无法启动。

五、最小示例:内存缓存读写与统计

5.1 编写演示程序

/opt/jcs-demo/src/main/java/demo/BasicCacheDemo.java 完整源码:

package demo;

import java.util.List;

import org.apache.commons.jcs3.JCS;
import org.apache.commons.jcs3.access.CacheAccess;
import org.apache.commons.jcs3.engine.stats.behavior.IStatElement;
import org.apache.commons.jcs3.engine.stats.behavior.IStats;

/**
 * 基础缓存演示: put / get / 命中率统计 / remove / clear
 */
public class BasicCacheDemo {

    public static void main(String[] args) {
        CacheAccess<String, String> cache = JCS.getInstance("demoRegion");

        System.out.println("[put] k1..k3");
        cache.put("k1", "value-1");
        cache.put("k2", "value-2");
        cache.put("k3", "value-3");

        System.out.println("[get] 5 次 (3 命中 2 未命中)");
        for (int i = 1; i <= 5; i++) {
            String k = "k" + i;
            System.out.println("  get(" + k + ") = " + cache.get(k));
        }

        System.out.println("[remove] k1");
        cache.remove("k1");
        System.out.println("  get(k1) after remove = " + cache.get("k1"));

        System.out.println("[statistics]");
        printStats(cache.getStatistics());
        System.out.println("  getStats() = " + cache.getStats());

        System.out.println("[clear]");
        cache.clear();
        System.out.println("  get(k2) after clear = " + cache.get("k2"));

        System.out.println("[statistics after clear]");
        printStats(cache.getStatistics());
        System.out.println("  getStats() = " + cache.getStats());

        cache.dispose();
        System.out.println("done");
    }

    private static void printStats(IStats stats) {
        System.out.println("  type = " + stats.getTypeName());
        List<IStatElement<?>> elems = stats.getStatElements();
        for (IStatElement<?> e : elems) {
            System.out.println("  " + e.getName() + " = " + e.getData());
        }
    }
}

同目录再创建 /opt/jcs-demo/src/main/java/demo/DiskCacheDemo.java(第六章运行,本章先随工程一起编译):

package demo;

import org.apache.commons.jcs3.JCS;
import org.apache.commons.jcs3.access.CacheAccess;

/**
 * 磁盘缓存演示: java demo.DiskCacheDemo [put|get]
 * region: diskRegion, 配置见 conf/cache.ccf (IndexedDiskCache, DiskPath=/opt/jcs-demo/disk-cache)
 */
public class DiskCacheDemo {

    public static void main(String[] args) {
        String mode = args.length > 0 ? args[0] : "put";
        CacheAccess<String, String> cache = JCS.getInstance("diskRegion");

        if ("put".equals(mode)) {
            for (int i = 1; i <= 20; i++) {
                cache.put("disk-key-" + i, "disk-value-" + i);
            }
            System.out.println("put 完成: disk-key-1..20");
            System.out.println("get(disk-key-7) = " + cache.get("disk-key-7"));
        } else {
            int found = 0;
            for (int i = 1; i <= 20; i++) {
                String v = cache.get("disk-key-" + i);
                if (v != null) {
                    found++;
                }
                System.out.println("get(disk-key-" + i + ") = " + v);
            }
            System.out.println("命中条数: " + found + "/20");
        }

        cache.dispose();
        JCS.shutdown();
        System.out.println("done");
    }
}

编译并生成运行时 classpath:

cd /opt/jcs-demo && mvn -B compile && mvn -B dependency:build-classpath -Dmdep.outputFile=/opt/jcs-demo/cp.txt 2>&1 | tail -3
cat cp.txt

输出节选(实测;compile 段见《Ubuntu 22.04 安装 Apache Commons JCS 指南》4.5 节,此处为 build-classpath 末尾 3 行):

[INFO] Total time:  0.738 s
[INFO] Finished at: 2026-10-14T10:24:52Z
[INFO] ------------------------------------------------------------------------
/root/.m2/repository/org/apache/commons/commons-jcs3-core/3.2.1/commons-jcs3-core-3.2.1.jar

5.2 先踩坑:无配置直接 NPE

工程此刻还没有 cache.ccf。直接运行,实测复现第四章预告的坑:

cd /opt/jcs-demo && java -cp target/classes:$(cat cp.txt) demo.BasicCacheDemo

输出:

Oct 14, 2026 10:25:01 AM org.apache.commons.jcs3.engine.control.CompositeCacheManager
INFO: Instance is null, creating with config [/cache.ccf]
Oct 14, 2026 10:25:01 AM org.apache.commons.jcs3.engine.control.CompositeCacheManager
INFO: Creating cache manager from config file: /cache.ccf
Exception in thread "main" java.lang.NullPointerException: inStream parameter is null
        at java.base/java.util.Objects.requireNonNull(Objects.java:235)
        at java.base/java.util.Properties.load(Properties.java:410)
        at org.apache.commons.jcs3.engine.control.CompositeCacheManager.configure(CompositeCacheManager.java:328)
        at org.apache.commons.jcs3.engine.control.CompositeCacheManager.getInstance(CompositeCacheManager.java:188)
        at org.apache.commons.jcs3.engine.control.CompositeCacheManager.getInstance(CompositeCacheManager.java:163)
        at org.apache.commons.jcs3.JCS.getCacheManager(JCS.java:126)
        at org.apache.commons.jcs3.JCS.getInstance(JCS.java:144)
        at demo.BasicCacheDemo.main(BasicCacheDemo.java:16)

⚠️ 注意:栈顶 Properties.load 的 inStream parameter is null 即「classpath 上没有 cache.ccf」。JCS 3.2.1 不回退默认配置,修复方式只有一个——提供配置文件。

5.3 提供配置文件

创建 /opt/jcs-demo/conf/cache.ccf 完整内容(本章先用它的默认区域语义跑通内存示例;diskRegion 与 DC 三段的磁盘语义在第六章逐项展开):

# JCS 配置: 仅对 diskRegion 启用索引磁盘缓存
# 内存缓存: LRU, 最多 100 条

# diskRegion: 内存上限 10 条, UPDATE 模式(写入即落盘), 辅助缓存 DC
jcs.region.diskRegion=DC
jcs.region.diskRegion.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.diskRegion.cacheattributes.MaxObjects=10
jcs.region.diskRegion.cacheattributes.MemoryCacheName=org.apache.commons.jcs3.engine.memory.lru.LRUMemoryCache
jcs.region.diskRegion.cacheattributes.DiskUsagePatternName=UPDATE

# DC = IndexedDiskCache, 磁盘文件目录
jcs.auxiliary.DC=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheFactory
jcs.auxiliary.DC.attributes=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes
jcs.auxiliary.DC.attributes.DiskPath=/opt/jcs-demo/disk-cache

5.4 运行与统计解读

把 conf 加入 classpath 后重新运行(-Dfile.encoding=UTF-8 用于默认编码为 ANSI_X3.4-1968 的环境避免中文乱码):

cd /opt/jcs-demo && java -Dfile.encoding=UTF-8 -cp target/classes:conf:$(cat cp.txt) demo.BasicCacheDemo

输出:

Oct 14, 2026 10:27:14 AM org.apache.commons.jcs3.engine.control.CompositeCacheManager
INFO: Instance is null, creating with config [/cache.ccf]
Oct 14, 2026 10:27:14 AM org.apache.commons.jcs3.engine.control.CompositeCacheManager
INFO: Creating cache manager from config file: /cache.ccf
Oct 14, 2026 10:27:14 AM org.apache.commons.jcs3.engine.control.CompositeCacheManager
INFO: Setting default auxiliaries to "null"
Oct 14, 2026 10:27:14 AM org.apache.commons.jcs3.engine.control.CompositeCacheConfigurator
INFO: No special CompositeCacheAttributes class defined for key [jcs.default.cacheattributes], using default class.
Oct 14, 2026 10:27:14 AM org.apache.commons.jcs3.engine.control.CompositeCacheManager
INFO: setting defaultCompositeCacheAttributes to [ useLateral = true, useRemote = true, useDisk = true, maxObjs = 100, maxSpoolPerRun = -1, diskUsagePattern = SWAP, spoolChunkSize = 2 ]
Oct 14, 2026 10:27:14 AM org.apache.commons.jcs3.engine.control.CompositeCacheConfigurator
INFO: No special ElementAttribute class defined for key [jcs.default.elementattributes], using default class.
Oct 14, 2026 10:27:14 AM org.apache.commons.jcs3.engine.control.CompositeCacheManager
INFO: setting defaultElementAttributes to [ IS_LATERAL = true, IS_SPOOL = true, IS_REMOTE = true, IS_ETERNAL = true, MaxLifeSeconds = -1, IdleTime = -1, CreateTime = 1791973634659, LastAccessTime = 1791973634659, getTimeToLiveSeconds() = -1, createTime = 1791973634659 ]
Oct 14, 2026 10:27:14 AM org.apache.commons.jcs3.engine.control.CompositeCacheConfigurator
INFO: No special ElementAttribute class defined for key [jcs.region.diskRegion.elementattributes], using default class.
Oct 14, 2026 10:27:14 AM org.apache.commons.jcs3.engine.memory.AbstractDoubleLinkedListMemoryCache
INFO: initialized MemoryCache for diskRegion
Oct 14, 2026 10:27:14 AM org.apache.commons.jcs3.engine.control.CompositeCache
INFO: Constructed cache with name [diskRegion] and cache attributes [ useLateral = true, useRemote = true, useDisk = true, maxObjs = 10, maxSpoolPerRun = -1, diskUsagePattern = UPDATE, spoolChunkSize = 2 ]
Oct 14, 2026 10:27:14 AM org.apache.commons.jcs3.auxiliary.AuxiliaryCacheConfigurator
INFO: No cache event logger defined for auxiliary [jcs.auxiliary.DC]
Oct 14, 2026 10:27:14 AM org.apache.commons.jcs3.auxiliary.AuxiliaryCacheConfigurator
INFO: Using standard serializer [org.apache.commons.jcs3.utils.serialization.StandardSerializer@5025a98f] for auxiliary [jcs.auxiliary.DC]
Oct 14, 2026 10:27:14 AM org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCache
INFO: Region [diskRegion] : Set maxKeySize to: "5,000"
Oct 14, 2026 10:27:14 AM org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCache
INFO: Region [diskRegion] : Cache file root directory: /opt/jcs-demo/disk-cache
Oct 14, 2026 10:27:14 AM org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCache
INFO: Region [diskRegion] : Indexed Disk Cache is alive.
Oct 14, 2026 10:27:14 AM org.apache.commons.jcs3.engine.control.CompositeCacheConfigurator
INFO: Parsed regions [diskRegion]
Oct 14, 2026 10:27:14 AM org.apache.commons.jcs3.engine.control.CompositeCacheManager
INFO: Finished configuration in 67 ms.
Oct 14, 2026 10:27:14 AM org.apache.commons.jcs3.engine.control.CompositeCacheConfigurator
INFO: No special ElementAttribute class defined for key [jcs.region.demoRegion.elementattributes], using default class.
Oct 14, 2026 10:27:14 AM org.apache.commons.jcs3.engine.memory.AbstractDoubleLinkedListMemoryCache
INFO: initialized MemoryCache for demoRegion
Oct 14, 2026 10:27:14 AM org.apache.commons.jcs3.engine.control.CompositeCache
INFO: Constructed cache with name [demoRegion] and cache attributes [ useLateral = true, useRemote = true, useDisk = true, maxObjs = 100, maxSpoolPerRun = -1, diskUsagePattern = SWAP, spoolChunkSize = 2 ]
[put] k1..k3
[get] 5 次 (3 命中 2 未命中)
  get(k1) = value-1
  get(k2) = value-2
  get(k3) = value-3
  get(k4) = null
  get(k5) = null
[remove] k1
  get(k1) after remove = null
[statistics]
  type = null
  HitCountRam = 3
  HitCountAux = 0
  getStats() = Region Name = demoRegion
HitCountRam = 3
HitCountAux = 0
---------------------------Memory Cache
Put Count = 3
Hit Count = 3
Miss Count = 3
Map Size = 2
List Size = 2
[clear]
  get(k2) after clear = null
[statistics after clear]
  type = null
  HitCountRam = 3
  HitCountAux = 0
  getStats() = Region Name = demoRegion
HitCountRam = 3
HitCountAux = 0
---------------------------Memory Cache
Put Count = 3
Hit Count = 3
Miss Count = 4
Map Size = 0
List Size = 0
Oct 14, 2026 10:27:14 AM org.apache.commons.jcs3.engine.control.CompositeCache
INFO: In DISPOSE, [demoRegion] fromRemote [false]
Oct 14, 2026 10:27:14 AM org.apache.commons.jcs3.engine.control.event.ElementEventQueue
INFO: Element event queue destroyed: org.apache.commons.jcs3.engine.control.event.ElementEventQueue@5bcea91b
Oct 14, 2026 10:27:14 AM org.apache.commons.jcs3.engine.control.CompositeCache
INFO: In DISPOSE, [demoRegion] disposing of memory cache.
Oct 14, 2026 10:27:14 AM org.apache.commons.jcs3.engine.memory.AbstractMemoryCache
INFO: Memory Cache dispose called.
done

💡 说明:从 5.2 的 NPE 到本节 done,唯一变化是 conf 目录进入 classpath。统计口径逐项核对——Put Count = 3(三次 put)、Hit Count = 3(命中 k1/k2/k3)、Miss Count = 3(k4/k5 加 remove 后的 k1)、Map Size = 2(remove k1 后剩 k2/k3);clear 后 Miss Count 增至 4、Map Size = 0。demoRegion 未在配置定义,日志 maxObjs = 100 走内置默认,与配置里 diskRegion 的 maxObjs = 10 形成对照。

六、磁盘持久化:写入、重启与读回验证

6.1 磁盘配置逐项说明

磁盘能力由 5.3 配置文件中的两组键实现,逐项解释:

  • jcs.region.diskRegion=DC:定义区域 diskRegion 并绑定名为 DC 的辅助缓存。
  • jcs.region.diskRegion.cacheattributes.MaxObjects=10:内存层最多 10 条,配合 DiskUsagePatternName=UPDATE 实现「写入即落盘」——每条 put 都有磁盘副本,内存只保留热数据。
  • jcs.auxiliary.DC=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheFactory 与 jcs.auxiliary.DC.attributes=org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCacheAttributes:辅助缓存的工厂与属性实现类。
  • jcs.auxiliary.DC.attributes.DiskPath=/opt/jcs-demo/disk-cache:磁盘文件目录,由 JCS 自动创建。

6.2 写入进程

cd /opt/jcs-demo && java -Dfile.encoding=UTF-8 -cp target/classes:conf:$(cat cp.txt) demo.DiskCacheDemo put

输出:

Oct 14, 2026 10:27:27 AM org.apache.commons.jcs3.engine.control.CompositeCacheManager
INFO: Instance is null, creating with config [/cache.ccf]
Oct 14, 2026 10:27:27 AM org.apache.commons.jcs3.engine.control.CompositeCacheManager
INFO: Creating cache manager from config file: /cache.ccf
Oct 14, 2026 10:27:27 AM org.apache.commons.jcs3.engine.control.CompositeCacheManager
INFO: Setting default auxiliaries to "null"
Oct 14, 2026 10:27:27 AM org.apache.commons.jcs3.engine.control.CompositeCacheConfigurator
INFO: No special CompositeCacheAttributes class defined for key [jcs.default.cacheattributes], using default class.
Oct 14, 2026 10:27:27 AM org.apache.commons.jcs3.engine.control.CompositeCacheManager
INFO: setting defaultCompositeCacheAttributes to [ useLateral = true, useRemote = true, useDisk = true, maxObjs = 100, maxSpoolPerRun = -1, diskUsagePattern = SWAP, spoolChunkSize = 2 ]
Oct 14, 2026 10:27:27 AM org.apache.commons.jcs3.engine.control.CompositeCacheConfigurator
INFO: No special ElementAttribute class defined for key [jcs.default.elementattributes], using default class.
Oct 14, 2026 10:27:27 AM org.apache.commons.jcs3.engine.control.CompositeCacheManager
INFO: setting defaultElementAttributes to [ IS_LATERAL = true, IS_SPOOL = true, IS_REMOTE = true, IS_ETERNAL = true, MaxLifeSeconds = -1, IdleTime = -1, CreateTime = 1791973647966, LastAccessTime = 1791973647966, getTimeToLiveSeconds() = -1, createTime = 1791973647966 ]
Oct 14, 2026 10:27:27 AM org.apache.commons.jcs3.engine.control.CompositeCacheConfigurator
INFO: No special ElementAttribute class defined for key [jcs.region.diskRegion.elementattributes], using default class.
Oct 14, 2026 10:27:27 AM org.apache.commons.jcs3.engine.memory.AbstractDoubleLinkedListMemoryCache
INFO: initialized MemoryCache for diskRegion
Oct 14, 2026 10:27:27 AM org.apache.commons.jcs3.engine.control.CompositeCache
INFO: Constructed cache with name [diskRegion] and cache attributes [ useLateral = true, useRemote = true, useDisk = true, maxObjs = 10, maxSpoolPerRun = -1, diskUsagePattern = UPDATE, spoolChunkSize = 2 ]
Oct 14, 2026 10:27:27 AM org.apache.commons.jcs3.auxiliary.AuxiliaryCacheConfigurator
INFO: No cache event logger defined for auxiliary [jcs.auxiliary.DC]
Oct 14, 2026 10:27:27 AM org.apache.commons.jcs3.auxiliary.AuxiliaryCacheConfigurator
INFO: Using standard serializer [org.apache.commons.jcs3.utils.serialization.StandardSerializer@5025a98f] for auxiliary [jcs.auxiliary.DC]
Oct 14, 2026 10:27:28 AM org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCache
INFO: Region [diskRegion] : Set maxKeySize to: "5,000"
Oct 14, 2026 10:27:28 AM org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCache
INFO: Region [diskRegion] : Cache file root directory: /opt/jcs-demo/disk-cache
Oct 14, 2026 10:27:28 AM org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCache
INFO: Region [diskRegion] : Indexed Disk Cache is alive.
Oct 14, 2026 10:27:28 AM org.apache.commons.jcs3.engine.control.CompositeCacheConfigurator
INFO: Parsed regions [diskRegion]
Oct 14, 2026 10:27:28 AM org.apache.commons.jcs3.engine.control.CompositeCacheManager
INFO: Finished configuration in 68 ms.
put 完成: disk-key-1..20
get(disk-key-7) = disk-value-7
Oct 14, 2026 10:27:28 AM org.apache.commons.jcs3.engine.control.CompositeCache
INFO: In DISPOSE, [diskRegion] fromRemote [false]
Oct 14, 2026 10:27:28 AM org.apache.commons.jcs3.engine.control.event.ElementEventQueue
INFO: Element event queue destroyed: org.apache.commons.jcs3.engine.control.event.ElementEventQueue@27f723
Oct 14, 2026 10:27:28 AM org.apache.commons.jcs3.engine.control.CompositeCache
INFO: In DISPOSE, [diskRegion] auxiliary [diskRegion]
Oct 14, 2026 10:27:28 AM org.apache.commons.jcs3.engine.control.CompositeCache
INFO: In DISPOSE, [diskRegion] put 9 into auxiliary [diskRegion]
Oct 14, 2026 10:27:28 AM org.apache.commons.jcs3.auxiliary.disk.AbstractDiskCache
INFO: In dispose, destroying event queue.
Oct 14, 2026 10:27:28 AM org.apache.commons.jcs3.engine.PooledCacheEventQueue
INFO: Cache event queue destroyed: CacheEventQueue [listenerId=972252816, cacheName=diskRegion]
Oct 14, 2026 10:27:28 AM org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCache
INFO: Region [diskRegion] : Saving keys to: diskRegion, key count: 20
Oct 14, 2026 10:27:28 AM org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCache
INFO: Region [diskRegion] : Finished saving keys.
Oct 14, 2026 10:27:28 AM org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCache
INFO: Region [diskRegion] : Shutdown complete.
Oct 14, 2026 10:27:28 AM org.apache.commons.jcs3.engine.control.CompositeCache
INFO: In DISPOSE, [diskRegion] disposing of memory cache.
Oct 14, 2026 10:27:28 AM org.apache.commons.jcs3.engine.memory.AbstractMemoryCache
INFO: Memory Cache dispose called.
Oct 14, 2026 10:27:28 AM org.apache.commons.jcs3.auxiliary.disk.AbstractDiskCache
INFO: In dispose, destroying event queue.
Oct 14, 2026 10:27:28 AM org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCache
SEVERE: Region [diskRegion] : Not alive and dispose was called, filename: diskRegion
done

验证磁盘文件已生成:

ls -la /opt/jcs-demo/disk-cache/

输出:

total 24
drwxr-xr-x 2 root root 4096 Oct 14 10:25 .
drwxr-xr-x 6 root root 4096 Oct 14 10:24 ..
-rw-r--r-- 1 root root 9742 Oct 14 10:27 diskRegion.data
-rw-r--r-- 1 root root  815 Oct 14 10:27 diskRegion.key

💡 说明:diskRegion.data(9,742 字节)存序列化值,diskRegion.key(815 字节)是键索引。Saving keys to: diskRegion, key count: 20 出现在 cache.dispose() 阶段——写入进程以 dispose() + JCS.shutdown() 收尾是索引落盘的前提(程序收尾逻辑见 5.1 的 DiskCacheDemo 源码)。末尾 SEVERE 是 shutdown 对已 dispose 区域的状态记录,进程正常退出,细节见《Apache Commons JCS 3.2.1 常用 API 与工具详解》4.4 节。

6.3 新进程读回(模拟重启)

另开一个全新进程只做读取:

cd /opt/jcs-demo && java -Dfile.encoding=UTF-8 -cp target/classes:conf:$(cat cp.txt) demo.DiskCacheDemo get

输出:

Oct 14, 2026 10:27:36 AM org.apache.commons.jcs3.engine.control.CompositeCacheManager
INFO: Instance is null, creating with config [/cache.ccf]
Oct 14, 2026 10:27:36 AM org.apache.commons.jcs3.engine.control.CompositeCacheManager
INFO: Creating cache manager from config file: /cache.ccf
Oct 14, 2026 10:27:36 AM org.apache.commons.jcs3.engine.control.CompositeCacheManager
INFO: Setting default auxiliaries to "null"
Oct 14, 2026 10:27:36 AM org.apache.commons.jcs3.engine.control.CompositeCacheConfigurator
INFO: No special CompositeCacheAttributes class defined for key [jcs.default.cacheattributes], using default class.
Oct 14, 2026 10:27:36 AM org.apache.commons.jcs3.engine.control.CompositeCacheManager
INFO: setting defaultCompositeCacheAttributes to [ useLateral = true, useRemote = true, useDisk = true, maxObjs = 100, maxSpoolPerRun = -1, diskUsagePattern = SWAP, spoolChunkSize = 2 ]
Oct 14, 2026 10:27:36 AM org.apache.commons.jcs3.engine.control.CompositeCacheConfigurator
INFO: No special ElementAttribute class defined for key [jcs.default.elementattributes], using default class.
Oct 14, 2026 10:27:36 AM org.apache.commons.jcs3.engine.control.CompositeCacheManager
INFO: setting defaultElementAttributes to [ IS_LATERAL = true, IS_SPOOL = true, IS_REMOTE = true, IS_ETERNAL = true, MaxLifeSeconds = -1, IdleTime = -1, CreateTime = 1791973656955, LastAccessTime = 1791973656955, getTimeToLiveSeconds() = -1, createTime = 1791973656955 ]
Oct 14, 2026 10:27:36 AM org.apache.commons.jcs3.engine.control.CompositeCacheConfigurator
INFO: No special ElementAttribute class defined for key [jcs.region.diskRegion.elementattributes], using default class.
Oct 14, 2026 10:27:36 AM org.apache.commons.jcs3.engine.memory.AbstractDoubleLinkedListMemoryCache
INFO: initialized MemoryCache for diskRegion
Oct 14, 2026 10:27:36 AM org.apache.commons.jcs3.engine.control.CompositeCache
INFO: Constructed cache with name [diskRegion] and cache attributes [ useLateral = true, useRemote = true, useDisk = true, maxObjs = 10, maxSpoolPerRun = -1, diskUsagePattern = UPDATE, spoolChunkSize = 2 ]
Oct 14, 2026 10:27:36 AM org.apache.commons.jcs3.auxiliary.AuxiliaryCacheConfigurator
INFO: No cache event logger defined for auxiliary [jcs.auxiliary.DC]
Oct 14, 2026 10:27:36 AM org.apache.commons.jcs3.auxiliary.AuxiliaryCacheConfigurator
INFO: Using standard serializer [org.apache.commons.jcs3.utils.serialization.StandardSerializer@5025a98f] for auxiliary [jcs.auxiliary.DC]
Oct 14, 2026 10:27:37 AM org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCache
INFO: Region [diskRegion] : Set maxKeySize to: "5,000"
Oct 14, 2026 10:27:37 AM org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCache
INFO: Region [diskRegion] : Cache file root directory: /opt/jcs-demo/disk-cache
Oct 14, 2026 10:27:37 AM org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCache
INFO: Region [diskRegion] : Loaded keys from [diskRegion], key count: 20; up to 5,000 will be available.
Oct 14, 2026 10:27:37 AM org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCache
INFO: Region [diskRegion] : Finished inital consistency check, isOk = true in 2ms.
Oct 14, 2026 10:27:37 AM org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCache
INFO: Region [diskRegion] : Indexed Disk Cache is alive.
Oct 14, 2026 10:27:37 AM org.apache.commons.jcs3.engine.control.CompositeCacheConfigurator
INFO: Parsed regions [diskRegion]
Oct 14, 2026 10:27:37 AM org.apache.commons.jcs3.engine.control.CompositeCacheManager
INFO: Finished configuration in 80 ms.
get(disk-key-1) = disk-value-1
get(disk-key-2) = disk-value-2
get(disk-key-3) = disk-value-3
get(disk-key-4) = disk-value-4
get(disk-key-5) = disk-value-5
get(disk-key-6) = disk-value-6
get(disk-key-7) = disk-value-7
get(disk-key-8) = disk-value-8
get(disk-key-9) = disk-value-9
get(disk-key-10) = disk-value-10
get(disk-key-11) = disk-value-11
get(disk-key-12) = disk-value-12
get(disk-key-13) = disk-value-13
get(disk-key-14) = disk-value-14
get(disk-key-15) = disk-value-15
get(disk-key-16) = disk-value-16
get(disk-key-17) = disk-value-17
get(disk-key-18) = disk-value-18
get(disk-key-19) = disk-value-19
get(disk-key-20) = disk-value-20
命中条数: 20/20
Oct 14, 2026 10:27:37 AM org.apache.commons.jcs3.engine.control.CompositeCache
INFO: In DISPOSE, [diskRegion] fromRemote [false]
Oct 14, 2026 10:27:37 AM org.apache.commons.jcs3.engine.control.event.ElementEventQueue
INFO: Element event queue destroyed: org.apache.commons.jcs3.engine.control.event.ElementEventQueue@4e718207
Oct 14, 2026 10:27:37 AM org.apache.commons.jcs3.engine.control.CompositeCache
INFO: In DISPOSE, [diskRegion] auxiliary [diskRegion]
Oct 14, 2026 10:27:37 AM org.apache.commons.jcs3.engine.control.CompositeCache
INFO: In DISPOSE, [diskRegion] put 10 into auxiliary [diskRegion]
Oct 14, 2026 10:27:37 AM org.apache.commons.jcs3.auxiliary.disk.AbstractDiskCache
INFO: In dispose, destroying event queue.
Oct 14, 2026 10:27:37 AM org.apache.commons.jcs3.engine.PooledCacheEventQueue
INFO: Cache event queue destroyed: CacheEventQueue [listenerId=972261806, cacheName=diskRegion]
Oct 14, 2026 10:27:37 AM org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCache
INFO: Region [diskRegion] : Saving keys to: diskRegion, key count: 20
Oct 14, 2026 10:27:37 AM org.apache.commons.jcs3.engine.control.CompositeCache
INFO: In DISPOSE, [diskRegion] disposing of memory cache.
Oct 14, 2026 10:27:37 AM org.apache.commons.jcs3.engine.memory.AbstractMemoryCache
INFO: Memory Cache dispose called.
Oct 14, 2026 10:27:37 AM org.apache.commons.jcs3.auxiliary.disk.AbstractDiskCache
INFO: In dispose, destroying event queue.
Oct 14, 2026 10:27:37 AM org.apache.commons.jcs3.auxiliary.disk.indexed.IndexedDiskCache
SEVERE: Region [diskRegion] : Not alive and dispose was called, filename: diskRegion
done

验证点(持久化闭环成立):

  • 新进程启动即 Loaded keys from [diskRegion], key count: 20; up to 5,000 will be available.——上一进程保存的键索引被加载;
  • 一致性自检通过:Finished inital consistency check, isOk = true in 2ms.("inital" 为实测日志原文);
  • 20 条逐条读回全部正确,程序自报 命中条数: 20/20;
  • 读回进程 dispose 时 Saving keys to: diskRegion, key count: 20 再次落盘,闭环可重复。

七、集成到业务工程

把本文验证过的形态迁移到业务工程,只需保持三件事不变形。

  1. 依赖形态:业务 pom 加同一个依赖即可;依赖树证明运行时只有 core jar 一个文件(第三章回显),离线部署拷这一个 jar 就够。
  2. 配置形态:cache.ccf 必须出现在运行时 classpath。Maven 业务工程放 src/main/resources/(随包进 classpath);由启动脚本管理的部署形态用独立 conf/ 目录并加入 -cp(本文 5.4 命令形态)。两种放法等价,缺文件即 NPE(5.2 实测)。
  3. 启动参数形态:本文全部运行命令为 java -Dfile.encoding=UTF-8 -cp target/classes:conf:$(cat cp.txt) <主类>——生产上把 classpath 换成业务 fat jar/目录、按需追加 -Xms256m -Xmx512m 限定堆即可;-Dfile.encoding=UTF-8 在默认编码为 POSIX/ASCII 的服务器上必须保留。

生命周期约定(实测依据见第六章):业务代码持有 CacheAccess 期间正常读写;进程优雅退出前调用 dispose()(磁盘区域随后 JCS.shutdown()),保证 Saving keys 落盘时机;JCS 自带 Shutdown 钩子可兜底(Shutdown hook activated. Shutdown was not called. Shutting down JCS.,实测见《CentOS 8 安装 Apache Commons JCS 指南》4.6 节末行),但不应作为常规依赖。

八、注意事项

  1. 配置文件是硬前置:classpath 无 cache.ccf 时 3.2.1 启动即 NPE(5.2 实测),务必在首个集成环境先确认该文件可达。
  2. get 未命中返回 null:不是异常,业务代码必须判空(5.4 回显中 get(k4) = null)。
  3. 区域内存上限与磁盘模式的组合语义:UPDATE 模式下 put 即落盘、内存满后数据不丢(第六章 20 条全量读回);默认 SWAP 模式磁盘只承接内存换出条目,二者按场景选择(对比表见《Apache Commons JCS 3.2.1 配置参数详解》5.4 节)。
  4. 落盘时机:Saving keys 发生在 dispose 阶段,强杀进程会丢索引更新,优雅退出是持久化的前提(6.2 说明)。
  5. 编码:默认编码为 ANSI_X3.4-1968 的环境运行含中文输出的程序需 -Dfile.encoding=UTF-8(5.4 命令均带)。
  6. JUL 日志量大:JCS 默认走 JUL INFO 级别输出配置过程,生产可按 JUL 常规方式调整日志级别,配置加载日志(Parsed regions/Finished configuration)是排查配置是否生效的第一现场。

九、常见问题(FAQ)

Q1:启动抛 NullPointerException: inStream parameter is null?

classpath 上没有 cache.ccf(5.2 实测完整栈)。把配置放进 src/main/resources 或独立目录加入 -cp;判定标准:日志出现 Creating cache manager from config file: /cache.ccf 且不再抛异常。

Q2:重启后读不回磁盘缓存数据?

检查写入进程是否优雅关闭。实测(6.2/6.3):Saving keys to: diskRegion, key count: 20(索引落盘)→ 新进程 Loaded keys from [diskRegion], key count: 20(索引加载)→ 20/20 读回。任一环节缺失(如强杀进程、未 dispose)都会破坏闭环。

Q3:程序日志中文乱码?

加 -Dfile.encoding=UTF-8(5.4 命令形态),Maven 工程同时配 project.build.sourceEncoding=UTF-8。

Q4:dependency:get 下载了 junit、hsqldb 等组件,业务工程要带它们吗?

不需要。这些是 JCS POM 中非 compile 范围声明(第三章回显可见),dependency:tree 证明运行时 classpath 只有 core jar。

Q5:进程退出打出 Shutdown hook activated. Shutdown was not called. Shutting down JCS.?

未显式调用 JCS.shutdown() 时 JCS 的 Shutdown 钩子兜底关闭(实测见《CentOS 8 安装 Apache Commons JCS 指南》4.6 节末行)。磁盘区域建议仍显式 dispose() + JCS.shutdown(),保证可靠的落盘时机。

Q6:想读回 20 条但只命中一部分?

先看启动日志的 Loaded keys from [diskRegion], key count: N(N 为索引中的键数);再确认两次进程的 DiskPath 指向同一目录且键前缀一致(本文 disk-key-)。本文实测 20 条索引完整、20/20 命中(6.3),若 N < 写入条数,通常是写入进程未完成落盘即退出。

十、参考链接

  1. Apache Commons JCS 官方站点:https://commons.apache.org/proper/commons-jcs/
  2. Maven 中央仓库坐标页:https://repo1.maven.org/maven2/org/apache/commons/commons-jcs3-core/
  3. 官方发行下载目录:https://downloads.apache.org/commons/jcs/
  4. 本文配套:《Apache Commons JCS 3.2.1 配置参数详解》《Apache Commons JCS 3.2.1 常用 API 与工具详解》
  5. 源码仓库(GitHub 镜像):https://github.com/apache/commons-jcs