diff --git a/hutool-core/src/main/java/cn/hutool/v7/core/cache/CacheStats.java b/hutool-core/src/main/java/cn/hutool/v7/core/cache/CacheStats.java
new file mode 100644
index 0000000000000000000000000000000000000000..577115e7e99e3980c6288ea4f7cce53bae41be81
--- /dev/null
+++ b/hutool-core/src/main/java/cn/hutool/v7/core/cache/CacheStats.java
@@ -0,0 +1,214 @@
+package cn.hutool.v7.core.cache;
+
+import java.io.Serializable;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.LongAdder;
+
+/**
+ * 缓存统计信息
+ *
+ * @author Nic
+ */
+public class CacheStats implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ private final LongAdder hitCount;
+ private final LongAdder missCount;
+ private final LongAdder loadSuccessCount;
+ private final LongAdder loadFailureCount;
+ private final LongAdder evictionCount;
+ private final LongAdder totalLoadTime; // 纳秒
+ private final AtomicLong cacheSize;
+ private final long startTime;
+
+ /**
+ * 构建器模式
+ */
+ public static class Builder {
+ private final CacheStats stats;
+
+ public Builder() {
+ this.stats = new CacheStats();
+ }
+
+ public Builder hitCount(long hitCount) {
+ stats.hitCount.add(hitCount);
+ return this;
+ }
+
+ public Builder missCount(long missCount) {
+ stats.missCount.add(missCount);
+ return this;
+ }
+
+ public Builder loadSuccessCount(long loadSuccessCount) {
+ stats.loadSuccessCount.add(loadSuccessCount);
+ return this;
+ }
+
+ public Builder loadFailureCount(long loadFailureCount) {
+ stats.loadFailureCount.add(loadFailureCount);
+ return this;
+ }
+
+ public Builder evictionCount(long evictionCount) {
+ stats.evictionCount.add(evictionCount);
+ return this;
+ }
+
+ public Builder totalLoadTime(long totalLoadTime) {
+ stats.totalLoadTime.add(totalLoadTime);
+ return this;
+ }
+
+ public Builder cacheSize(long cacheSize) {
+ stats.cacheSize.set(cacheSize);
+ return this;
+ }
+
+ public CacheStats build() {
+ return stats;
+ }
+ }
+
+ public CacheStats() {
+ this.hitCount = new LongAdder();
+ this.missCount = new LongAdder();
+ this.loadSuccessCount = new LongAdder();
+ this.loadFailureCount = new LongAdder();
+ this.evictionCount = new LongAdder();
+ this.totalLoadTime = new LongAdder();
+ this.cacheSize = new AtomicLong(0);
+ this.startTime = System.currentTimeMillis();
+ }
+
+ // ========== 统计计算方法 ==========
+
+ /**
+ * 获取命中率
+ */
+ public double getHitRate() {
+ long requestCount = hitCount.longValue() + missCount.longValue();
+ return requestCount == 0 ? 1.0 : (double) hitCount.longValue() / requestCount;
+ }
+
+ /**
+ * 获取未命中率
+ */
+ public double getMissRate() {
+ long requestCount = hitCount.longValue() + missCount.longValue();
+ return requestCount == 0 ? 0.0 : (double) missCount.longValue() / requestCount;
+ }
+
+ /**
+ * 获取平均加载时间(毫秒)
+ */
+ public double getAverageLoadTime() {
+ long total = totalLoadTime.longValue();
+ long success = loadSuccessCount.longValue();
+ return success == 0 ? 0.0 : (total / 1_000_000.0) / success;
+ }
+
+ /**
+ * 获取加载失败率
+ */
+ public double getLoadFailureRate() {
+ long totalLoads = loadSuccessCount.longValue() + loadFailureCount.longValue();
+ return totalLoads == 0 ? 0.0 : (double) loadFailureCount.longValue() / totalLoads;
+ }
+
+ /**
+ * 获取缓存运行时间(秒)
+ */
+ public long getRuntimeSeconds() {
+ return (System.currentTimeMillis() - startTime) / 1000;
+ }
+
+ // ========== Getter方法 ==========
+
+ public long getHitCount() {
+ return hitCount.longValue();
+ }
+
+ public long getMissCount() {
+ return missCount.longValue();
+ }
+
+ public long getLoadSuccessCount() {
+ return loadSuccessCount.longValue();
+ }
+
+ public long getLoadFailureCount() {
+ return loadFailureCount.longValue();
+ }
+
+ public long getEvictionCount() {
+ return evictionCount.longValue();
+ }
+
+ public long getTotalLoadTime() {
+ return totalLoadTime.longValue();
+ }
+
+ public long getCacheSize() {
+ return cacheSize.get();
+ }
+
+ public long getStartTime() {
+ return startTime;
+ }
+
+ /**
+ * 记录一次命中
+ */
+ public void recordHit() {
+ hitCount.increment();
+ }
+
+ /**
+ * 记录一次未命中
+ */
+ public void recordMiss() {
+ missCount.increment();
+ }
+
+ /**
+ * 记录一次成功的加载
+ */
+ public void recordLoadSuccess(long loadTime) {
+ loadSuccessCount.increment();
+ totalLoadTime.add(loadTime);
+ }
+
+ /**
+ * 记录一次失败的加载
+ */
+ public void recordLoadFailure() {
+ loadFailureCount.increment();
+ }
+
+ /**
+ * 记录一次驱逐
+ */
+ public void recordEviction() {
+ evictionCount.increment();
+ }
+
+ /**
+ * 更新缓存大小
+ */
+ public void setCacheSize(long size) {
+ cacheSize.set(size);
+ }
+
+ @Override
+ public String toString() {
+ return String.format(
+ "CacheStats{hitRate=%.2f%%, hits=%d, misses=%d, loadSuccess=%d, loadFailure=%d, " +
+ "evictions=%d, avgLoadTime=%.2fms, size=%d, runtime=%ds}",
+ getHitRate() * 100, getHitCount(), getMissCount(), getLoadSuccessCount(),
+ getLoadFailureCount(), getEvictionCount(), getAverageLoadTime(),
+ getCacheSize(), getRuntimeSeconds()
+ );
+ }
+}
diff --git a/hutool-core/src/main/java/cn/hutool/v7/core/cache/SmartCache.java b/hutool-core/src/main/java/cn/hutool/v7/core/cache/SmartCache.java
new file mode 100644
index 0000000000000000000000000000000000000000..2f11dc8057820ed4f8058bb5aef501ee7e43f431
--- /dev/null
+++ b/hutool-core/src/main/java/cn/hutool/v7/core/cache/SmartCache.java
@@ -0,0 +1,91 @@
+package cn.hutool.v7.core.cache;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Function;
+
+/**
+ * 智能缓存接口 - 扩展Hutool标准缓存功能
+ *
+ *
提供多级缓存、异步刷新、缓存预热等高级功能
+ *
+ * @author Nic
+ */
+public interface SmartCache extends Cache {
+
+ /**
+ * 批量获取缓存项
+ *
+ * @param keys 键集合
+ * @return 键值对映射
+ */
+ Map getAll(Collection keys);
+
+ /**
+ * 批量放入缓存项
+ *
+ * @param map 键值对映射
+ */
+ void putAll(Map extends K, ? extends V> map);
+
+ /**
+ * 异步刷新缓存项
+ *
+ * @param key 缓存键
+ * @return CompletableFuture包装的缓存值
+ */
+ CompletableFuture refreshAsync(K key);
+
+ /**
+ * 缓存预热
+ *
+ * @param keys 需要预热的键集合
+ * @return 预热成功的数量
+ */
+ int warmUp(Collection keys);
+
+ /**
+ * 原子操作:如果不存在则计算并放入
+ *
+ * @param key 缓存键
+ * @param mappingFunction 映射函数
+ * @return 缓存值
+ */
+ V computeIfAbsent(K key, Function mappingFunction);
+
+ /**
+ * 原子操作:如果存在则重新计算
+ *
+ * @param key 缓存键
+ * @param remappingFunction 重新映射函数
+ * @return 新的缓存值
+ */
+ V computeIfPresent(K key, Function remappingFunction);
+
+ /**
+ * 获取缓存统计信息
+ *
+ * @return 缓存统计
+ */
+ CacheStats getStats();
+
+ /**
+ * 清除所有统计信息
+ */
+ void clearStats();
+
+ /**
+ * 获取缓存名称
+ *
+ * @return 缓存名称
+ */
+ String getName();
+
+ /**
+ * 设置缓存名称
+ *
+ * @param name 缓存名称
+ */
+ void setName(String name);
+}
diff --git a/hutool-core/src/main/java/cn/hutool/v7/core/cache/SmartCacheBuilder.java b/hutool-core/src/main/java/cn/hutool/v7/core/cache/SmartCacheBuilder.java
new file mode 100644
index 0000000000000000000000000000000000000000..9313dbcdaec2707e564bae9ed0705c5bcef7b39e
--- /dev/null
+++ b/hutool-core/src/main/java/cn/hutool/v7/core/cache/SmartCacheBuilder.java
@@ -0,0 +1,122 @@
+package cn.hutool.v7.core.cache;
+
+import cn.hutool.v7.core.cache.impl.SmartCacheImpl;
+import cn.hutool.v7.core.text.StrUtil;
+
+import java.time.Duration;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.function.Function;
+
+/**
+ * 智能缓存构建器
+ *
+ * @author Nic
+ */
+public class SmartCacheBuilder {
+
+ // 必需参数
+ private final Cache cache;
+
+ // 可选参数
+ private String name = "SmartCache";
+ private boolean enableStats = true;
+ private boolean enableAsyncRefresh = false;
+ private int warmUpBatchSize = 100;
+ private Duration refreshTimeout = Duration.ofSeconds(30);
+ private ExecutorService refreshExecutor;
+ private Function cacheLoader;
+
+ /**
+ * 私有构造器
+ */
+ private SmartCacheBuilder(Cache cache) {
+ this.cache = cache;
+ }
+
+ /**
+ * 创建构建器
+ */
+ public static SmartCacheBuilder of(Cache cache) {
+ return new SmartCacheBuilder<>(cache);
+ }
+
+ /**
+ * 设置缓存名称
+ */
+ public SmartCacheBuilder name(String name) {
+ this.name = StrUtil.defaultIfBlank(name, "SmartCache");
+ return this;
+ }
+
+ /**
+ * 启用统计
+ */
+ public SmartCacheBuilder enableStats(boolean enableStats) {
+ this.enableStats = enableStats;
+ return this;
+ }
+
+ /**
+ * 启用异步刷新
+ */
+ public SmartCacheBuilder enableAsyncRefresh(boolean enableAsyncRefresh) {
+ this.enableAsyncRefresh = enableAsyncRefresh;
+ return this;
+ }
+
+ /**
+ * 设置预热批次大小
+ */
+ public SmartCacheBuilder warmUpBatchSize(int warmUpBatchSize) {
+ this.warmUpBatchSize = Math.max(1, warmUpBatchSize);
+ return this;
+ }
+
+ /**
+ * 设置刷新超时时间
+ */
+ public SmartCacheBuilder refreshTimeout(Duration refreshTimeout) {
+ this.refreshTimeout = refreshTimeout;
+ return this;
+ }
+
+ /**
+ * 设置刷新线程池
+ */
+ public SmartCacheBuilder refreshExecutor(ExecutorService refreshExecutor) {
+ this.refreshExecutor = refreshExecutor;
+ return this;
+ }
+
+ /**
+ * 设置缓存加载器
+ */
+ public SmartCacheBuilder cacheLoader(Function cacheLoader) {
+ this.cacheLoader = cacheLoader;
+ return this;
+ }
+
+ /**
+ * 构建智能缓存
+ */
+ public SmartCache build() {
+ // 确保有刷新线程池(如果需要异步刷新)
+ if (enableAsyncRefresh && refreshExecutor == null) {
+ refreshExecutor = Executors.newFixedThreadPool(
+ Math.max(2, Runtime.getRuntime().availableProcessors() / 2)
+ );
+ }
+
+ return new SmartCacheImpl<>(
+ cache,
+ name,
+ enableStats,
+ enableAsyncRefresh,
+ warmUpBatchSize,
+ refreshTimeout,
+ refreshExecutor,
+ cacheLoader
+ );
+ }
+}
diff --git a/hutool-core/src/main/java/cn/hutool/v7/core/cache/SmartCacheUtil.java b/hutool-core/src/main/java/cn/hutool/v7/core/cache/SmartCacheUtil.java
new file mode 100644
index 0000000000000000000000000000000000000000..f4e439ff3e8c7aea70f6b06cf70709cbc7c310cf
--- /dev/null
+++ b/hutool-core/src/main/java/cn/hutool/v7/core/cache/SmartCacheUtil.java
@@ -0,0 +1,116 @@
+package cn.hutool.v7.core.cache;
+
+import cn.hutool.v7.core.cache.impl.LRUCache;
+
+/**
+ * 智能缓存工具类
+ *
+ * @author Nic
+ */
+public class SmartCacheUtil {
+
+ private SmartCacheUtil() {
+ // 工具类,禁止实例化
+ }
+
+ /**
+ * 创建LRU智能缓存
+ */
+ public static SmartCache newLRUSmartCache(int capacity) {
+ return (SmartCache) SmartCacheBuilder.of(CacheUtil.newLRUCache(capacity))
+ .name("LRU-SmartCache")
+ .build();
+ }
+
+ /**
+ * 创建LFU智能缓存
+ */
+ public static SmartCache newLFUSmartCache(int capacity) {
+ return (SmartCache) SmartCacheBuilder.of(CacheUtil.newLFUCache(capacity))
+ .name("LFU-SmartCache")
+ .build();
+ }
+
+ /**
+ * 创建FIFO智能缓存
+ */
+ public static SmartCache newFIFOSmartCache(int capacity) {
+ return (SmartCache) SmartCacheBuilder.of(CacheUtil.newFIFOCache(capacity))
+ .name("FIFO-SmartCache")
+ .build();
+ }
+
+ /**
+ * 创建带加载器的智能缓存
+ */
+ public static SmartCache newSmartCache(
+ Cache cache,
+ java.util.function.Function loader) {
+
+ return SmartCacheBuilder.of(cache)
+ .cacheLoader(loader)
+ .enableAsyncRefresh(true)
+ .enableStats(true)
+ .build();
+ }
+
+ /**
+ * 创建定时过期的智能缓存
+ */
+ public static SmartCache newTimedSmartCache(
+ int capacity,
+ long timeout,
+ java.util.function.Function loader) {
+
+ Cache cache = new LRUCache<>(capacity, timeout) {
+ @Override
+ public boolean isFull() {
+ return this.cacheMap.size() >= capacity;
+ }
+ };
+
+ return SmartCacheBuilder.of(cache)
+ .name("Timed-SmartCache")
+ .cacheLoader(loader)
+ .enableStats(true)
+ .build();
+ }
+
+ /**
+ * 获取缓存的详细统计信息
+ */
+ public static String getDetailedStats(SmartCache, ?> cache) {
+ if (cache == null) {
+ return "Cache is null";
+ }
+
+ try {
+ CacheStats stats = cache.getStats();
+ return String.format(
+ "Cache: %s\n" +
+ " Size: %d / %d\n" +
+ " Hit Rate: %.2f%%\n" +
+ " Hits: %d\n" +
+ " Misses: %d\n" +
+ " Load Success: %d\n" +
+ " Load Failure: %d\n" +
+ " Avg Load Time: %.2fms\n" +
+ " Evictions: %d\n" +
+ " Runtime: %ds",
+ cache.getName(),
+ cache.size(),
+ cache.capacity(),
+ stats.getHitRate() * 100,
+ stats.getHitCount(),
+ stats.getMissCount(),
+ stats.getLoadSuccessCount(),
+ stats.getLoadFailureCount(),
+ stats.getAverageLoadTime(),
+ stats.getEvictionCount(),
+ stats.getRuntimeSeconds()
+ );
+ } catch (Exception e) {
+ return "Unable to get stats: " + e.getMessage();
+ }
+ }
+}
diff --git a/hutool-core/src/main/java/cn/hutool/v7/core/cache/impl/SmartCacheImpl.java b/hutool-core/src/main/java/cn/hutool/v7/core/cache/impl/SmartCacheImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..162de67573fa1dbffc6ac3d2030769b855348edf
--- /dev/null
+++ b/hutool-core/src/main/java/cn/hutool/v7/core/cache/impl/SmartCacheImpl.java
@@ -0,0 +1,573 @@
+package cn.hutool.v7.core.cache.impl;
+
+import cn.hutool.v7.core.cache.Cache;
+import cn.hutool.v7.core.cache.CacheStats;
+import cn.hutool.v7.core.cache.SmartCache;
+import cn.hutool.v7.core.collection.CollUtil;
+import cn.hutool.v7.core.collection.iter.CopiedIter;
+import cn.hutool.v7.core.collection.partition.Partition;
+import cn.hutool.v7.core.func.SerSupplier;
+import cn.hutool.v7.core.map.MapUtil;
+import cn.hutool.v7.core.text.StrUtil;
+import java.time.Duration;
+import java.util.*;
+import java.util.concurrent.*;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.function.Function;
+
+/**
+ * 智能缓存实现
+ *
+ * @author Nic
+ */
+public class SmartCacheImpl implements SmartCache {
+
+ // 底层缓存
+ private final Cache delegate;
+
+ // 配置参数
+ private String name;
+ private final boolean enableStats;
+ private final boolean enableAsyncRefresh;
+ private final int warmUpBatchSize;
+ private final Duration refreshTimeout;
+ private final ExecutorService refreshExecutor;
+ private final Function cacheLoader;
+
+ // 统计信息
+ private final CacheStats stats;
+
+ // 锁机制
+ private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
+ private final Map> pendingRefreshes = new ConcurrentHashMap<>();
+
+ /**
+ * 构造器
+ */
+ public SmartCacheImpl(
+ Cache delegate,
+ String name,
+ boolean enableStats,
+ boolean enableAsyncRefresh,
+ int warmUpBatchSize,
+ Duration refreshTimeout,
+ ExecutorService refreshExecutor,
+ Function cacheLoader) {
+
+ this.delegate = delegate;
+ this.name = name;
+ this.enableStats = enableStats;
+ this.enableAsyncRefresh = enableAsyncRefresh;
+ this.warmUpBatchSize = Math.max(1, warmUpBatchSize);
+ this.refreshTimeout = refreshTimeout != null ? refreshTimeout : Duration.ofSeconds(30);
+ this.refreshExecutor = refreshExecutor;
+ this.cacheLoader = cacheLoader;
+ this.stats = enableStats ? new CacheStats() : null;
+ }
+
+ // ========== 实现Cache接口方法 ==========
+
+ @Override
+ public void put(K key, V object, long timeout) {
+ lock.writeLock().lock();
+ try {
+ delegate.put(key, object, timeout);
+ if (enableStats) {
+ stats.setCacheSize(delegate.size());
+ }
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
+
+ @Override
+ public void put(K key, V object) {
+ put(key, object, 0);
+ }
+
+ @Override
+ public V get(K key, boolean isUpdateLastAccess) {
+ lock.readLock().lock();
+ try {
+ V value = delegate.get(key, isUpdateLastAccess);
+
+ if (enableStats) {
+ if (value != null) {
+ stats.recordHit();
+ } else {
+ stats.recordMiss();
+
+ // 如果有缓存加载器,尝试加载
+ if (cacheLoader != null) {
+ long startTime = System.nanoTime();
+ try {
+ value = cacheLoader.apply(key);
+ if (value != null) {
+ delegate.put(key, value);
+ stats.recordLoadSuccess(System.nanoTime() - startTime);
+ }
+ } catch (Exception e) {
+ stats.recordLoadFailure();
+ throw new CacheException("Failed to load cache value for key: " + key, e);
+ }
+ }
+ }
+ }
+
+ return value;
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ @Override
+ public V get(K key) {
+ return get(key, false);
+ }
+
+ @Override
+ public Iterator iterator() {
+ return delegate.iterator();
+ }
+
+ @Override
+ public int prune() {
+ lock.writeLock().lock();
+ try {
+ int pruned = delegate.prune();
+ if (enableStats && pruned > 0) {
+ for (int i = 0; i < pruned; i++) {
+ stats.recordEviction();
+ }
+ stats.setCacheSize(delegate.size());
+ }
+ return pruned;
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
+
+ @Override
+ public boolean isFull() {
+ lock.readLock().lock();
+ try {
+ return delegate.isFull();
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ @Override
+ public void remove(K key) {
+ lock.writeLock().lock();
+ try {
+ delegate.remove(key);
+ if (enableStats) {
+ stats.setCacheSize(delegate.size());
+ }
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
+
+ @Override
+ public void clear() {
+ lock.writeLock().lock();
+ try {
+ delegate.clear();
+ if (enableStats) {
+ stats.setCacheSize(0);
+ }
+ pendingRefreshes.clear();
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
+
+ @Override
+ public int capacity() {
+ lock.readLock().lock();
+ try {
+ return delegate.capacity();
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ @Override
+ public long timeout() {
+ lock.readLock().lock();
+ try {
+ return delegate.timeout();
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ @Override
+ public boolean isEmpty() {
+ lock.readLock().lock();
+ try {
+ return delegate.isEmpty();
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ @Override
+ public int size() {
+ lock.readLock().lock();
+ try {
+ return delegate.size();
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ @Override
+ public boolean containsKey(K key) {
+ lock.readLock().lock();
+ try {
+ return delegate.containsKey(key);
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ // ========== 实现SmartCache接口方法 ==========
+
+ @Override
+ public Map getAll(Collection keys) {
+ if (CollUtil.isEmpty(keys)) {
+ return Collections.emptyMap();
+ }
+
+ lock.readLock().lock();
+ try {
+ Map result = new HashMap<>(keys.size());
+
+ for (K key : keys) {
+ V value = get(key);
+ if (value != null) {
+ result.put(key, value);
+ }
+ }
+
+ return result;
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ @Override
+ public void putAll(Map extends K, ? extends V> map) {
+ if (MapUtil.isEmpty(map)) {
+ return;
+ }
+
+ lock.writeLock().lock();
+ try {
+ for (Map.Entry extends K, ? extends V> entry : map.entrySet()) {
+ delegate.put(entry.getKey(), entry.getValue());
+ }
+
+ if (enableStats) {
+ stats.setCacheSize(delegate.size());
+ }
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
+
+ @Override
+ public CompletableFuture refreshAsync(K key) {
+ if (!enableAsyncRefresh) {
+ throw new UnsupportedOperationException("Async refresh is not enabled");
+ }
+
+ if (cacheLoader == null) {
+ throw new IllegalStateException("Cache loader is required for async refresh");
+ }
+
+ // 检查是否已经有正在进行的刷新
+ CompletableFuture pending = pendingRefreshes.get(key);
+ if (pending != null) {
+ return pending;
+ }
+
+ CompletableFuture future = CompletableFuture.supplyAsync(() -> {
+ try {
+ long startTime = System.nanoTime();
+ V newValue = cacheLoader.apply(key);
+
+ if (newValue != null) {
+ lock.writeLock().lock();
+ try {
+ delegate.put(key, newValue);
+ if (enableStats) {
+ stats.recordLoadSuccess(System.nanoTime() - startTime);
+ }
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
+
+ return newValue;
+ } catch (Exception e) {
+ if (enableStats) {
+ stats.recordLoadFailure();
+ }
+ throw new CompletionException(e);
+ } finally {
+ pendingRefreshes.remove(key);
+ }
+ }, refreshExecutor);
+
+ // 设置超时
+ future = future.orTimeout(refreshTimeout.toMillis(), TimeUnit.MILLISECONDS)
+ .exceptionally(ex -> {
+ pendingRefreshes.remove(key);
+ return null;
+ });
+
+ pendingRefreshes.put(key, future);
+ return future;
+ }
+
+ @Override
+ public int warmUp(Collection keys) {
+ if (cacheLoader == null || CollUtil.isEmpty(keys)) {
+ return 0;
+ }
+
+ int warmedUp = 0;
+ Collection> batches = new Partition<>(new ArrayList<>(keys), warmUpBatchSize);
+
+ for (List batch : batches) {
+ lock.writeLock().lock();
+ try {
+ for (K key : batch) {
+ if (!delegate.containsKey(key)) {
+ try {
+ V value = cacheLoader.apply(key);
+ if (value != null) {
+ delegate.put(key, value);
+ warmedUp++;
+ }
+ } catch (Exception e) {
+ // 忽略单个键的加载失败,继续处理其他键
+ }
+ }
+ }
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
+
+ if (enableStats) {
+ stats.setCacheSize(delegate.size());
+ }
+
+ return warmedUp;
+ }
+
+ @Override
+ public V computeIfAbsent(K key, Function mappingFunction) {
+ lock.writeLock().lock();
+ try {
+ V value = delegate.get(key);
+ if (value == null && mappingFunction != null) {
+ long startTime = System.nanoTime();
+ try {
+ value = mappingFunction.apply(key);
+ if (value != null) {
+ delegate.put(key, value);
+
+ if (enableStats) {
+ stats.recordLoadSuccess(System.nanoTime() - startTime);
+ stats.setCacheSize(delegate.size());
+ }
+ }
+ } catch (Exception e) {
+ if (enableStats) {
+ stats.recordLoadFailure();
+ }
+ throw new CacheException("Failed to compute value for key: " + key, e);
+ }
+ }
+
+ return value;
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
+
+ @Override
+ public V computeIfPresent(K key, Function remappingFunction) {
+ lock.writeLock().lock();
+ try {
+ if (delegate.containsKey(key) && remappingFunction != null) {
+ long startTime = System.nanoTime();
+ try {
+ V newValue = remappingFunction.apply(key);
+ if (newValue != null) {
+ delegate.put(key, newValue);
+
+ if (enableStats) {
+ stats.recordLoadSuccess(System.nanoTime() - startTime);
+ }
+ }
+ return newValue;
+ } catch (Exception e) {
+ if (enableStats) {
+ stats.recordLoadFailure();
+ }
+ throw new CacheException("Failed to compute value for key: " + key, e);
+ }
+ }
+ return null;
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
+
+ @Override
+ public CacheStats getStats() {
+ if (!enableStats) {
+ throw new UnsupportedOperationException("Statistics are not enabled");
+ }
+
+ lock.readLock().lock();
+ try {
+ stats.setCacheSize(delegate.size());
+ return stats;
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
+ @Override
+ public void clearStats() {
+ if (!enableStats) {
+ throw new UnsupportedOperationException("Statistics are not enabled");
+ }
+
+ lock.writeLock().lock();
+ try {
+ // 创建新的统计实例,保留缓存大小
+ long currentSize = stats.getCacheSize();
+ stats.setCacheSize(currentSize);
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
+
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ @Override
+ public void setName(String name) {
+ this.name = StrUtil.defaultIfBlank(name, "SmartCache");
+ }
+
+ /**
+ * 获取底层缓存
+ */
+ public Cache getDelegate() {
+ return delegate;
+ }
+
+ @Override
+ public V get(K key, boolean isUpdateLastAccess, long timeout, SerSupplier valueFactory) {
+ if (key == null) {
+ throw new NullPointerException("Key must not be null");
+ }
+
+ lock.readLock().lock();
+ V value = null;
+ try {
+ // 1. 优先尝试从底层缓存获取
+ value = delegate.get(key, isUpdateLastAccess);
+ } finally {
+ lock.readLock().unlock();
+ }
+
+ // 2. 如果缓存未命中,则使用工厂方法创建、缓存并返回新值
+ if (value == null && valueFactory != null) {
+ lock.writeLock().lock();
+ try {
+ // 双重检查锁定模式,防止在获取写锁期间,其他线程已经创建并插入了值
+ value = delegate.get(key, isUpdateLastAccess);
+ if (value == null) {
+ // 记录加载开始时间,用于统计
+ long loadStartTime = System.nanoTime();
+ try {
+ // 调用工厂方法创建新值
+ value = valueFactory.get();
+ // 如果工厂成功创建了值,则将其放入缓存
+ if (value != null) {
+ if (timeout > 0) {
+ // 使用传入的自定义超时时间
+ delegate.put(key, value, timeout);
+ } else {
+ // 使用缓存的默认超时策略
+ delegate.put(key, value);
+ }
+
+ // 记录加载成功(如果开启了统计)
+ if (enableStats) {
+ stats.recordLoadSuccess(System.nanoTime() - loadStartTime);
+ }
+ } else {
+ // 工厂方法返回了null,记录加载失败(可选逻辑)
+ if (enableStats) {
+ stats.recordLoadFailure();
+ }
+ // 注意:此时并未将null值存入缓存,下次请求仍会触发加载
+ }
+ } catch (Exception e) {
+ if (enableStats) {
+ stats.recordLoadFailure();
+ }
+ // 可以根据需要决定是抛出异常,还是返回null。
+ // 为了保持接口的健壮性,这里将异常包装后抛出。
+ throw new CacheException("Failed to load value for key: " + key, e);
+ }
+ }
+ // 无论新值是否由当前线程创建,写锁块结束时,value变量中已经有了最终结果。
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
+ // 返回最终结果
+ return value;
+ }
+
+
+ @Override
+ public Iterator> cacheObjIterator() {
+ CopiedIter> copiedIterator;
+ lock.readLock().lock();
+ try {
+ copiedIterator = CopiedIter.copyOf(this.delegate.cacheObjIterator());
+ } finally {
+ lock.readLock().unlock();
+ }
+ return new CacheObjIterator<>(copiedIterator);
+ }
+
+ /**
+ * 自定义缓存异常
+ */
+ public static class CacheException extends RuntimeException {
+ public CacheException(String message) {
+ super(message);
+ }
+
+ public CacheException(String message, Throwable cause) {
+ super(message, cause);
+ }
+ }
+}
diff --git a/hutool-core/src/test/java/cn/hutool/v7/core/cache/SmartCacheBasicTest.java b/hutool-core/src/test/java/cn/hutool/v7/core/cache/SmartCacheBasicTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..8ce7abf4320581023bbe5325e41abe7fde528547
--- /dev/null
+++ b/hutool-core/src/test/java/cn/hutool/v7/core/cache/SmartCacheBasicTest.java
@@ -0,0 +1,153 @@
+package cn.hutool.v7.core.cache;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.DisplayName;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * 智能缓存基础功能测试
+ */
+@DisplayName("智能缓存基础功能测试")
+public class SmartCacheBasicTest {
+
+ private SmartCache