diff --git a/wgx_jvm_cache/.gitignore b/wgx_jvm_cache/.gitignore new file mode 100644 index 0000000..5ff6309 --- /dev/null +++ b/wgx_jvm_cache/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/wgx_jvm_cache/README.md b/wgx_jvm_cache/README.md new file mode 100644 index 0000000..c12fe85 --- /dev/null +++ b/wgx_jvm_cache/README.md @@ -0,0 +1,282 @@ +# JvmCache - JVM内存缓存依赖库 + +## 概述 +`JvmCache` 是一个基于Caffeine实现的JVM内存缓存工具,用于高效地管理和操作内存中的缓存数据。 + +## 应用配置参数 + +JvmCache 提供了两个可配置的参数,用于调整缓存的性能和容量。这些参数可以通过环境变量或配置文件进行设置。 + +1. `initialCapacity` + - 描述:初始的缓存空间大小 + - 单位:MB + - 默认值: + - 开发环境:10 + - 生产环境:10 + - 配置示例:`initialCapacity=20` + +2. `maximumSize` + - 描述:缓存的最大条目数 + - 单位:条目数量 + - 默认值: + - 开发环境:10,000 + - 生产环境:10,000 + - 配置示例:`maximumSize=20000` + +## 主要方法 + +### getAllKeys() + +获取缓存中所有的键。 + +| 参数名 | 类型 | 描述 | 是否必填 | +|------|------|------|--------| +| 无 | 无 | 无 | 无 | + +**返回值**:List< String> +- 包含所有缓存键的列表。如果缓存为空或未初始化,返回空列表。 + +**异常处理**: +- 如果缓存未初始化,抛出CacheException。 + +### getAllCache() + +获取缓存中的所有键值对。 + +| 参数名 | 类型 | 描述 | 是否必填 | +|------|------|------|--------| +| 无 | 无 | 无 | 无 | + +**返回值**:Map +- 包含所有缓存的键值对。如果缓存为空或未初始化,返回空Map。 + +**异常处理**: +- 如果缓存未初始化,抛出CacheException。 +- 其他异常会被捕获并记录,返回空Map。 + +### exist(String key) + +检查指定的键是否存在于缓存中。 + +| 参数名 | 类型 | 描述 | 是否必填 | +|-------|-------|------------|--------| +| key | String | 要检查的缓存键 | 是 | + +**返回值**:Boolean +- true:如果键存在 +- false:如果键不存在或为空 + +**异常处理**: +- 如果缓存未初始化,抛出CacheException。 + +### existHash(String key, String hashField) + +检查指定的哈希键是否存在于缓存中。 + +| 参数名 | 类型 | 描述 | 是否必填 | +|-----------|-------|--------|--------| +| key | String | 主键 | 是 | +| hashField | String | 哈希字段 | 是 | + +**返回值**:Boolean +- true:如果哈希键存在 +- false:如果哈希键不存在或参数无效 + +**异常处理**: +- 如果缓存未初始化,抛出CacheException。 + +### setCache(String key, String value) + +设置缓存键值对。 + +| 参数名 | 类型 | 描述 | 是否必填 | +|-------|-------|-------|--------| +| key | String | 缓存键 | 是 | +| value | String | 缓存值 | 是 | + +**返回值**:Boolean +- true:设置成功 +- false:设置失败(key为空) + +**异常处理**: +- 如果缓存未初始化或设置过程中发生异常,抛出CacheException。 + +### setCacheWithExpire(String key, String value, Long expire) + +设置带过期时间的缓存键值对。 + +| 参数名 | 类型 | 描述 | 是否必填 | +|--------|-------|--------------|--------| +| key | String | 缓存键 | 是 | +| value | String | 缓存值 | 是 | +| expire | Long | 过期时间(毫秒) | 是 | + +**返回值**:Boolean +- true:设置成功 +- false:设置失败(参数无效) + +**异常处理**: +- 如果缓存未初始化或设置过程中发生异常,抛出CacheException。 + +### setHashCache(String key, String hashField, String value) + +设置哈希缓存。 + +| 参数名 | 类型 | 描述 | 是否必填 | +|-----------|-------|--------|--------| +| key | String | 主键 | 是 | +| hashField | String | 哈希字段 | 是 | +| value | String | 缓存值 | 是 | + +**返回值**:Boolean +- true:设置成功 +- false:设置失败(参数无效) + +**异常处理**: +- 如果缓存未初始化或设置过程中发生异常,抛出CacheException。 + +### getCache(String key) + +获取指定键的缓存值。 + +| 参数名 | 类型 | 描述 | 是否必填 | +|-------|-------|-------|--------| +| key | String | 缓存键 | 是 | + +**返回值**:String +- 对应的缓存值,如果不存在或已过期返回null。 + +**异常处理**: +- 如果缓存未初始化或获取过程中发生异常,抛出CacheException。 + +### getHashCache(String key, String hashField) + +获取指定哈希键的缓存值。 + +| 参数名 | 类型 | 描述 | 是否必填 | +|-----------|-------|--------|--------| +| key | String | 主键 | 是 | +| hashField | String | 哈希字段 | 是 | + +**返回值**:String +- 对应的哈希缓存值,如果不存在或已过期返回null。 + +**异常处理**: +- 如果缓存未初始化或获取过程中发生异常,抛出CacheException。 + +### getMultiCache(List keys) + +批量获取多个键的缓存值。 + +| 参数名 | 类型 | 描述 | 是否必填 | +|-------|---------------|----------------|--------| +| keys | List | 要获取的键的列表 | 是 | + +**返回值**:Map +- 包含存在的键值对。 + +**异常处理**: +- 如果缓存未初始化或批量获取过程中发生异常,抛出CacheException。 + +### deleteCache(String key) + +删除指定的缓存键值对。 + +| 参数名 | 类型 | 描述 | 是否必填 | +|-------|-------|------------|--------| +| key | String | 要删除的缓存键 | 是 | + +**返回值**:Boolean +- true:删除成功 +- false:删除失败(key为空或删除过程中发生异常) + +**异常处理**: +- 如果缓存未初始化,抛出CacheException。 + +### deleteHashCache(String key, String hashField) + +删除指定的哈希缓存。 + +| 参数名 | 类型 | 描述 | 是否必填 | +|-----------|-------|--------|--------| +| key | String | 主键 | 是 | +| hashField | String | 哈希字段 | 是 | + +**返回值**:Boolean +- true:删除成功 +- false:删除失败(参数无效或删除过程中发生异常) + +**异常处理**: +- 如果缓存未初始化,抛出CacheException。 + +### clearAllCache() + +清空所有缓存。 + +| 参数名 | 类型 | 描述 | 是否必填 | +|------|------|------|--------| +| 无 | 无 | 无 | 无 | + +**返回值**:Boolean +- true:清空成功 +- false:清空失败(清空过程中发生异常) + +**异常处理**: +- 如果缓存未初始化,抛出CacheException。 + +### getEstimatedSize() + +获取缓存的估计大小。 + +| 参数名 | 类型 | 描述 | 是否必填 | +|------|------|------|--------| +| 无 | 无 | 无 | 无 | + +**返回值**:Long +- 缓存中的估计条目数。 + +**异常处理**: +- 如果缓存未初始化,抛出CacheException。 + +### getOrComputeAndSet(String key, Long expireAfterWriteMillis, Function computeFunction) + +获取缓存,如果缓存不存在则执行指定的计算函数,并将计算结果存入缓存。 + +| 参数名 | 类型 | 描述 | 是否必填 | +|------------------------|----------------------------|------------------------------|--------| +| key | String | 缓存键 | 是 | +| expireAfterWriteMillis | Long | 写入后的过期时间(毫秒) | 是 | +| computeFunction | Function | 如果缓存不存在时,用于计算值的函数 | 是 | + +**返回值**:String +- 缓存中的值或计算后的新值。如果计算结果为null,则返回null且不会更新缓存。 + +**异常处理**: +- 如果缓存未初始化或操作过程中发生异常,抛出CacheException。 + +## 使用示例 + + +## 使用步骤说明 + +1. 在您的项目中引入 JvmCache 依赖库。 +2. 在需要使用缓存的地方,调用相应的方法。 +3. 检查返回的值以确定操作是否成功。 +4. 根据需要处理可能的异常情况。 + +## 使用示例 + +1. 下载依赖库后,应用引用依赖库 + ![](image/img.png) +2. 在需要使用缓存操作的地方,调用相应的方法。 + ![](image/img_2.png) + ![](image/img_1.png) +3. 点击按钮调用setCache方法,设置缓存 + ![](image/img_3.png) +4. 调用结果: + ![](image/img_4.png) +5. 点击按钮调用getCache方法,获取缓存值 + ![](image/img_5.png) + +## 应用演示链接 +https://dev-testapp-jvmcache.app.codewave.163.com/jvmCacheTest \ No newline at end of file diff --git a/wgx_jvm_cache/image/img.png b/wgx_jvm_cache/image/img.png new file mode 100644 index 0000000..cb0a335 Binary files /dev/null and b/wgx_jvm_cache/image/img.png differ diff --git a/wgx_jvm_cache/image/img_1.png b/wgx_jvm_cache/image/img_1.png new file mode 100644 index 0000000..e7fffaf Binary files /dev/null and b/wgx_jvm_cache/image/img_1.png differ diff --git a/wgx_jvm_cache/image/img_2.png b/wgx_jvm_cache/image/img_2.png new file mode 100644 index 0000000..996e00c Binary files /dev/null and b/wgx_jvm_cache/image/img_2.png differ diff --git a/wgx_jvm_cache/image/img_3.png b/wgx_jvm_cache/image/img_3.png new file mode 100644 index 0000000..2d44fc1 Binary files /dev/null and b/wgx_jvm_cache/image/img_3.png differ diff --git a/wgx_jvm_cache/image/img_4.png b/wgx_jvm_cache/image/img_4.png new file mode 100644 index 0000000..ece6b01 Binary files /dev/null and b/wgx_jvm_cache/image/img_4.png differ diff --git a/wgx_jvm_cache/image/img_5.png b/wgx_jvm_cache/image/img_5.png new file mode 100644 index 0000000..ce7879f Binary files /dev/null and b/wgx_jvm_cache/image/img_5.png differ diff --git a/wgx_jvm_cache/jar/nasl-metadata-collector-0.8.0.jar b/wgx_jvm_cache/jar/nasl-metadata-collector-0.8.0.jar new file mode 100644 index 0000000..fffde15 Binary files /dev/null and b/wgx_jvm_cache/jar/nasl-metadata-collector-0.8.0.jar differ diff --git a/wgx_jvm_cache/pom.xml b/wgx_jvm_cache/pom.xml new file mode 100644 index 0000000..9e2bf91 --- /dev/null +++ b/wgx_jvm_cache/pom.xml @@ -0,0 +1,105 @@ + + + 4.0.0 + + com.wgx + wgx_jvm_cache + 1.0.7 + JVM缓存工具 + JVM缓存工具,支持缓存的读写、清除操作 + + + 8 + 8 + UTF-8 + + + + org.springframework.boot + spring-boot-starter-parent + 2.2.9.RELEASE + + + + + + + + + nasl-metadata-collector + com.netease.lowcode + 0.8.0 + true + system + ${project.basedir}/jar/nasl-metadata-collector-0.8.0.jar + + + + com.github.ben-manes.caffeine + caffeine + 2.5.5 + + + + org.springframework.boot + spring-boot-starter + + + + + com.fasterxml.jackson.core + jackson-databind + ${jackson.version} + + + + + org.slf4j + slf4j-api + provided + + + + + org.springframework.boot + spring-boot-starter-web + provided + + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + org.apache.commons + commons-lang3 + 3.9 + + + + + + + com.netease.lowcode + nasl-metadata-maven-plugin + 1.3.0 + + + + archive + + + + + + + \ No newline at end of file diff --git a/wgx_jvm_cache/src/main/java/com/wgx/Main.java b/wgx_jvm_cache/src/main/java/com/wgx/Main.java new file mode 100644 index 0000000..5ef8886 --- /dev/null +++ b/wgx_jvm_cache/src/main/java/com/wgx/Main.java @@ -0,0 +1,17 @@ +package com.wgx; + +//TIP To Run code, press or +// click the icon in the gutter. +public class Main { + public static void main(String[] args) { + //TIP Press with your caret at the highlighted text + // to see how IntelliJ IDEA suggests fixing it. + System.out.printf("Hello and welcome!"); + + for (int i = 1; i <= 5; i++) { + //TIP Press to start debugging your code. We have set one breakpoint + // for you, but you can always add more by pressing . + System.out.println("i = " + i); + } + } +} \ No newline at end of file diff --git a/wgx_jvm_cache/src/main/java/com/wgx/cache/jvm/LibraryAutoScan.java b/wgx_jvm_cache/src/main/java/com/wgx/cache/jvm/LibraryAutoScan.java new file mode 100644 index 0000000..9e3a337 --- /dev/null +++ b/wgx_jvm_cache/src/main/java/com/wgx/cache/jvm/LibraryAutoScan.java @@ -0,0 +1,8 @@ +package com.wgx.cache.jvm; + +/** + * 依赖库自动扫描类 + * @author system + */ +public class LibraryAutoScan { +} diff --git a/wgx_jvm_cache/src/main/java/com/wgx/cache/jvm/config/JvmCacheConfig.java b/wgx_jvm_cache/src/main/java/com/wgx/cache/jvm/config/JvmCacheConfig.java new file mode 100644 index 0000000..9a96814 --- /dev/null +++ b/wgx_jvm_cache/src/main/java/com/wgx/cache/jvm/config/JvmCacheConfig.java @@ -0,0 +1,32 @@ +package com.wgx.cache.jvm.config; + +import com.netease.lowcode.core.EnvironmentType; +import com.netease.lowcode.core.annotation.Environment; +import com.netease.lowcode.core.annotation.NaslConfiguration; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class JvmCacheConfig { + + /** + * 初始的缓存空间大小 单位为M + */ + @Value("${initialCapacity}") + @NaslConfiguration(defaultValue = { + @Environment(type = EnvironmentType.DEV, value = "10"), + @Environment(type = EnvironmentType.ONLINE, value = "10") + }) + public Long initialCapacity; + + /** + * 缓存的最大条数 + */ + @Value("${maximumSize}") + @NaslConfiguration(defaultValue = { + @Environment(type = EnvironmentType.DEV, value = "10000"), + @Environment(type = EnvironmentType.ONLINE, value = "10000") + }) + public Long maximumSize; + +} diff --git a/wgx_jvm_cache/src/main/java/com/wgx/cache/jvm/exception/CacheException.java b/wgx_jvm_cache/src/main/java/com/wgx/cache/jvm/exception/CacheException.java new file mode 100644 index 0000000..4664f84 --- /dev/null +++ b/wgx_jvm_cache/src/main/java/com/wgx/cache/jvm/exception/CacheException.java @@ -0,0 +1,11 @@ +package com.wgx.cache.jvm.exception; + +public class CacheException extends RuntimeException { + public CacheException(String message) { + super(message); + } + + public CacheException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/wgx_jvm_cache/src/main/java/com/wgx/cache/jvm/manager/JvmCacheManager.java b/wgx_jvm_cache/src/main/java/com/wgx/cache/jvm/manager/JvmCacheManager.java new file mode 100644 index 0000000..612810f --- /dev/null +++ b/wgx_jvm_cache/src/main/java/com/wgx/cache/jvm/manager/JvmCacheManager.java @@ -0,0 +1,56 @@ +package com.wgx.cache.jvm.manager; + +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; +import com.github.benmanes.caffeine.cache.Expiry; +import com.wgx.cache.jvm.config.JvmCacheConfig; +import com.wgx.cache.jvm.model.CacheDataWrapper; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * JVM缓存管理器 + * 负责初始化和配置Caffeine缓存 + */ +@Configuration +public class JvmCacheManager { + + @Autowired + private JvmCacheConfig cacheConfig; + + @Bean("basicCommonCache") + public Cache initCache() { + return Caffeine.newBuilder() + // 初始的缓存空间大小 + .initialCapacity(Math.toIntExact(cacheConfig.initialCapacity)) + // 缓存的最大条数 + .maximumSize(cacheConfig.maximumSize) + // key过期策略 + .expireAfter(new Expiry() { + //创建缓存设置过期时间,当TimeUnit参数为空时,不设置过期 + @Override + public long expireAfterCreate(Object o , CacheDataWrapper cw, long l) { + if (cw.getUnit()!=null){ + return cw.getUnit().toNanos(cw.getDelay()); + } + return l; + } + //更新缓存(相同key)时,取新的过期时间设置 + @Override + public long expireAfterUpdate(Object o, CacheDataWrapper cw, long l, long l1) { + if (cw.getUnit()!=null){ + return cw.getUnit().toNanos(cw.getDelay()); + } + return l; + } + //读完缓存不能影响过期时间 + @Override + public long expireAfterRead(Object o, CacheDataWrapper cw, long l, long l1) { + return l1; + } + }) + .build(); + } +} \ No newline at end of file diff --git a/wgx_jvm_cache/src/main/java/com/wgx/cache/jvm/model/CacheDataWrapper.java b/wgx_jvm_cache/src/main/java/com/wgx/cache/jvm/model/CacheDataWrapper.java new file mode 100644 index 0000000..826fd5f --- /dev/null +++ b/wgx_jvm_cache/src/main/java/com/wgx/cache/jvm/model/CacheDataWrapper.java @@ -0,0 +1,68 @@ +package com.wgx.cache.jvm.model; + +import java.util.Objects; +import java.util.concurrent.TimeUnit; + +public class CacheDataWrapper { + //缓存内容 + private String data; + //缓存过期时间 + private Long delay; + //缓存过期时间单位 + private TimeUnit unit; + + public CacheDataWrapper() { + } + + public CacheDataWrapper(String data, Long delay, TimeUnit unit) { + this.data = data; + this.delay = delay; + this.unit = unit; + } + + public String getData() { + return data; + } + + public void setData(String data) { + this.data = data; + } + + public TimeUnit getUnit() { + return unit; + } + + public void setUnit(TimeUnit unit) { + this.unit = unit; + } + + public Long getDelay() { + return delay; + } + + public void setDelay(Long delay) { + this.delay = delay; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + CacheDataWrapper that = (CacheDataWrapper) o; + return Objects.equals(data, that.data) && Objects.equals(delay, that.delay) && unit == that.unit; + } + + @Override + public int hashCode() { + return Objects.hash(data, delay, unit); + } + + @Override + public String toString() { + return "CacheDataWrapper{" + + "data='" + data + '\'' + + ", delay=" + delay + + ", unit=" + unit + + '}'; + } +} diff --git a/wgx_jvm_cache/src/main/java/com/wgx/cache/jvm/spring/JvmCacheSpringEnvironmentConfiguration.java b/wgx_jvm_cache/src/main/java/com/wgx/cache/jvm/spring/JvmCacheSpringEnvironmentConfiguration.java new file mode 100644 index 0000000..7652142 --- /dev/null +++ b/wgx_jvm_cache/src/main/java/com/wgx/cache/jvm/spring/JvmCacheSpringEnvironmentConfiguration.java @@ -0,0 +1,14 @@ +package com.wgx.cache.jvm.spring; + +import com.wgx.cache.jvm.LibraryAutoScan; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +/** + * 加入spring环境配置(在spring.factories中指定) + */ +@Configuration +@ComponentScan(basePackageClasses = LibraryAutoScan.class) +public class JvmCacheSpringEnvironmentConfiguration { +} + diff --git a/wgx_jvm_cache/src/main/java/com/wgx/cache/jvm/util/JvmCacheUtil.java b/wgx_jvm_cache/src/main/java/com/wgx/cache/jvm/util/JvmCacheUtil.java new file mode 100644 index 0000000..e76a04c --- /dev/null +++ b/wgx_jvm_cache/src/main/java/com/wgx/cache/jvm/util/JvmCacheUtil.java @@ -0,0 +1,455 @@ +package com.wgx.cache.jvm.util; + +import com.github.benmanes.caffeine.cache.Cache; +import com.netease.lowcode.core.annotation.NaslLogic; +import com.wgx.cache.jvm.exception.CacheException; +import com.wgx.cache.jvm.model.CacheDataWrapper; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; + +import java.util.*; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import java.util.function.Function; + +@Component +public class JvmCacheUtil { + + // getLogger参数统一使用LCAP_EXTENSION_LOGGER + private static final Logger logger = LoggerFactory.getLogger("LCAP_EXTENSION_LOGGER"); + + @Autowired + @Qualifier("basicCommonCache") + public Cache basicCommonCache; + + //用于连接外层key和hash的Key,作为新key存储hash的Value + private static final String SEPARATOR = ":"; + + /** + * 获取所有缓存键 + * @return 所有缓存键的集合,如果缓存为空或未初始化则返回空列表 + */ + @NaslLogic + public List getAllKeys() { + checkCacheInitialized("获取所有缓存键"); + + // 获取缓存中所有键的集合 + Set allKeys = basicCommonCache.asMap().keySet(); + if (allKeys.isEmpty()) { + return Collections.emptyList(); + } + // 过滤掉已经过期的键 + return allKeys.stream() + .filter(key -> basicCommonCache.getIfPresent(key) != null) + .collect(Collectors.toList()); + }; + + /** + * 获取缓存中的所有键值对 + * @return 包含所有键值对的Map,如果缓存为空或未初始化则返回空Map + */ + @NaslLogic + public Map getAllCache() { + checkCacheInitialized("获取所有缓存"); + + Map cacheMap = basicCommonCache.asMap(); + if (cacheMap.isEmpty()) { + logger.info("获取所有缓存时,缓存为空"); + return Collections.emptyMap(); + } + + try { + return cacheMap.entrySet().stream() + .collect(Collectors.toMap( + Map.Entry::getKey, + e -> String.valueOf(e.getValue().getData()), + (v1, v2) -> v2, + LinkedHashMap::new + )); + } catch (Exception e) { + logger.error("获取所有缓存异常", e); + return Collections.emptyMap(); + } + } + + /** + * 检查键是否存在 + * @param key 缓存键 + * @return 如果键存在返回true,否则返回false + */ + @NaslLogic + public Boolean exist(final String key) { + checkCacheInitialized("检查键是否存在"); + + if (StringUtils.isBlank(key)) { + logger.warn("检查键是否存在时, key为空或空白"); + return false; + } + + return basicCommonCache.getIfPresent(key) != null; + } + + /** + * 判断哈希键是否存在 + * + * @param key 主键 + * @param hashField 哈希字段 + * @return 如果存在返回true,否则返回false + */ + @NaslLogic + public Boolean existHash(final String key, final String hashField) { + checkCacheInitialized("检查哈希键是否存在"); + + if (StringUtils.isBlank(key) || StringUtils.isBlank(hashField)) { + logger.warn("检查哈希键是否存在时,key或hashField为空或空白"); + return false; + } + + return basicCommonCache.asMap().containsKey(key + SEPARATOR + hashField); + } + + /** + * 设置缓存 + * + * @param key 缓存键 + * @param value 缓存值 + * @return 存入成功返回true,否则返回false + * @throws CacheException 如果存入缓存时发生异常 + */ + @NaslLogic + public Boolean setCache(final String key, final String value) { + checkCacheInitialized("设置缓存"); + + if (key == null || key.isEmpty()) { + logger.warn("设置缓存时,key为空或空白"); + return false; + } + + try { + basicCommonCache.put(key, new CacheDataWrapper(value, null, null)); + logger.info("设置缓存成功:键 = {}, 值 = {}", key, value); + return true; + } catch (Exception e) { + logger.error("设置缓存失败:键 = {}, 值 = {}", key, value, e); + throw new CacheException("设置缓存异常", e); + } + } + + /** + * 设置带过期时间的缓存 + * @param key 缓存键 + * @param value 缓存值 + * @param expire 过期时间(毫秒) + * @return 设置成功返回true,否则返回false + */ + @NaslLogic + public Boolean setCacheWithExpire(final String key, final String value, final Long expire) { + checkCacheInitialized("设置带过期时间的缓存"); + + if (StringUtils.isBlank(key) || expire == null || expire < 0) { + logger.warn("设置带过期时间的缓存时,key为空或expire无效: key = {}, expire = {}", key, expire); + return false; + } + try { + basicCommonCache.put(key, new CacheDataWrapper(value, expire, TimeUnit.MILLISECONDS)); + logger.info("设置缓存成功:键 = {}, 值 = {}, 过期时间 = {} 毫秒", key, value, expire); + return true; + } catch (Exception e) { + logger.error("设置缓存失败:键 = {}, 值 = {}, 过期时间 = {} 毫秒", key, value, expire, e); + throw new CacheException("设置带过期时间的缓存异常", e); + } + } + + /** + * 设置哈希缓存 + * @param key 缓存键 + * @param hashField 哈希字段 + * @param value 缓存值 + * @return 设置成功返回true,否则返回false + * @throws CacheException 如果设置缓存时发生异常 + */ + @NaslLogic + public Boolean setHashCache(final String key, final String hashField, final String value) { + checkCacheInitialized("设置哈希缓存"); + + if (StringUtils.isBlank(key) || StringUtils.isBlank(hashField)) { + logger.warn("设置哈希缓存时,key或hashField为空或空白"); + return false; + } + try { + basicCommonCache.put(key + SEPARATOR + hashField, new CacheDataWrapper(value, null , null)); + logger.info("哈希设置缓存成功:键 = {}, 字段 = {}, 值 = {}", key, hashField, value); + return true; + } catch (Exception e) { + logger.error("哈希设置缓存失败:键 = {}, 字段 = {}, 值 = {}", key, hashField, value, e); + throw new CacheException("设置哈希缓存异常", e); + } + } + + /** + * 设置带过期时间的哈希缓存 + * @param key 缓存键 + * @param hashField 哈希字段 + * @param value 缓存值 + * @param expire 过期时间(毫秒) + * @return 设置成功返回true,否则返回false + * @throws CacheException 如果设置缓存时发生异常 + */ + @NaslLogic + public Boolean setHashCacheWithExpire(final String key, final String hashField, final String value, final Long expire) { + checkCacheInitialized("设置带过期时间的哈希缓存"); + + if (StringUtils.isBlank(key) || StringUtils.isBlank(hashField) || expire == null || expire < 0) { + logger.warn("设置带过期时间的哈希缓存时,参数无效: key = {}, hashField = {}, expire = {}", key, hashField, expire); + return false; + } + try { + basicCommonCache.put(key + SEPARATOR + hashField, new CacheDataWrapper(value, expire, TimeUnit.MILLISECONDS)); + logger.info("哈希设置缓存成功:键 = {}, 字段 = {}, 值 = {}, 过期时间 = {} 毫秒", key, hashField, value, expire); + return true; + } catch (Exception e) { + logger.error("哈希设置缓存失败:键 = {}, 字段 = {}, 值 = {}, 过期时间 = {} 毫秒", key, hashField, value, expire, e); + throw new CacheException("设置带过期时间的哈希缓存异常", e); + } + } + + /** + * 获取缓存 + * @param key 缓存键 + * @return 缓存值,如果不存在或已过期返回null + * @throws CacheException 如果获取缓存时发生异常 + */ + @NaslLogic + public String getCache(final String key) { + checkCacheInitialized("获取缓存"); + + if (StringUtils.isBlank(key)) { + logger.warn("获取缓存失败: key为空或空白"); + return null; + } + + try { + CacheDataWrapper wrapper = basicCommonCache.getIfPresent(key); + if (wrapper != null) { + String value = wrapper.getData(); + logger.info("获取缓存成功:键 = {}, 值 = {}", key, value); + return value; + } else { + logger.info("获取缓存失败:键 = {} 不存在或已过期", key); + return null; + } + } catch (Exception e) { + logger.error("获取缓存异常:键 = {}", key, e); + throw new CacheException("获取缓存异常", e); + } + } + + /** + * 获取哈希缓存 + * @param key 缓存键 + * @param hashField 哈希字段 + * @return 缓存值,如果不存在或已过期返回null + * @throws CacheException 如果获取缓存时发生异常 + */ + @NaslLogic + public String getHashCache(final String key, final String hashField) { + checkCacheInitialized("获取哈希缓存"); + + if (StringUtils.isBlank(key) || StringUtils.isBlank(hashField)) { + logger.warn("获取哈希缓存失败: key或hashField为空或空白"); + return null; + } + + try { + CacheDataWrapper wrapper = basicCommonCache.getIfPresent(key + SEPARATOR + hashField); + if (wrapper != null) { + String value = wrapper.getData(); + logger.info("哈希获取缓存成功:键 = {}, 字段 = {}, 值 = {}", key, hashField, value); + return value; + } else { + logger.info("哈希获取缓存失败:键 = {}, 字段 = {} 不存在或已过期", key, hashField); + return null; + } + } catch (Exception e) { + logger.error("哈希获取缓存异常:键 = {}, 字段 = {}", key, hashField, e); + throw new CacheException("哈希获取缓存异常", e); + } + } + + /** + * 批量获取缓存值 + * @param keys 要获取的键的集合 + * @return 包含存在的键值对的Map + * @throws CacheException 如果批量获取缓存时发生异常 + */ + @NaslLogic + public Map getMultiCache(List keys) { + checkCacheInitialized("批量获取缓存"); + + if (keys == null || keys.isEmpty()) { + logger.warn("批量获取缓存失败: 键列表为空"); + return Collections.emptyMap(); + } + + try { + Map result = basicCommonCache.getAllPresent(keys); + Map returnMap = new LinkedHashMap<>(result.size()); + for (Map.Entry entry : result.entrySet()) { + returnMap.put(entry.getKey(), entry.getValue().getData()); + } + logger.info("批量获取缓存成功: 获取到 {} 个键值对", returnMap.size()); + return returnMap; + } catch (Exception e) { + logger.error("批量获取缓存异常: {}", e.getMessage()); + throw new CacheException("批量获取缓存异常", e); + } + } + + /** + * 获取缓存,如果缓存不存在则执行function,并将查询的值放到缓存中 + * @param key 缓存键 + * @param expireAfterWriteMillis 写入后过期时间(毫秒) + * @param computeFunction 如果缓存不存在时,用于计算值的函数 + * @return 缓存值或计算后的新值 + * @throws CacheException 如果操作过程中发生异常 + */ + @NaslLogic + public String getOrComputeAndSet(String key, Long expireAfterWriteMillis, Function computeFunction) { + checkCacheInitialized("获取或计算并设置缓存"); + + if (StringUtils.isBlank(key)) { + logger.warn("获取或计算并设置缓存失败: key(缓存键) 为空"); + return null; + } + + if (expireAfterWriteMillis == null || expireAfterWriteMillis < 0) { + logger.warn("获取或计算并设置缓存失败: expireAfterWriteMillis(写入后过期时间(毫秒)) 无效"); + return null; + } + + if (computeFunction == null) { + logger.warn("获取或计算并设置缓存失败: computeFunction(如果缓存不存在时,用于计算值的函数)为空"); + return null; + } + + try { + String value = getCache(key); + if (value != null) { + logger.info("从缓存中获取到值:键 = {}, 值 = {}", key, value); + return value; + } + + String computedValue = computeFunction.apply(key); + if (computedValue != null) { + boolean setSuccess = setCacheWithExpire(key, computedValue, expireAfterWriteMillis); + if (setSuccess) { + logger.info("计算并设置缓存成功:键 = {}, 值 = {}, 过期时间 = {} 毫秒", key, computedValue, expireAfterWriteMillis); + } else { + logger.warn("计算值成功但设置缓存失败:键 = {}, 值 = {}", key, computedValue); + } + } else { + logger.info("计算值为null,不设置缓存:键 = {}", key); + } + + return computedValue; + } catch (Exception e) { + logger.error("获取或计算并设置缓存异常:键 = {}", key, e); + throw new CacheException("获取或计算并设置缓存异常", e); + } + } + + /** + * 删除缓存 + * @param key 缓存键 + * @throws CacheException 如果删除缓存时发生异常 + */ + @NaslLogic + public Boolean deleteCache(final String key) { + checkCacheInitialized("删除缓存"); + + if (StringUtils.isBlank(key)) { + logger.warn("删除缓存失败: key为空或空白"); + return false; + } + + try { + basicCommonCache.invalidate(key); + logger.info("删除缓存成功:键 = {}", key); + return true; + } catch (Exception e) { + logger.error("删除缓存异常:键 = {}", key, e); + return false; + } + } + + /** + * 删除哈希缓存 + * @param key 缓存键 + * @param hashField 哈希字段 + * @throws CacheException 如果删除哈希缓存时发生异常 + */ + @NaslLogic + public Boolean deleteHashCache(final String key, final String hashField) { + checkCacheInitialized("删除哈希缓存"); + + if (StringUtils.isBlank(key) || StringUtils.isBlank(hashField)) { + logger.warn("删除哈希缓存失败: key或hashField为空或空白"); + return false; + } + + try { + basicCommonCache.invalidate(key + SEPARATOR + hashField); + logger.info("删除哈希缓存成功:键 = {}, 字段 = {}", key, hashField); + return true; + } catch (Exception e) { + logger.error("删除哈希缓存异常:键 = {}, 字段 = {}", key, hashField, e); + return false; + } + } + + /** + * 清空所有缓存 + * @throws CacheException 如果清空缓存时发生异常 + */ + @NaslLogic + public Boolean clearAllCache() { + checkCacheInitialized("清空缓存"); + + try { + basicCommonCache.invalidateAll(); + logger.info("清空所有缓存成功"); + return true; + } catch (Exception e) { + logger.error("清空所有缓存异常", e); + return false; + } + } + + /** + * 获取缓存的估计大小 + * @return 缓存中的估计条目数,如果缓存管理器未初始化则返回null + */ + @NaslLogic + public Long getEstimatedSize() { + checkCacheInitialized("获取缓存估计大小"); + + long size = basicCommonCache.estimatedSize(); + logger.info("当前缓存估计大小: {}", size); + return size; + } + + /* 检查缓存是否初始化 + * @param operation 操作名称 + * @throws CacheException 如果缓存管理器未初始化 + */ + private void checkCacheInitialized(String operation) { + if (basicCommonCache == null) { + throw new CacheException(operation + "失败: 缓存管理器未初始化"); + } + } +} \ No newline at end of file diff --git a/wgx_jvm_cache/src/main/resources/META-INF/spring.factories b/wgx_jvm_cache/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000..09425a2 --- /dev/null +++ b/wgx_jvm_cache/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +com.wgx.cache.jvm.spring.JvmCacheSpringEnvironmentConfiguration \ No newline at end of file diff --git "a/wgx_jvm_cache/\344\276\235\350\265\226\345\272\223\344\275\277\347\224\250\346\226\207\346\241\243\350\257\264\346\230\216.docx" "b/wgx_jvm_cache/\344\276\235\350\265\226\345\272\223\344\275\277\347\224\250\346\226\207\346\241\243\350\257\264\346\230\216.docx" new file mode 100644 index 0000000..9f84cc8 Binary files /dev/null and "b/wgx_jvm_cache/\344\276\235\350\265\226\345\272\223\344\275\277\347\224\250\346\226\207\346\241\243\350\257\264\346\230\216.docx" differ