新增本地缓存基础设施

This commit is contained in:
wkc
2026-03-28 10:45:08 +08:00
parent ed77eaea84
commit bc2582246b
6 changed files with 224 additions and 1 deletions

View File

@@ -0,0 +1,9 @@
package com.ruoyi.common.core.cache;
record InMemoryCacheEntry(Object value, Long expireAtMillis)
{
boolean isExpired(long now)
{
return expireAtMillis != null && expireAtMillis <= now;
}
}

View File

@@ -0,0 +1,12 @@
package com.ruoyi.common.core.cache;
public record InMemoryCacheStats(
String cacheType,
String mode,
long keySize,
long hitCount,
long missCount,
long expiredCount,
long writeCount)
{
}

View File

@@ -0,0 +1,125 @@
package com.ruoyi.common.core.cache;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
public class InMemoryCacheStore
{
private final ConcurrentHashMap<String, InMemoryCacheEntry> entries = new ConcurrentHashMap<>();
private final AtomicLong hitCount = new AtomicLong();
private final AtomicLong missCount = new AtomicLong();
private final AtomicLong expiredCount = new AtomicLong();
private final AtomicLong writeCount = new AtomicLong();
public void set(String key, Object value)
{
putEntry(key, new InMemoryCacheEntry(value, null));
}
public void set(String key, Object value, long timeout, TimeUnit unit)
{
long expireAtMillis = System.currentTimeMillis() + unit.toMillis(timeout);
putEntry(key, new InMemoryCacheEntry(value, expireAtMillis));
}
public <T> T get(String key)
{
InMemoryCacheEntry entry = readEntry(key);
return entry == null ? null : (T) entry.value();
}
public boolean hasKey(String key)
{
return readEntry(key) != null;
}
public boolean delete(String key)
{
return entries.remove(key) != null;
}
public Set<String> keys(String pattern)
{
purgeExpiredEntries();
Set<String> matchedKeys = new TreeSet<>();
entries.forEach((key, value) -> {
if (matches(pattern, key))
{
matchedKeys.add(key);
}
});
return matchedKeys;
}
public InMemoryCacheStats snapshot()
{
purgeExpiredEntries();
return new InMemoryCacheStats(
"IN_MEMORY",
"single-instance",
entries.size(),
hitCount.get(),
missCount.get(),
expiredCount.get(),
writeCount.get());
}
private void putEntry(String key, InMemoryCacheEntry entry)
{
entries.put(key, entry);
writeCount.incrementAndGet();
}
private InMemoryCacheEntry readEntry(String key)
{
InMemoryCacheEntry entry = entries.get(key);
if (entry == null)
{
missCount.incrementAndGet();
return null;
}
if (entry.isExpired(System.currentTimeMillis()))
{
removeExpiredEntry(key, entry);
missCount.incrementAndGet();
return null;
}
hitCount.incrementAndGet();
return entry;
}
private void purgeExpiredEntries()
{
long now = System.currentTimeMillis();
entries.forEach((key, entry) -> {
if (entry.isExpired(now))
{
removeExpiredEntry(key, entry);
}
});
}
private void removeExpiredEntry(String key, InMemoryCacheEntry expectedEntry)
{
if (entries.remove(key, expectedEntry))
{
expiredCount.incrementAndGet();
}
}
private boolean matches(String pattern, String key)
{
if ("*".equals(pattern))
{
return true;
}
if (pattern.endsWith("*"))
{
return key.startsWith(pattern.substring(0, pattern.length() - 1));
}
return key.equals(pattern);
}
}