├── .idea ├── .gitignore ├── compiler.xml ├── encodings.xml ├── jarRepositories.xml ├── jpa-buddy.xml ├── misc.xml ├── uiDesigner.xml └── vcs.xml ├── CR-api ├── pom.xml └── src │ └── main │ └── java │ ├── annotation │ └── CacheInterceptor.java │ └── api │ ├── ICache.java │ ├── ICacheContext.java │ ├── ICacheEntry.java │ ├── ICacheEvict.java │ ├── ICacheEvictContext.java │ ├── ICacheExpire.java │ ├── ICacheInterceptor.java │ ├── ICacheInterceptorContext.java │ ├── ICacheLoad.java │ ├── ICachePersist.java │ ├── ICacheRemoveListener.java │ ├── ICacheRemoveListenerContext.java │ ├── ICacheSlowListener.java │ ├── ICacheSlowListenerContext.java │ └── package-info.java ├── CR-core ├── pom.xml └── src │ └── main │ └── java │ └── core │ ├── Context │ ├── Evict │ │ ├── Evict.java │ │ ├── EvictFIFO.java │ │ └── EvictLFU.java │ └── Expire │ │ └── Expire.java │ ├── KV │ ├── Key.java │ ├── KeyValueNode.java │ └── Values │ │ ├── HashValue.java │ │ ├── ListValue.java │ │ ├── SetValue.java │ │ ├── StringValue.java │ │ ├── Value.java │ │ └── ZSetValue.java │ ├── bs │ ├── CacheBs.java │ └── package-info.java │ ├── constant │ ├── GlobalCode.java │ ├── enums │ │ ├── CacheRemoveType.java │ │ └── model │ │ │ ├── CacheEntry.java │ │ │ ├── CircleListNode.java │ │ │ ├── DoubleListNode.java │ │ │ ├── FreqNode.java │ │ │ ├── PersistAofEntry.java │ │ │ └── PersistRdbEntry.java │ └── package-info.java │ ├── core │ ├── CR.java │ ├── CRcontext.java │ ├── Cache.java │ ├── CacheContext.java │ ├── exception │ │ ├── CRRunTimeException.java │ │ ├── CacheRuntimeException.java │ │ ├── ExceptionCode.java │ │ └── ExceptionCouple.java │ └── util │ │ └── GlobalUtils.java │ └── support │ ├── evict │ ├── AbstractCacheEvict.java │ ├── CacheEvictClock.java │ ├── CacheEvictContext.java │ ├── CacheEvictFifo.java │ ├── CacheEvictLfu.java │ ├── CacheEvictLru.java │ ├── CacheEvictLru2.java │ ├── CacheEvictLru2Q.java │ ├── CacheEvictLruDoubleListMap.java │ ├── CacheEvictLruLinkedHashMap.java │ ├── CacheEvictNone.java │ ├── CacheEvicts.java │ └── package-info.java │ ├── expire │ ├── CacheExpire.java │ ├── CacheExpireRandom.java │ ├── CacheExpireSort.java │ └── package-info.java │ ├── interceptor │ ├── CacheInterceptorContext.java │ ├── CacheInterceptors.java │ ├── aof │ │ └── CacheInterceptorAof.java │ ├── common │ │ └── CacheInterceptorCost.java │ ├── evict │ │ └── CacheInterceptorEvict.java │ ├── package-info.java │ └── refresh │ │ └── CacheInterceptorRefresh.java │ ├── listener │ ├── package-info.java │ ├── remove │ │ ├── CacheRemoveListener.java │ │ ├── CacheRemoveListenerContext.java │ │ └── CacheRemoveListeners.java │ └── slow │ │ ├── CacheSlowListener.java │ │ ├── CacheSlowListenerContext.java │ │ ├── CacheSlowListeners.java │ │ └── package-info.java │ ├── load │ ├── CacheLoadAof.java │ ├── CacheLoadDbJson.java │ ├── CacheLoadNone.java │ ├── CacheLoads.java │ └── package-info.java │ ├── map │ ├── Maps.java │ └── package-info.java │ ├── package-info.java │ ├── persist │ ├── CachePersistAdaptor.java │ ├── CachePersistAof.java │ ├── CachePersistDbJson.java │ ├── CachePersistNone.java │ ├── CachePersists.java │ ├── InnerCachePersist.java │ └── package-info.java │ ├── proxy │ ├── CacheProxy.java │ ├── ICacheProxy.java │ ├── bs │ │ ├── CacheProxyBs.java │ │ ├── CacheProxyBsContext.java │ │ └── ICacheProxyBsContext.java │ ├── cglib │ │ └── CglibProxy.java │ ├── dynamic │ │ ├── DynamicProxy.java │ │ └── package-info.java │ ├── none │ │ └── NoneProxy.java │ └── package-info.java │ └── struct │ ├── lru │ ├── ILruMap.java │ └── impl │ │ ├── LruMapCircleList.java │ │ └── LruMapDoubleList.java │ └── package-info.java ├── Readme.md └── pom.xml /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # 默认忽略的文件 2 | /shelf/ 3 | /workspace.xml 4 | # 基于编辑器的 HTTP 客户端请求 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | # Zeppelin ignored files 10 | /ZeppelinRemoteNotebooks/ 11 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 23 | 24 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | -------------------------------------------------------------------------------- /.idea/jpa-buddy.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 16 | 17 | 18 | 19 | 20 | 21 | 23 | 24 | 27 | 28 | -------------------------------------------------------------------------------- /.idea/uiDesigner.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /CR-api/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | CacheRedis 7 | org.example 8 | 1.0-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | CR-api 13 | 14 | 15 | 17 16 | 17 17 | 18 | 19 | -------------------------------------------------------------------------------- /CR-api/src/main/java/annotation/CacheInterceptor.java: -------------------------------------------------------------------------------- 1 | package annotation; 2 | 3 | import java.lang.annotation.*; 4 | 5 | /** 6 | * 7 | * @author lujiaxin 8 | * @date 2023/5/8 9 | */ 10 | @Documented 11 | @Inherited 12 | @Target(ElementType.METHOD) 13 | @Retention(RetentionPolicy.RUNTIME) 14 | public @interface CacheInterceptor { 15 | 16 | /** 17 | * 通用拦截器 18 | * 19 | * 1. 耗时统计 20 | * 2. 慢日志统计 21 | * 22 | * etc. 23 | * @return 默认开启 24 | * @since 0.0.5 25 | */ 26 | boolean common() default true; 27 | 28 | /** 29 | * 是否启用刷新 30 | * @return false 31 | * @since 0.0.5 32 | */ 33 | boolean refresh() default false; 34 | 35 | /** 36 | * 操作是否需要 append to file,默认为 false 37 | * 主要针对 cache 内容有变更的操作,不包括查询操作。 38 | * 包括删除,添加,过期等操作。 39 | * @return 是否 40 | * @since 0.0.10 41 | */ 42 | boolean aof() default false; 43 | 44 | /** 45 | * 是否执行驱除更新 46 | * 47 | * 主要用于 LRU/LFU 等驱除策略 48 | * @return 是否 49 | * @since 0.0.11 50 | */ 51 | boolean evict() default false; 52 | 53 | } 54 | -------------------------------------------------------------------------------- /CR-api/src/main/java/api/ICache.java: -------------------------------------------------------------------------------- 1 | package api; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | 6 | /** 7 | * 缓存接口 8 | * @author xmbcc 9 | * @since 0.0.1 10 | */ 11 | public interface ICache extends Map { 12 | 13 | /** 14 | * 设置过期时间 15 | * (1)如果 key 不存在,则什么都不做。 16 | * (2)暂时不提供新建 key 指定过期时间的方式,会破坏原来的方法。 17 | * 18 | * 会做什么: 19 | * 类似于 redis 20 | * (1)惰性删除。 21 | * 在执行下面的方法时,如果过期则进行删除。 22 | * {@link ICache#get(Object)} 获取 23 | * {@link ICache#values()} 获取所有值 24 | * {@link ICache#entrySet()} 获取所有明细 25 | * 26 | * 【数据的不一致性】 27 | * 调用其他方法,可能得到的不是使用者的预期结果,因为此时的 expire 信息可能没有被及时更新。 28 | * 比如 29 | * {@link ICache#isEmpty()} 是否为空 30 | * {@link ICache#size()} 当前大小 31 | * 同时会导致以 size() 作为过期条件的问题。 32 | * 33 | * 解决方案:考虑添加 refresh 等方法,暂时不做一致性的考虑。 34 | * 对于实际的使用,我们更关心 K/V 的信息。 35 | * 36 | * (2)定时删除 37 | * 启动一个定时任务。每次随机选择指定大小的 key 进行是否过期判断。 38 | * 类似于 redis,为了简化,可以考虑设定超时时间,频率与超时时间成反比。 39 | * 40 | * 其他拓展性考虑: 41 | * 后期考虑提供原子性操作,保证事务性。暂时不做考虑。 42 | * 此处默认使用 TTL 作为比较的基准,暂时不想支持 LastAccessTime 的淘汰策略。会增加复杂度。 43 | * 如果增加 lastAccessTime 过期,本方法可以不做修改。 44 | * 45 | * @param key key 46 | * @param timeInMills 毫秒时间之后过期 47 | * @return this 48 | * @since 0.0.3 49 | */ 50 | ICache expire(final K key, final long timeInMills); 51 | 52 | /** 53 | * 在指定的时间过期 54 | * @param key key 55 | * @param timeInMills 时间戳 56 | * @return this 57 | * @since 0.0.3 58 | */ 59 | ICache expireAt(final K key, final long timeInMills); 60 | 61 | /** 62 | * 获取缓存的过期处理类 63 | * @return 处理类实现 64 | * @since 0.0.4 65 | */ 66 | ICacheExpire expire(); 67 | 68 | /** 69 | * 删除监听类列表 70 | * @return 监听器列表 71 | * @since 0.0.6 72 | */ 73 | List> removeListeners(); 74 | 75 | /** 76 | * 慢日志监听类列表 77 | * @return 监听器列表 78 | * @since 0.0.9 79 | */ 80 | List slowListeners(); 81 | 82 | /** 83 | * 加载信息 84 | * @return 加载信息 85 | * @since 0.0.7 86 | */ 87 | ICacheLoad load(); 88 | 89 | /** 90 | * 持久化类 91 | * @return 持久化类 92 | * @since 0.0.10 93 | */ 94 | ICachePersist persist(); 95 | 96 | /** 97 | * 淘汰策略 98 | * @return 淘汰 99 | * @since 0.0.11 100 | */ 101 | ICacheEvict evict(); 102 | 103 | } 104 | -------------------------------------------------------------------------------- /CR-api/src/main/java/api/ICacheContext.java: -------------------------------------------------------------------------------- 1 | package api; 2 | 3 | import java.util.Map; 4 | 5 | /** 6 | * 7 | * @author lujiaxin 8 | * @date 2023/5/8 9 | */ 10 | public interface ICacheContext { 11 | 12 | /** 13 | * map 信息 14 | * @return map 15 | * @since 0.0.2 16 | */ 17 | Map map(); 18 | 19 | /** 20 | * 大小限制 21 | * @return 大小限制 22 | * @since 0.0.2 23 | */ 24 | int size(); 25 | 26 | /** 27 | * 驱除策略 28 | * @return 策略 29 | * @since 0.0.2 30 | */ 31 | ICacheEvict cacheEvict(); 32 | 33 | } 34 | -------------------------------------------------------------------------------- /CR-api/src/main/java/api/ICacheEntry.java: -------------------------------------------------------------------------------- 1 | package api; 2 | 3 | /** 4 | * 5 | * @author lujiaxin 6 | * @date 2023/5/8 7 | */ 8 | public interface ICacheEntry { 9 | 10 | /** 11 | * @since 0.0.11 12 | * @return key 13 | */ 14 | K key(); 15 | 16 | /** 17 | * @since 0.0.11 18 | * @return value 19 | */ 20 | V value(); 21 | 22 | } 23 | -------------------------------------------------------------------------------- /CR-api/src/main/java/api/ICacheEvict.java: -------------------------------------------------------------------------------- 1 | package api; 2 | 3 | /** 4 | * 5 | * @author lujiaxin 6 | * @date 2023/5/8 7 | */ 8 | public interface ICacheEvict { 9 | 10 | /** 11 | * 驱除策略 12 | * 13 | * @param context 上下文 14 | * @since 0.0.2 15 | * @return 被移除的明细,没有时返回 null 16 | */ 17 | ICacheEntry evict(final ICacheEvictContext context); 18 | 19 | /** 20 | * 更新 key 信息 21 | * @param key key 22 | * @since 0.0.11 23 | */ 24 | void updateKey(final K key); 25 | 26 | /** 27 | * 删除 key 信息 28 | * @param key key 29 | * @since 0.0.11 30 | */ 31 | void removeKey(final K key); 32 | 33 | } 34 | -------------------------------------------------------------------------------- /CR-api/src/main/java/api/ICacheEvictContext.java: -------------------------------------------------------------------------------- 1 | package api; 2 | 3 | /** 4 | * 5 | * @author lujiaxin 6 | * @date 2023/5/8 7 | */ 8 | public interface ICacheEvictContext { 9 | 10 | /** 11 | * 新加的 key 12 | * @return key 13 | * @since 0.0.2 14 | */ 15 | K key(); 16 | 17 | /** 18 | * cache 实现 19 | * @return map 20 | * @since 0.0.2 21 | */ 22 | ICache cache(); 23 | 24 | /** 25 | * 获取大小 26 | * @return 大小 27 | * @since 0.0.2 28 | */ 29 | int size(); 30 | 31 | } 32 | -------------------------------------------------------------------------------- /CR-api/src/main/java/api/ICacheExpire.java: -------------------------------------------------------------------------------- 1 | package api; 2 | 3 | import java.util.Collection; 4 | 5 | /** 6 | * 7 | * @author lujiaxin 8 | * @date 2023/5/8 9 | */ 10 | public interface ICacheExpire { 11 | 12 | /** 13 | * 指定过期信息 14 | * @param key key 15 | * @param expireAt 什么时候过期 16 | * @since 0.0.3 17 | */ 18 | void expire(final K key, final long expireAt); 19 | 20 | /** 21 | * 惰性删除中需要处理的 keys 22 | * @param keyList keys 23 | * @since 0.0.3 24 | */ 25 | void refreshExpire(final Collection keyList); 26 | 27 | /** 28 | * 待过期的 key 29 | * 不存在,则返回 null 30 | * @param key 待过期的 key 31 | * @return 结果 32 | * @since 0.0.8 33 | */ 34 | Long expireTime(final K key); 35 | 36 | } 37 | -------------------------------------------------------------------------------- /CR-api/src/main/java/api/ICacheInterceptor.java: -------------------------------------------------------------------------------- 1 | package api; 2 | 3 | /** 4 | * 5 | * @author lujiaxin 6 | * @date 2023/5/8 7 | */ 8 | public interface ICacheInterceptor { 9 | 10 | /** 11 | * 方法执行之前 12 | * @param context 上下文 13 | * @since 0.0.5 14 | */ 15 | void before(ICacheInterceptorContext context); 16 | 17 | /** 18 | * 方法执行之后 19 | * @param context 上下文 20 | * @since 0.0.5 21 | */ 22 | void after(ICacheInterceptorContext context); 23 | 24 | } 25 | -------------------------------------------------------------------------------- /CR-api/src/main/java/api/ICacheInterceptorContext.java: -------------------------------------------------------------------------------- 1 | package api; 2 | 3 | import java.lang.reflect.Method; 4 | 5 | /** 6 | * 7 | * @author lujiaxin 8 | * @date 2023/5/8 9 | */ 10 | public interface ICacheInterceptorContext { 11 | 12 | /** 13 | * 缓存信息 14 | * @return 缓存信息 15 | * @since 0.0.5 16 | */ 17 | ICache cache(); 18 | 19 | /** 20 | * 执行的方法信息 21 | * @return 方法 22 | * @since 0.0.5 23 | */ 24 | Method method(); 25 | 26 | /** 27 | * 执行的参数 28 | * @return 参数 29 | * @since 0.0.5 30 | */ 31 | Object[] params(); 32 | 33 | /** 34 | * 方法执行的结果 35 | * @return 结果 36 | * @since 0.0.5 37 | */ 38 | Object result(); 39 | 40 | /** 41 | * 开始时间 42 | * @return 时间 43 | * @since 0.0.5 44 | */ 45 | long startMills(); 46 | 47 | /** 48 | * 结束时间 49 | * @return 时间 50 | * @since 0.0.5 51 | */ 52 | long endMills(); 53 | 54 | } 55 | -------------------------------------------------------------------------------- /CR-api/src/main/java/api/ICacheLoad.java: -------------------------------------------------------------------------------- 1 | package api; 2 | 3 | /** 4 | * 5 | * @author lujiaxin 6 | * @date 2023/5/8 7 | */ 8 | public interface ICacheLoad { 9 | 10 | /** 11 | * 加载缓存信息 12 | * @param cache 缓存 13 | * @since 0.0.7 14 | */ 15 | void load(final ICache cache); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /CR-api/src/main/java/api/ICachePersist.java: -------------------------------------------------------------------------------- 1 | package api; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | 5 | /** 6 | * 7 | * @author lujiaxin 8 | * @date 2023/5/8 9 | */ 10 | public interface ICachePersist { 11 | 12 | /** 13 | * 持久化缓存信息 14 | * @param cache 缓存 15 | * @since 0.0.7 16 | */ 17 | void persist(final ICache cache); 18 | 19 | /** 20 | * 延迟时间 21 | * @return 延迟 22 | * @since 0.0.10 23 | */ 24 | long delay(); 25 | 26 | /** 27 | * 时间间隔 28 | * @return 间隔 29 | * @since 0.0.10 30 | */ 31 | long period(); 32 | 33 | /** 34 | * 时间单位 35 | * @return 时间单位 36 | * @since 0.0.10 37 | */ 38 | TimeUnit timeUnit(); 39 | } 40 | -------------------------------------------------------------------------------- /CR-api/src/main/java/api/ICacheRemoveListener.java: -------------------------------------------------------------------------------- 1 | package api; 2 | 3 | /** 4 | * 5 | * @author lujiaxin 6 | * @date 2023/5/8 7 | */ 8 | public interface ICacheRemoveListener { 9 | 10 | /** 11 | * 监听 12 | * @param context 上下文 13 | * @since 0.0.6 14 | */ 15 | void listen(final ICacheRemoveListenerContext context); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /CR-api/src/main/java/api/ICacheRemoveListenerContext.java: -------------------------------------------------------------------------------- 1 | package api; 2 | 3 | /** 4 | * 删除监听器上下文 5 | *(1)耗时统计 6 | *(2)监听器 7 | * @author lujiaxin 8 | * @date 2023/5/8 9 | */ 10 | public interface ICacheRemoveListenerContext { 11 | 12 | /** 13 | * 清空的 key 14 | * @return key 15 | * @since 0.0.6 16 | */ 17 | K key(); 18 | 19 | /** 20 | * 值 21 | * @return 值 22 | * @since 0.0.6 23 | */ 24 | V value(); 25 | 26 | /** 27 | * 删除类型 28 | * @return 类型 29 | * @since 0.0.6 30 | */ 31 | String type(); 32 | 33 | } 34 | -------------------------------------------------------------------------------- /CR-api/src/main/java/api/ICacheSlowListener.java: -------------------------------------------------------------------------------- 1 | package api; 2 | 3 | /** 4 | * 慢日志操作接口 5 | * @author lujiaxin 6 | * @date 2023/5/8 7 | */ 8 | public interface ICacheSlowListener { 9 | 10 | /** 11 | * 监听 12 | * @param context 上下文 13 | * @since 0.0.6 14 | */ 15 | void listen(final ICacheSlowListenerContext context); 16 | 17 | /** 18 | * 慢日志的阈值 19 | * @return 慢日志的阈值 20 | * @since 0.0.9 21 | */ 22 | long slowerThanMills(); 23 | 24 | } 25 | -------------------------------------------------------------------------------- /CR-api/src/main/java/api/ICacheSlowListenerContext.java: -------------------------------------------------------------------------------- 1 | package api; 2 | 3 | /** 4 | * 慢日志监听器上下文 5 | * @author lujiaxin 6 | * @date 2023/5/8 7 | */ 8 | public interface ICacheSlowListenerContext { 9 | 10 | /** 11 | * 方法名称 12 | * @return 方法名称 13 | * @since 0.0.9 14 | */ 15 | String methodName(); 16 | 17 | /** 18 | * 参数信息 19 | * @return 参数列表 20 | * @since 0.0.9 21 | */ 22 | Object[] params(); 23 | 24 | /** 25 | * 方法结果 26 | * @return 方法结果 27 | * @since 0.0.9 28 | */ 29 | Object result(); 30 | 31 | /** 32 | * 开始时间 33 | * @return 时间 34 | * @since 0.0.9 35 | */ 36 | long startTimeMills(); 37 | 38 | /** 39 | * 结束时间 40 | * @return 结束时间 41 | * @since 0.0.9 42 | */ 43 | long endTimeMills(); 44 | 45 | /** 46 | * 消耗时间 47 | * @return 耗时 48 | * @since 0.0.9 49 | */ 50 | long costTimeMills(); 51 | 52 | } 53 | -------------------------------------------------------------------------------- /CR-api/src/main/java/api/package-info.java: -------------------------------------------------------------------------------- 1 | package api; -------------------------------------------------------------------------------- /CR-core/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | CacheRedis 7 | org.example 8 | 1.0-SNAPSHOT 9 | 10 | 11 | CR-core 12 | 13 | 14 | 15 | org.example 16 | CR-api 17 | 1.0-SNAPSHOT 18 | 19 | 20 | com.github.houbb 21 | aop-core 22 | 0.0.3 23 | 24 | 25 | org.slf4j 26 | jcl-over-slf4j 27 | 2.0.4 28 | 29 | 30 | cglib 31 | cglib 32 | 3.1 33 | 34 | 35 | ch.qos.logback 36 | logback-core 37 | 1.4.5 38 | 39 | 40 | 4.0.0 41 | 42 | 43 | 44 | 17 45 | 17 46 | 47 | 48 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/Context/Evict/Evict.java: -------------------------------------------------------------------------------- 1 | package core.Context.Evict; 2 | 3 | import core.KV.Key; 4 | import core.KV.Values.Value; 5 | import core.core.CRcontext; 6 | import core.core.exception.CRRunTimeException; 7 | 8 | /** 9 | * 淘汰策略接口 10 | * @author lujiaxin 11 | * @date 2023/5/11 12 | */ 13 | public interface Evict { 14 | 15 | void doEvict(Key key, Object value, CRcontext crc) throws CRRunTimeException; 16 | 17 | } 18 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/Context/Evict/EvictFIFO.java: -------------------------------------------------------------------------------- 1 | package core.Context.Evict; 2 | 3 | import core.KV.Key; 4 | import core.core.CRcontext; 5 | 6 | import java.util.LinkedList; 7 | import java.util.Queue; 8 | 9 | import static core.constant.GlobalCode.CACHE_LIMIT_MAX; 10 | 11 | /** 12 | * FIFO(先进先出)淘汰策略 13 | * @author lujiaxin 14 | * @date 2023/5/11 15 | */ 16 | public class EvictFIFO implements Evict{ 17 | 18 | private Queue list = new LinkedList(); 19 | 20 | @Override 21 | public void doEvict(Key key, Object value, CRcontext crc) { 22 | 23 | if(list.size() >= CACHE_LIMIT_MAX){ 24 | //超出长度限制,进行淘汰 25 | crc.getMap().remove(list.poll()); 26 | } 27 | list.offer(key); 28 | crc.getMap().put(key,value); 29 | 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/Context/Evict/EvictLFU.java: -------------------------------------------------------------------------------- 1 | package core.Context.Evict; 2 | 3 | import core.KV.Key; 4 | import core.KV.KeyValueNode; 5 | import core.core.CRcontext; 6 | import core.core.exception.CRRunTimeException; 7 | 8 | import java.util.HashMap; 9 | import java.util.LinkedHashSet; 10 | import java.util.Map; 11 | 12 | import static core.constant.GlobalCode.*; 13 | import static core.core.exception.ExceptionCode.LFU_MIN_NOTFIND; 14 | 15 | /** 16 | * 淘汰策略-最小使用频次 17 | * @author lujiaxin 18 | * @date 2023/5/11 19 | */ 20 | public class EvictLFU implements Evict{ 21 | 22 | private Map> map; 23 | 24 | private Integer min; 25 | 26 | public EvictLFU() { 27 | init(); 28 | } 29 | 30 | private void init() { 31 | 32 | map = new HashMap<>(); 33 | min = LFU_MIN; 34 | 35 | } 36 | 37 | @Override 38 | public void doEvict(Key key, Object value, CRcontext crc) throws CRRunTimeException { 39 | 40 | if(crc.getMap().size() >= CACHE_LIMIT_MAX){ 41 | //超出限制,进行淘汰 42 | LinkedHashSet minSet = map.get(min); 43 | //判断是否为空 44 | while(minSet.isEmpty()){ 45 | min++; 46 | if(min>crc.getMap().size()) throw new CRRunTimeException(LFU_MIN_NOTFIND); 47 | } 48 | KeyValueNode next = minSet.iterator().next(); 49 | crc.getMap().remove(next.getKey(),next.getValue()); 50 | } 51 | //放入新元素 52 | LinkedHashSet set = map.get(LFU_INIT_NUM); 53 | KeyValueNode node = new KeyValueNode(key,value); 54 | set.add(node); 55 | map.put(LFU_INIT_NUM,set); 56 | min = LFU_MIN; 57 | 58 | } 59 | 60 | /** 61 | * 频次自增操作 62 | * @param key 63 | * @param value 64 | */ 65 | public void doIncrease(Key key,Object value) { 66 | 67 | //自增操作 68 | KeyValueNode node = new KeyValueNode(key, value); 69 | for(int i=0;i set = map.get(i); 71 | if(set.contains(node)){ 72 | set.remove(node); 73 | //获取下一个频次,没有就创建 74 | map.getOrDefault(i+1,new LinkedHashSet<>()).add(node); 75 | } 76 | } 77 | 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/Context/Expire/Expire.java: -------------------------------------------------------------------------------- 1 | package core.Context.Expire; 2 | 3 | /** 4 | * 过期策略接口 5 | * @author lujiaxin 6 | * @date 2023/5/11 7 | */ 8 | public interface Expire { 9 | 10 | void expire(); 11 | 12 | } 13 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/KV/Key.java: -------------------------------------------------------------------------------- 1 | package core.KV; 2 | 3 | import java.nio.charset.Charset; 4 | import java.nio.charset.StandardCharsets; 5 | import java.util.Arrays; 6 | 7 | /** 8 | * Key为封装的String 9 | * 10 | * @author lujiaxin 11 | * @date 2023/5/9 12 | */ 13 | public class Key implements Comparable { 14 | 15 | static final Charset charset = StandardCharsets.UTF_8; 16 | private final byte[] content; 17 | private long expireSeconds; 18 | 19 | /** 20 | * 构造函数 21 | * @param bytes 22 | */ 23 | public Key(byte[] bytes){ 24 | this.content = bytes; 25 | } 26 | 27 | /** 28 | * 过期构造 29 | * 30 | * @param bytes 31 | * @param expireSeconds 32 | */ 33 | public Key(byte[] bytes, long expireSeconds){ 34 | this.content = bytes; 35 | this.expireSeconds = expireSeconds; 36 | } 37 | /** 38 | * 重写hashcode 39 | * @return 40 | */ 41 | @Override 42 | public int hashCode() { 43 | return Arrays.hashCode(content); 44 | } 45 | 46 | /** 47 | * 转换为utf-8 48 | * @return 49 | */ 50 | public String toUtf8(){ 51 | return new String(content,charset); 52 | } 53 | 54 | /** 55 | * 重写equals判断key是否唯一 56 | * @param obj 57 | * @return 58 | */ 59 | @Override 60 | public boolean equals(Object obj) { 61 | 62 | if (this == obj) return true; 63 | 64 | if(getClass() != obj.getClass() || obj == null) return false; 65 | 66 | Key k = (Key) obj; 67 | 68 | return Arrays.equals(content,k.content); 69 | 70 | } 71 | 72 | @Override 73 | public int compareTo(Key o) { 74 | return 0; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/KV/KeyValueNode.java: -------------------------------------------------------------------------------- 1 | package core.KV; 2 | 3 | /** 4 | * 封装Key、Value的Node节点 5 | * @author lujiaxin 6 | * @date 2023/5/11 7 | */ 8 | public class KeyValueNode { 9 | 10 | private Key key; 11 | private Object value; 12 | 13 | public KeyValueNode(Key key, Object value) { 14 | this.key = key; 15 | this.value = value; 16 | } 17 | 18 | public Key getKey() { 19 | return key; 20 | } 21 | 22 | public void setKey(Key key) { 23 | this.key = key; 24 | } 25 | 26 | public Object getValue() { 27 | return value; 28 | } 29 | 30 | public void setValue(Object value) { 31 | this.value = value; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/KV/Values/HashValue.java: -------------------------------------------------------------------------------- 1 | package core.KV.Values; 2 | 3 | import core.KV.Key; 4 | import core.core.CRcontext; 5 | 6 | import java.util.Map; 7 | 8 | public class HashValue implements Value { 9 | 10 | private Map map; 11 | 12 | private CRcontext crc; 13 | 14 | public HashValue() { 15 | } 16 | 17 | public HashValue(CRcontext crc) { 18 | this.crc = crc; 19 | this.map = crc.getMap(); 20 | } 21 | 22 | @Override 23 | public V get(Key key) { 24 | return null; 25 | } 26 | 27 | @Override 28 | public Boolean set(Key key, Object value) { 29 | return null; 30 | } 31 | 32 | @Override 33 | public void expire(Key key, long timeinMillons) { 34 | 35 | } 36 | 37 | @Override 38 | public Boolean containsKey(Key key) { 39 | return null; 40 | } 41 | 42 | @Override 43 | public V remove(Key key) { 44 | return null; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/KV/Values/ListValue.java: -------------------------------------------------------------------------------- 1 | package core.KV.Values; 2 | 3 | import core.KV.Key; 4 | import core.core.CRcontext; 5 | 6 | import java.util.Map; 7 | 8 | public class ListValue implements Value { 9 | 10 | private Map map; 11 | 12 | private CRcontext crc; 13 | 14 | public ListValue() { 15 | } 16 | 17 | public ListValue(CRcontext crc) { 18 | this.crc = crc; 19 | this.map = crc.getMap(); 20 | } 21 | 22 | @Override 23 | public V get(Key key) { 24 | return null; 25 | } 26 | 27 | @Override 28 | public Boolean set(Key key, Object value) { 29 | return null; 30 | } 31 | 32 | @Override 33 | public void expire(Key key, long timeinMillons) { 34 | 35 | } 36 | 37 | @Override 38 | public Boolean containsKey(Key key) { 39 | return null; 40 | } 41 | 42 | @Override 43 | public V remove(Key key) { 44 | return null; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/KV/Values/SetValue.java: -------------------------------------------------------------------------------- 1 | package core.KV.Values; 2 | 3 | import core.KV.Key; 4 | import core.core.CRcontext; 5 | 6 | import java.util.Map; 7 | 8 | public class SetValue implements Value { 9 | 10 | private Map map; 11 | 12 | private CRcontext crc; 13 | 14 | public SetValue() { 15 | } 16 | 17 | public SetValue(CRcontext crc) { 18 | this.crc = crc; 19 | this.map = crc.getMap(); 20 | } 21 | 22 | @Override 23 | public V get(Key key) { 24 | return null; 25 | } 26 | 27 | @Override 28 | public Boolean set(Key key, Object value) { 29 | return null; 30 | } 31 | 32 | @Override 33 | public void expire(Key key, long timeinMillons) { 34 | 35 | } 36 | 37 | @Override 38 | public Boolean containsKey(Key key) { 39 | return null; 40 | } 41 | 42 | @Override 43 | public V remove(Key key) { 44 | return null; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/KV/Values/StringValue.java: -------------------------------------------------------------------------------- 1 | package core.KV.Values; 2 | 3 | import core.Context.Evict.Evict; 4 | import core.Context.Evict.EvictLFU; 5 | import core.KV.Key; 6 | import core.core.CRcontext; 7 | import core.core.exception.CRRunTimeException; 8 | import core.core.util.GlobalUtils; 9 | 10 | import java.util.Map; 11 | 12 | import static core.core.exception.ExceptionCode.*; 13 | 14 | /** 15 | * String数据类型 16 | * @author lujiaxin 17 | * @date 2023/5/9 18 | */ 19 | public class StringValue implements Value{ 20 | 21 | private CRcontext crc; 22 | 23 | private Map map; 24 | 25 | /** 26 | * 空参 27 | */ 28 | public StringValue() { 29 | } 30 | 31 | /** 32 | * 带参 33 | * @param crc 34 | */ 35 | public StringValue(CRcontext crc) { 36 | this.crc = crc; 37 | this.map = crc.getMap(); 38 | } 39 | 40 | /** 41 | * get方法 42 | * @param key 43 | * @return 44 | * @param 45 | * @throws CRRunTimeException 46 | */ 47 | @Override 48 | public V get(Key key) throws CRRunTimeException { 49 | //参数校验 50 | if( !GlobalUtils.pc(key) ){ 51 | //error:key格式错误 52 | throw new CRRunTimeException(KEY_FORMAT_ERROR); 53 | } 54 | //判断Key是否存在 55 | if(!map.containsKey(key)) 56 | //error:key不存在 57 | throw new CRRunTimeException(KEY_NOTFIND_ERROR); 58 | //超时、策略逻辑 59 | //LFU 自增操作 60 | GlobalUtils.doIncrease(key,crc,map); 61 | //查找并校验value 62 | if( !GlobalUtils.pc(map.get(key)) ){ 63 | //error:value格式错误 64 | throw new CRRunTimeException(VALUE_FORMAT_ERROR); 65 | } 66 | 67 | return (V) map.get(key); 68 | } 69 | 70 | /** 71 | * set方法 72 | * @param key 73 | * @param value 74 | * @return 75 | */ 76 | @Override 77 | public Boolean set(Key key, Object value) throws CRRunTimeException { 78 | //参数校验 79 | if(!GlobalUtils.pc(key,value)) throw new CRRunTimeException(KEY_VALUE_FORMAT_ERROR); 80 | //判断key是否存在 81 | if(!containsKey(key)) throw new CRRunTimeException(KEY_NOTFIND_ERROR); 82 | //开始存入,判断是否触发容量限制 83 | map.put(key,value); 84 | //封装方法:超过限制/未超过 85 | //淘汰 86 | crc.getEvict().doEvict(key,value,crc); 87 | return true; 88 | } 89 | 90 | private void dosomething() { 91 | } 92 | 93 | 94 | /** 95 | * 给Key设置过期时间 96 | * @param key 97 | * @param timeinMillons 98 | * @return 99 | */ 100 | @Override 101 | public void expire(Key key, long timeinMillons) { 102 | 103 | //创建key,附加时间 104 | long time = System.currentTimeMillis() + timeinMillons; 105 | Key k = new Key(key.toString().getBytes(),time); 106 | //触发使用频次++ 107 | GlobalUtils.doIncrease(key,crc,map); 108 | //塞入 109 | map.put(key,map.get(key)); 110 | 111 | } 112 | 113 | @Override 114 | public Boolean containsKey(Key key) { 115 | if(map.containsKey(key)) return true; 116 | return false; 117 | } 118 | 119 | @Override 120 | public Object remove(Key key) throws CRRunTimeException { 121 | //判断传入参数是否符合格式 122 | if(!GlobalUtils.pc(key)) throw new CRRunTimeException(KEY_FORMAT_ERROR); 123 | //判断Key是否存在 124 | if(!containsKey(key)) throw new CRRunTimeException(KEY_NOTFIND_ERROR); 125 | //dosomething 126 | 127 | //删除Key 128 | return map.remove(key); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/KV/Values/Value.java: -------------------------------------------------------------------------------- 1 | package core.KV.Values; 2 | 3 | import core.KV.Key; 4 | import core.core.exception.CRRunTimeException; 5 | 6 | /** 7 | * 数据类型顶层接口,实现接口创造数据类型 8 | * @author lujiaxin 9 | * @date 2023/5/9 10 | */ 11 | public interface Value { 12 | 13 | V get(Key key) throws CRRunTimeException; 14 | 15 | Boolean set(Key key,Object value) throws CRRunTimeException; 16 | 17 | void expire(Key key,long timeinMillons); 18 | 19 | Boolean containsKey(Key key); 20 | 21 | V remove(Key key) throws CRRunTimeException; 22 | 23 | } 24 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/KV/Values/ZSetValue.java: -------------------------------------------------------------------------------- 1 | package core.KV.Values; 2 | 3 | import core.KV.Key; 4 | import core.core.CRcontext; 5 | 6 | import java.util.Map; 7 | 8 | public class ZSetValue implements Value { 9 | 10 | private Map map; 11 | 12 | private CRcontext crc; 13 | 14 | public ZSetValue() { 15 | } 16 | 17 | public ZSetValue(CRcontext crc) { 18 | this.crc = crc; 19 | this.map = crc.getMap(); 20 | } 21 | 22 | @Override 23 | public V get(Key key) { 24 | return null; 25 | } 26 | 27 | @Override 28 | public Boolean set(Key key, Object value) { 29 | return null; 30 | } 31 | 32 | @Override 33 | public void expire(Key key, long timeinMillons) { 34 | 35 | } 36 | 37 | @Override 38 | public Boolean containsKey(Key key) { 39 | return null; 40 | } 41 | 42 | @Override 43 | public V remove(Key key) { 44 | return null; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/bs/CacheBs.java: -------------------------------------------------------------------------------- 1 | package core.bs; 2 | 3 | import api.*; 4 | import com.github.houbb.heaven.util.common.ArgUtil; 5 | import core.core.Cache; 6 | import core.support.evict.CacheEvicts; 7 | import core.support.listener.remove.CacheRemoveListeners; 8 | import core.support.listener.slow.CacheSlowListeners; 9 | import core.support.load.CacheLoads; 10 | import core.support.persist.CachePersists; 11 | import core.support.proxy.CacheProxy; 12 | 13 | import java.util.HashMap; 14 | import java.util.List; 15 | import java.util.Map; 16 | 17 | //介绍: 一个缓存引导类,便捷创建缓存 18 | //作用: 将繁杂的初始化缓存过程封装 19 | //使用: CacheBs.newInstance() 创建对象 20 | // .load() 设置加载模式 21 | // .persist() 设置持久化策略 22 | // .map() 设置指定数据集 23 | // .size() 设置大小 24 | // .evict() 设置驱逐策略 25 | // .addRemoveListener() 添加指定删除监听器 26 | // .addSlowListener() 添加指定慢日志监听器 27 | // .build() 最后执行创建命令 28 | /** 29 | * 30 | * @author lujiaxin 31 | * @date 2023/5/8 32 | */ 33 | public final class CacheBs { 34 | //aaa 35 | 36 | //默认设置 37 | private Map map = new HashMap<>(); 38 | private int size = Integer.MAX_VALUE; 39 | private ICacheEvict evict = CacheEvicts.fifo(); 40 | private final List> removeListeners = CacheRemoveListeners.defaults(); 41 | private final List slowListeners = CacheSlowListeners.none(); 42 | private ICacheLoad load = CacheLoads.none(); 43 | private ICachePersist persist = CachePersists.none(); 44 | 45 | //自定义设置 46 | public CacheBs map(Map map) { 47 | ArgUtil.notNull(map, "map"); 48 | 49 | this.map = map; 50 | return this; 51 | } 52 | public CacheBs size(int size) { 53 | ArgUtil.notNegative(size, "size"); 54 | 55 | this.size = size; 56 | return this; 57 | } 58 | public CacheBs evict(ICacheEvict evict) { 59 | ArgUtil.notNull(evict, "evict"); 60 | 61 | this.evict = evict; 62 | return this; 63 | } 64 | public CacheBs load(ICacheLoad load) { 65 | ArgUtil.notNull(load, "load"); 66 | 67 | this.load = load; 68 | return this; 69 | } 70 | public CacheBs addRemoveListener(ICacheRemoveListener removeListener) { 71 | ArgUtil.notNull(removeListener, "removeListener"); 72 | 73 | this.removeListeners.add(removeListener); 74 | return this; 75 | } 76 | public CacheBs addSlowListener(ICacheSlowListener slowListener) { 77 | ArgUtil.notNull(slowListener, "slowListener"); 78 | 79 | this.slowListeners.add(slowListener); 80 | return this; 81 | } 82 | public CacheBs persist(ICachePersist persist) { 83 | this.persist = persist; 84 | return this; 85 | } 86 | 87 | //创建缓存 88 | public ICache build() { 89 | Cache cache = new Cache<>(); 90 | cache.map(map); 91 | cache.evict(evict); 92 | cache.sizeLimit(size); 93 | cache.removeListeners(removeListeners); 94 | cache.load(load); 95 | cache.persist(persist); 96 | cache.slowListeners(slowListeners); 97 | 98 | // 初始化 99 | cache.init(); 100 | return CacheProxy.getProxy(cache); 101 | } 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | //构造函数 115 | private CacheBs(){} 116 | 117 | 118 | 119 | //流式编程 | 返回值 | 方法名 | 120 | public static CacheBs newInstance() { 121 | return new CacheBs<>(); 122 | } 123 | 124 | } 125 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/bs/package-info.java: -------------------------------------------------------------------------------- 1 | package core.bs; -------------------------------------------------------------------------------- /CR-core/src/main/java/core/constant/GlobalCode.java: -------------------------------------------------------------------------------- 1 | package core.constant; 2 | 3 | public class GlobalCode { 4 | 5 | public static Integer CACHE_LIMIT_MAX = Integer.MAX_VALUE; 6 | 7 | public static Integer LFU_MIN = 1; 8 | 9 | public static Integer LFU_INIT_NUM = 1; 10 | 11 | } 12 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/constant/enums/CacheRemoveType.java: -------------------------------------------------------------------------------- 1 | package core.constant.enums; 2 | 3 | /** 4 | * 5 | * @author lujiaxin 6 | * @date 2023/5/8 7 | */ 8 | public enum CacheRemoveType { 9 | EXPIRE("expire", "过期"), 10 | EVICT("evict", "淘汰"), 11 | ; 12 | 13 | private final String code; 14 | 15 | private final String desc; 16 | 17 | 18 | CacheRemoveType(String code, String desc) { 19 | this.code = code; 20 | this.desc = desc; 21 | } 22 | 23 | public String code() { 24 | return code; 25 | } 26 | 27 | public String desc() { 28 | return desc; 29 | } 30 | 31 | @Override 32 | public String toString() { 33 | return "CacheRemoveType{" + 34 | "code='" + code + '\'' + 35 | ", desc='" + desc + '\'' + 36 | '}'; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/constant/enums/model/CacheEntry.java: -------------------------------------------------------------------------------- 1 | package core.constant.enums.model; 2 | 3 | import api.ICacheEntry; 4 | 5 | /** 6 | * 7 | * @author lujiaxin 8 | * @date 2023/5/8 9 | */ 10 | public class CacheEntry implements ICacheEntry { 11 | 12 | /** 13 | * key 14 | * @since 0.0.11 15 | */ 16 | private final K key; 17 | 18 | /** 19 | * value 20 | * @since 0.0.11 21 | */ 22 | private final V value; 23 | 24 | /** 25 | * 新建元素 26 | * @param key key 27 | * @param value value 28 | * @param 泛型 29 | * @param 泛型 30 | * @return 结果 31 | * @since 0.0.11 32 | */ 33 | public static CacheEntry of(final K key, 34 | final V value) { 35 | return new CacheEntry<>(key, value); 36 | } 37 | 38 | public CacheEntry(K key, V value) { 39 | this.key = key; 40 | this.value = value; 41 | } 42 | 43 | @Override 44 | public K key() { 45 | return key; 46 | } 47 | 48 | @Override 49 | public V value() { 50 | return value; 51 | } 52 | 53 | @Override 54 | public String toString() { 55 | return "EvictEntry{" + 56 | "key=" + key + 57 | ", value=" + value + 58 | '}'; 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/constant/enums/model/CircleListNode.java: -------------------------------------------------------------------------------- 1 | package core.constant.enums.model; 2 | 3 | /** 4 | * 5 | * @author lujiaxin 6 | * @date 2023/5/8 7 | */ 8 | public class CircleListNode { 9 | 10 | /** 11 | * 键 12 | * @since 0.0.15 13 | */ 14 | private K key; 15 | 16 | /** 17 | * 值 18 | * @since 0.0.15 19 | */ 20 | private V value = null; 21 | 22 | /** 23 | * 是否被访问过 24 | * @since 0.0.15 25 | */ 26 | private boolean accessFlag = false; 27 | 28 | /** 29 | * 后一个节点 30 | * @since 0.0.15 31 | */ 32 | private CircleListNode pre; 33 | 34 | /** 35 | * 后一个节点 36 | * @since 0.0.15 37 | */ 38 | private CircleListNode next; 39 | 40 | public CircleListNode(K key) { 41 | this.key = key; 42 | } 43 | 44 | public K key() { 45 | return key; 46 | } 47 | 48 | public CircleListNode key(K key) { 49 | this.key = key; 50 | return this; 51 | } 52 | 53 | public V value() { 54 | return value; 55 | } 56 | 57 | public CircleListNode value(V value) { 58 | this.value = value; 59 | return this; 60 | } 61 | 62 | public boolean accessFlag() { 63 | return accessFlag; 64 | } 65 | 66 | public CircleListNode accessFlag(boolean accessFlag) { 67 | this.accessFlag = accessFlag; 68 | return this; 69 | } 70 | 71 | public CircleListNode pre() { 72 | return pre; 73 | } 74 | 75 | public CircleListNode pre(CircleListNode pre) { 76 | this.pre = pre; 77 | return this; 78 | } 79 | 80 | public CircleListNode next() { 81 | return next; 82 | } 83 | 84 | public CircleListNode next(CircleListNode next) { 85 | this.next = next; 86 | return this; 87 | } 88 | 89 | @Override 90 | public String toString() { 91 | return "CircleListNode{" + 92 | "key=" + key + 93 | ", value=" + value + 94 | ", accessFlag=" + accessFlag + 95 | ", pre=" + pre + 96 | ", next=" + next + 97 | '}'; 98 | } 99 | 100 | } 101 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/constant/enums/model/DoubleListNode.java: -------------------------------------------------------------------------------- 1 | package core.constant.enums.model; 2 | 3 | /** 4 | * 5 | * @author lujiaxin 6 | * @date 2023/5/8 7 | */ 8 | public class DoubleListNode { 9 | 10 | /** 11 | * 键 12 | * @since 0.0.12 13 | */ 14 | private K key; 15 | 16 | /** 17 | * 值 18 | * @since 0.0.12 19 | */ 20 | private V value; 21 | 22 | /** 23 | * 前一个节点 24 | * @since 0.0.12 25 | */ 26 | private DoubleListNode pre; 27 | 28 | /** 29 | * 后一个节点 30 | * @since 0.0.12 31 | */ 32 | private DoubleListNode next; 33 | 34 | public K key() { 35 | return key; 36 | } 37 | 38 | public DoubleListNode key(K key) { 39 | this.key = key; 40 | return this; 41 | } 42 | 43 | public V value() { 44 | return value; 45 | } 46 | 47 | public DoubleListNode value(V value) { 48 | this.value = value; 49 | return this; 50 | } 51 | 52 | public DoubleListNode pre() { 53 | return pre; 54 | } 55 | 56 | public DoubleListNode pre(DoubleListNode pre) { 57 | this.pre = pre; 58 | return this; 59 | } 60 | 61 | public DoubleListNode next() { 62 | return next; 63 | } 64 | 65 | public DoubleListNode next(DoubleListNode next) { 66 | this.next = next; 67 | return this; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/constant/enums/model/FreqNode.java: -------------------------------------------------------------------------------- 1 | package core.constant.enums.model; 2 | 3 | import java.util.Objects; 4 | 5 | /** 6 | * 7 | * @author lujiaxin 8 | * @date 2023/5/8 9 | */ 10 | public class FreqNode { 11 | 12 | /** 13 | * 键 14 | * @since 0.0.14 15 | */ 16 | private K key; 17 | 18 | /** 19 | * 值 20 | * @since 0.0.14 21 | */ 22 | private V value = null; 23 | 24 | /** 25 | * 频率 26 | * @since 0.0.14 27 | */ 28 | private int frequency = 1; 29 | 30 | public FreqNode(K key) { 31 | this.key = key; 32 | } 33 | 34 | public K key() { 35 | return key; 36 | } 37 | 38 | public FreqNode key(K key) { 39 | this.key = key; 40 | return this; 41 | } 42 | 43 | public V value() { 44 | return value; 45 | } 46 | 47 | public FreqNode value(V value) { 48 | this.value = value; 49 | return this; 50 | } 51 | 52 | public int frequency() { 53 | return frequency; 54 | } 55 | 56 | public FreqNode frequency(int frequency) { 57 | this.frequency = frequency; 58 | return this; 59 | } 60 | 61 | @Override 62 | public String toString() { 63 | return "FreqNode{" + 64 | "key=" + key + 65 | ", value=" + value + 66 | ", frequency=" + frequency + 67 | '}'; 68 | } 69 | 70 | @Override 71 | public boolean equals(Object o) { 72 | if (this == o) { 73 | return true; 74 | } 75 | if (o == null || getClass() != o.getClass()) { 76 | return false; 77 | } 78 | FreqNode freqNode = (FreqNode) o; 79 | return frequency == freqNode.frequency && 80 | Objects.equals(key, freqNode.key) && 81 | Objects.equals(value, freqNode.value); 82 | } 83 | 84 | @Override 85 | public int hashCode() { 86 | return Objects.hash(key, value, frequency); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/constant/enums/model/PersistAofEntry.java: -------------------------------------------------------------------------------- 1 | package core.constant.enums.model; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * 7 | * @author lujiaxin 8 | * @date 2023/5/8 9 | */ 10 | public class PersistAofEntry { 11 | 12 | /** 13 | * 参数信息 14 | * @since 0.0.10 15 | */ 16 | private Object[] params; 17 | 18 | /** 19 | * 方法名称 20 | * @since 0.0.10 21 | */ 22 | private String methodName; 23 | 24 | /** 25 | * 新建对象实例 26 | * @return this 27 | * @since 0.0.10 28 | */ 29 | public static PersistAofEntry newInstance() { 30 | return new PersistAofEntry(); 31 | } 32 | 33 | public Object[] getParams() { 34 | return params; 35 | } 36 | 37 | public void setParams(Object[] params) { 38 | this.params = params; 39 | } 40 | 41 | public String getMethodName() { 42 | return methodName; 43 | } 44 | 45 | public void setMethodName(String methodName) { 46 | this.methodName = methodName; 47 | } 48 | 49 | @Override 50 | public String toString() { 51 | return "PersistAofEntry{" + 52 | "params=" + Arrays.toString(params) + 53 | ", methodName='" + methodName + '\'' + 54 | '}'; 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/constant/enums/model/PersistRdbEntry.java: -------------------------------------------------------------------------------- 1 | package core.constant.enums.model; 2 | 3 | /** 4 | * 5 | * @author lujiaxin 6 | * @date 2023/5/8 7 | */ 8 | public class PersistRdbEntry { 9 | 10 | /** 11 | * key 12 | * @since 0.0.8 13 | */ 14 | private K key; 15 | 16 | /** 17 | * value 18 | * @since 0.0.8 19 | */ 20 | private V value; 21 | 22 | /** 23 | * expire 24 | * @since 0.0.8 25 | */ 26 | private Long expire; 27 | 28 | public K getKey() { 29 | return key; 30 | } 31 | 32 | public void setKey(K key) { 33 | this.key = key; 34 | } 35 | 36 | public V getValue() { 37 | return value; 38 | } 39 | 40 | public void setValue(V value) { 41 | this.value = value; 42 | } 43 | 44 | public Long getExpire() { 45 | return expire; 46 | } 47 | 48 | public void setExpire(Long expire) { 49 | this.expire = expire; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/constant/package-info.java: -------------------------------------------------------------------------------- 1 | package core.constant; -------------------------------------------------------------------------------- /CR-core/src/main/java/core/core/CR.java: -------------------------------------------------------------------------------- 1 | package core.core; 2 | 3 | import core.Context.Evict.Evict; 4 | import core.Context.Evict.EvictFIFO; 5 | import core.Context.Expire.Expire; 6 | import core.KV.Key; 7 | import core.KV.Values.*; 8 | import java.util.*; 9 | 10 | /** 11 | * 核心 12 | * @author lujiaxin 13 | * @date 2023/5/9 14 | */ 15 | //缓存核心类 16 | public class CR { 17 | 18 | //默认配置 19 | private Map map; 20 | private StringValue sValue; 21 | private ListValue listValue; 22 | private HashValue hashValue; 23 | private Evict evict; 24 | private Expire expire; 25 | private SetValue setValue; 26 | private ZSetValue zsetValue; 27 | 28 | /** 29 | * 构造 30 | */ 31 | public CR() { 32 | init(); 33 | } 34 | 35 | /** 36 | * 指定过期策略构造 37 | * @param expire 38 | */ 39 | public CR(Expire expire){ 40 | this.expire = expire; 41 | } 42 | 43 | /** 44 | * 指定淘汰策略构造 45 | * @param evict 46 | */ 47 | public CR(Evict evict){ 48 | this.evict = evict; 49 | } 50 | 51 | /** 52 | * 指定过期、淘汰策略构造 53 | * @param expire 54 | * @param evict 55 | */ 56 | public CR(Expire expire,Evict evict){ 57 | this.evict = evict; 58 | this.expire = expire; 59 | } 60 | 61 | //初始化 62 | public void init() { 63 | //加载数据结构 64 | this.map = new HashMap(); 65 | CRcontext crc = new CRcontext(evict,expire,map); 66 | this.sValue = new StringValue(crc); 67 | this.listValue = new ListValue(crc); 68 | this.hashValue = new HashValue(crc); 69 | this.setValue = new SetValue(crc); 70 | this.zsetValue = new ZSetValue(crc); 71 | //设置淘汰、过期策略 72 | this.evict = new EvictFIFO(); 73 | // 初始化持久化 74 | } 75 | 76 | public Value opsForString(){ 77 | return sValue; 78 | } 79 | 80 | public Value opsForList(){ 81 | return listValue; 82 | } 83 | 84 | public Value opsForHash(){ 85 | return hashValue; 86 | } 87 | 88 | public Value opsForSet(){ 89 | return setValue; 90 | } 91 | 92 | public Value opsForZset(){ 93 | return zsetValue; 94 | } 95 | 96 | 97 | } 98 | 99 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/core/CRcontext.java: -------------------------------------------------------------------------------- 1 | package core.core; 2 | 3 | import core.Context.Evict.Evict; 4 | import core.Context.Expire.Expire; 5 | 6 | import java.util.Map; 7 | 8 | /** 9 | * 上下文配置信息 10 | * @author lujiaxin 11 | * @date 2023/5/10 12 | */ 13 | public class CRcontext { 14 | 15 | //驱除策略 16 | private Evict evict; 17 | //过期策略 18 | private Expire expire; 19 | 20 | //map 21 | private Map map; 22 | 23 | public CRcontext(Evict evict, Expire expire,Map map) { 24 | this.evict = evict; 25 | this.expire = expire; 26 | this.map = map; 27 | } 28 | 29 | public Evict getEvict() { 30 | return evict; 31 | } 32 | 33 | public void setEvict(Evict evict) { 34 | this.evict = evict; 35 | } 36 | 37 | public Expire getExpire() { 38 | return expire; 39 | } 40 | 41 | public void setExpire(Expire expire) { 42 | this.expire = expire; 43 | } 44 | 45 | public Map getMap() { 46 | return map; 47 | } 48 | 49 | public void setMap(Map map) { 50 | this.map = map; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/core/Cache.java: -------------------------------------------------------------------------------- 1 | package core.core; 2 | 3 | import annotation.CacheInterceptor; 4 | import api.*; 5 | import core.KV.Values.*; 6 | import core.constant.enums.CacheRemoveType; 7 | import core.core.exception.CacheRuntimeException; 8 | import core.support.evict.CacheEvictContext; 9 | import core.support.expire.CacheExpire; 10 | import core.support.listener.remove.CacheRemoveListenerContext; 11 | import core.support.persist.InnerCachePersist; 12 | import core.support.proxy.CacheProxy; 13 | import com.github.houbb.heaven.util.lang.ObjectUtil; 14 | 15 | import java.util.*; 16 | /** 17 | * 18 | * @author lujiaxin 19 | * @date 2023/5/8 20 | */ 21 | //缓存核心类 22 | public class Cache implements ICache { 23 | 24 | //初始化 25 | public void init() { 26 | //加载数据结构 27 | this.sValue = new StringValue(); 28 | this.listValue = new ListValue(); 29 | this.hashValue = new HashValue(); 30 | this.setValue = new SetValue(); 31 | this.zsetValue = new ZSetValue(); 32 | //设置过期策略 33 | this.expire = new CacheExpire<>(this); 34 | this.load.load(this); 35 | 36 | // 初始化持久化 37 | if(this.persist != null) { 38 | new InnerCachePersist<>(this, persist); 39 | } 40 | } 41 | 42 | public Value opsForString(){ 43 | return sValue; 44 | } 45 | 46 | public Value opsForList(){ 47 | return listValue; 48 | } 49 | 50 | public Value opsForHash(){ 51 | return hashValue; 52 | } 53 | 54 | public Value opsForSet(){ 55 | return setValue; 56 | } 57 | 58 | public Value opsForZset(){ 59 | return zsetValue; 60 | } 61 | 62 | 63 | //方法: get 64 | //同时刷新清除过期数据 65 | @Override 66 | @CacheInterceptor(evict = true) 67 | @SuppressWarnings("unchecked") 68 | public V get(Object key) { 69 | //1. 刷新所有过期信息 70 | K genericKey = (K) key; 71 | this.expire.refreshExpire(Collections.singletonList(genericKey)); 72 | 73 | return map.get(key); 74 | } 75 | 76 | //方法: put 77 | @Override 78 | @CacheInterceptor(aof = true, evict = true) 79 | public V put(K key, V value) { 80 | //1.1 尝试驱除 81 | CacheEvictContext context = new CacheEvictContext<>(); 82 | context.key(key).size(sizeLimit).cache(this); 83 | 84 | ICacheEntry evictEntry = evict.evict(context); 85 | 86 | // 添加拦截器调用 87 | if(ObjectUtil.isNotNull(evictEntry)) { 88 | // 执行淘汰监听器 89 | ICacheRemoveListenerContext removeListenerContext = CacheRemoveListenerContext.newInstance().key(evictEntry.key()) 90 | .value(evictEntry.value()) 91 | .type(CacheRemoveType.EVICT.code()); 92 | for(ICacheRemoveListener listener : context.cache().removeListeners()) { 93 | listener.listen(removeListenerContext); 94 | } 95 | } 96 | 97 | //2. 判断驱除后的信息 98 | if(isSizeLimit()) { 99 | throw new CacheRuntimeException("当前队列已满,数据添加失败!"); 100 | } 101 | 102 | //3. 执行添加 103 | return map.put(key, value); 104 | } 105 | 106 | //1.1方法:设置过期时间 107 | @Override 108 | @CacheInterceptor 109 | public ICache expire(K key, long timeInMills) { 110 | long expireTime = System.currentTimeMillis() + timeInMills; 111 | 112 | // 使用代理调用 113 | Cache cachePoxy = (Cache) CacheProxy.getProxy(this); 114 | return cachePoxy.expireAt(key, expireTime); 115 | } 116 | 117 | //1.1方法: 指定时间过期 118 | @Override 119 | @CacheInterceptor(aof = true) 120 | public ICache expireAt(K key, long timeInMills) { 121 | this.expire.expire(key, timeInMills); 122 | return this; 123 | } 124 | 125 | //方法: 获取过期策略 126 | @Override 127 | @CacheInterceptor 128 | public ICacheExpire expire() { 129 | return this.expire; 130 | } 131 | 132 | //方法: 获取长度 133 | @Override 134 | @CacheInterceptor(refresh = true) 135 | public int size() { 136 | return map.size(); 137 | } 138 | 139 | //方法: 判断是否为空 140 | @Override 141 | @CacheInterceptor(refresh = true) 142 | public boolean isEmpty() { 143 | return map.isEmpty(); 144 | } 145 | 146 | //方法: 是否包含key 147 | @Override 148 | @CacheInterceptor(refresh = true, evict = true) 149 | public boolean containsKey(Object key) { 150 | return map.containsKey(key); 151 | } 152 | 153 | //方法: 是否包含value 154 | @Override 155 | @CacheInterceptor(refresh = true) 156 | public boolean containsValue(Object value) { 157 | return map.containsValue(value); 158 | } 159 | 160 | //方法: 判断是否数据满了 161 | private boolean isSizeLimit() { 162 | final int currentSize = this.size(); 163 | return currentSize >= this.sizeLimit; 164 | } 165 | 166 | //方法: 移除key 167 | @Override 168 | @CacheInterceptor(aof = true, evict = true) 169 | public V remove(Object key) { 170 | return map.remove(key); 171 | } 172 | 173 | //方法: 一次性put多个 174 | @Override 175 | @CacheInterceptor(aof = true) 176 | public void putAll(Map m) { 177 | map.putAll(m); 178 | } 179 | 180 | //方法: 清除所有 181 | @Override 182 | @CacheInterceptor(refresh = true, aof = true) 183 | public void clear() { 184 | map.clear(); 185 | } 186 | 187 | //方法: 取出key的set集合 188 | @Override 189 | @CacheInterceptor(refresh = true) 190 | public Set keySet() { 191 | return map.keySet(); 192 | } 193 | 194 | //方法: 取出value的集合 195 | @Override 196 | @CacheInterceptor(refresh = true) 197 | public Collection values() { 198 | return map.values(); 199 | } 200 | 201 | //方法: 取出entry的set集合 202 | @Override 203 | @CacheInterceptor(refresh = true) 204 | public Set> entrySet() { 205 | return map.entrySet(); 206 | } 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | //默认配置 215 | private Map map; 216 | private int sizeLimit; 217 | private ICacheEvict evict; 218 | private ICacheExpire expire; 219 | private List> removeListeners; 220 | private List slowListeners; 221 | private ICacheLoad load; 222 | private ICachePersist persist; 223 | private StringValue sValue; 224 | private ListValue listValue; 225 | private HashValue hashValue; 226 | private SetValue setValue; 227 | private ZSetValue zsetValue; 228 | 229 | //自定义配置 230 | public Cache map(Map map) { 231 | this.map = map; 232 | return this; 233 | } 234 | public Cache sizeLimit(int sizeLimit) { 235 | this.sizeLimit = sizeLimit; 236 | return this; 237 | } 238 | public Cache evict(ICacheEvict cacheEvict) { 239 | this.evict = cacheEvict; 240 | return this; 241 | } 242 | @Override 243 | public ICachePersist persist() { 244 | return persist; 245 | } 246 | @Override 247 | public ICacheEvict evict() { 248 | return this.evict; 249 | } 250 | public void persist(ICachePersist persist) { 251 | this.persist = persist; 252 | } 253 | @Override 254 | public List> removeListeners() { 255 | return removeListeners; 256 | } 257 | public Cache removeListeners(List> removeListeners) { 258 | this.removeListeners = removeListeners; 259 | return this; 260 | } 261 | @Override 262 | public List slowListeners() { 263 | return slowListeners; 264 | } 265 | public Cache slowListeners(List slowListeners) { 266 | this.slowListeners = slowListeners; 267 | return this; 268 | } 269 | @Override 270 | public ICacheLoad load() { 271 | return load; 272 | } 273 | public Cache load(ICacheLoad load) { 274 | this.load = load; 275 | return this; 276 | } 277 | 278 | } 279 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/core/CacheContext.java: -------------------------------------------------------------------------------- 1 | package core.core; 2 | 3 | import api.ICacheContext; 4 | import api.ICacheEvict; 5 | 6 | import java.util.Map; 7 | 8 | 9 | //介绍: 缓存上下文 10 | //内容: map 数据 11 | // size 大小 12 | // cacheEvict 驱逐策略 13 | /** 14 | * 15 | * @author lujiaxin 16 | * @date 2023/5/8 17 | */ 18 | public class CacheContext implements ICacheContext { 19 | 20 | //map数据 21 | private Map map; 22 | 23 | 24 | //大小限制 25 | private int size; 26 | 27 | //驱逐策略 28 | private ICacheEvict cacheEvict; 29 | 30 | //获取上下文map数据 31 | @Override 32 | public Map map() { 33 | return map; 34 | } 35 | 36 | //设置上下文map数据 37 | public CacheContext map(Map map) { 38 | this.map = map; 39 | return this; 40 | } 41 | 42 | //获取上下文数据长度 43 | @Override 44 | public int size() { 45 | return size; 46 | } 47 | 48 | //设置上下文数据长度 49 | public CacheContext size(int size) { 50 | this.size = size; 51 | return this; 52 | } 53 | 54 | //获取上下文驱逐策略 55 | @Override 56 | public ICacheEvict cacheEvict() { 57 | return cacheEvict; 58 | } 59 | 60 | //设置上下文驱逐策略 61 | public CacheContext cacheEvict(ICacheEvict cacheEvict) { 62 | this.cacheEvict = cacheEvict; 63 | return this; 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/core/exception/CRRunTimeException.java: -------------------------------------------------------------------------------- 1 | package core.core.exception; 2 | 3 | /** 4 | * 自定义异常 5 | * @author lujiaxin 6 | * @date 2023/5/11 7 | */ 8 | public class CRRunTimeException extends Exception{ 9 | 10 | private ExceptionCouple couple; 11 | 12 | public CRRunTimeException(ExceptionCouple couple) { 13 | this.couple = couple; 14 | } 15 | 16 | public CRRunTimeException() { 17 | } 18 | 19 | public ExceptionCouple getCouple() { 20 | return couple; 21 | } 22 | 23 | public void setCouple(ExceptionCouple couple) { 24 | this.couple = couple; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/core/exception/CacheRuntimeException.java: -------------------------------------------------------------------------------- 1 | package core.core.exception; 2 | 3 | /** 4 | * 5 | * @author lujiaxin 6 | * @date 2023/5/8 7 | */ 8 | public class CacheRuntimeException extends RuntimeException { 9 | 10 | public CacheRuntimeException() { 11 | } 12 | 13 | public CacheRuntimeException(String message) { 14 | super(message); 15 | } 16 | 17 | public CacheRuntimeException(String message, Throwable cause) { 18 | super(message, cause); 19 | } 20 | 21 | public CacheRuntimeException(Throwable cause) { 22 | super(cause); 23 | } 24 | 25 | public CacheRuntimeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { 26 | super(message, cause, enableSuppression, writableStackTrace); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/core/exception/ExceptionCode.java: -------------------------------------------------------------------------------- 1 | package core.core.exception; 2 | 3 | /** 4 | * 异常编码 5 | * 便于统一管理 6 | * @author lujiaxin 7 | * @date 2023/5/11 8 | */ 9 | public class ExceptionCode { 10 | 11 | public static ExceptionCouple KEY_FORMAT_ERROR = new ExceptionCouple("输入Key格式错误!",101); 12 | public static ExceptionCouple KEY_NOTFIND_ERROR = new ExceptionCouple("Key不存在!",102); 13 | public static ExceptionCouple VALUE_FORMAT_ERROR = new ExceptionCouple("Value格式错误!!",103); 14 | public static ExceptionCouple KEY_VALUE_FORMAT_ERROR = new ExceptionCouple("Key或Value格式错误!!",104); 15 | public static ExceptionCouple LFU_MIN_NOTFIND = new ExceptionCouple("未找到使用频次最小的!",105); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/core/exception/ExceptionCouple.java: -------------------------------------------------------------------------------- 1 | package core.core.exception; 2 | 3 | /** 4 | * 异常信息封装 5 | * @author lujiaxin 6 | * @date 2023/5/10 7 | */ 8 | public class ExceptionCouple { 9 | 10 | private String message; 11 | private Integer code; 12 | 13 | public String getMessage() { 14 | return message; 15 | } 16 | 17 | public void setMessage(String message) { 18 | this.message = message; 19 | } 20 | 21 | public Integer getCode() { 22 | return code; 23 | } 24 | 25 | public void setCode(Integer code) { 26 | this.code = code; 27 | } 28 | 29 | public ExceptionCouple() { 30 | } 31 | 32 | public ExceptionCouple(String message, Integer code) { 33 | this.message = message; 34 | this.code = code; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/core/util/GlobalUtils.java: -------------------------------------------------------------------------------- 1 | package core.core.util; 2 | 3 | import com.github.houbb.heaven.util.lang.ObjectUtil; 4 | import com.github.houbb.heaven.util.lang.StringUtil; 5 | import core.Context.Evict.Evict; 6 | import core.Context.Evict.EvictLFU; 7 | import core.KV.Key; 8 | import core.core.CRcontext; 9 | 10 | import java.util.Map; 11 | 12 | /** 13 | * 参数校验工具类 14 | * @author lujiaxin 15 | * @date 2023/5/10 16 | */ 17 | public class GlobalUtils { 18 | 19 | /** 20 | * 单个参数校验 21 | * @param o1 22 | * @return 23 | */ 24 | public static boolean pc(Object o1){ 25 | if( o1 == null || ObjectUtil.isNull(o1) || StringUtil.isBlank(o1.toString()) ){ 26 | return false; 27 | } 28 | return true; 29 | } 30 | 31 | /** 32 | * 双参数校验 33 | * @param o1 34 | * @param o2 35 | * @return 36 | */ 37 | public static boolean pc(Object o1,Object o2){ 38 | if( o1 == null || ObjectUtil.isNull(o1) || o1.getClass() == null || 39 | o2 == null || ObjectUtil.isNull(o2) || o2.getClass() == null){ 40 | return false; 41 | } 42 | return true; 43 | } 44 | 45 | /** 46 | * 封装自增代码 47 | * @param key 48 | * @param crc 49 | * @param map 50 | */ 51 | public static void doIncrease(Key key, CRcontext crc, Map map){ 52 | 53 | if(crc.getEvict().getClass().equals(EvictLFU.class)){ 54 | EvictLFU evict = (EvictLFU) crc.getEvict(); 55 | evict.doIncrease(key,map.get(key)); 56 | } 57 | 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/evict/AbstractCacheEvict.java: -------------------------------------------------------------------------------- 1 | package core.support.evict; 2 | 3 | import api.ICacheEntry; 4 | import api.ICacheEvict; 5 | import api.ICacheEvictContext; 6 | 7 | /** 8 | * 丢弃策略-抽象实现类 9 | * @author lujiaxin 10 | * @date 2023/5/8 11 | */ 12 | public abstract class AbstractCacheEvict implements ICacheEvict { 13 | 14 | @Override 15 | public ICacheEntry evict(ICacheEvictContext context) { 16 | //3. 返回结果 17 | return doEvict(context); 18 | } 19 | 20 | /** 21 | * 执行移除 22 | * @param context 上下文 23 | * @return 结果 24 | * @since 0.0.11 25 | */ 26 | protected abstract ICacheEntry doEvict(ICacheEvictContext context); 27 | 28 | @Override 29 | public void updateKey(K key) { 30 | 31 | } 32 | 33 | @Override 34 | public void removeKey(K key) { 35 | 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/evict/CacheEvictClock.java: -------------------------------------------------------------------------------- 1 | package core.support.evict; 2 | 3 | import api.ICache; 4 | import api.ICacheEntry; 5 | import api.ICacheEvictContext; 6 | //import core.model.CacheEntry; 7 | import core.support.struct.lru.ILruMap; 8 | import core.support.struct.lru.impl.LruMapCircleList; 9 | import api.ICache; 10 | import api.ICacheEntry; 11 | import api.ICacheEvictContext; 12 | import com.github.houbb.log.integration.core.Log; 13 | import com.github.houbb.log.integration.core.LogFactory; 14 | import core.constant.enums.model.CacheEntry; 15 | import core.support.struct.lru.ILruMap; 16 | import core.support.struct.lru.impl.LruMapCircleList; 17 | 18 | /** 19 | * 淘汰策略-clock 算法 20 | * @author lujiaxin 21 | * @date 2023/5/8 22 | */ 23 | public class CacheEvictClock extends AbstractCacheEvict { 24 | 25 | private static final Log log = LogFactory.getLog(CacheEvictClock.class); 26 | 27 | /** 28 | * 循环链表 29 | * @since 0.0.15 30 | */ 31 | private final ILruMap circleList; 32 | 33 | public CacheEvictClock() { 34 | this.circleList = new LruMapCircleList<>(); 35 | } 36 | 37 | @Override 38 | protected ICacheEntry doEvict(ICacheEvictContext context) { 39 | ICacheEntry result = null; 40 | final ICache cache = context.cache(); 41 | // 超过限制,移除队尾的元素 42 | if(cache.size() >= context.size()) { 43 | ICacheEntry evictEntry = circleList.removeEldest();; 44 | // 执行缓存移除操作 45 | final K evictKey = evictEntry.key(); 46 | V evictValue = cache.remove(evictKey); 47 | 48 | log.debug("基于 clock 算法淘汰 key:{}, value: {}", evictKey, evictValue); 49 | result = new CacheEntry<>(evictKey, evictValue); 50 | } 51 | 52 | return result; 53 | } 54 | 55 | 56 | /** 57 | * 更新信息 58 | * @param key 元素 59 | * @since 0.0.15 60 | */ 61 | @Override 62 | public void updateKey(final K key) { 63 | this.circleList.updateKey(key); 64 | } 65 | 66 | /** 67 | * 移除元素 68 | * 69 | * @param key 元素 70 | * @since 0.0.15 71 | */ 72 | @Override 73 | public void removeKey(final K key) { 74 | this.circleList.removeKey(key); 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/evict/CacheEvictContext.java: -------------------------------------------------------------------------------- 1 | package core.support.evict; 2 | 3 | import api.ICache; 4 | import api.ICacheEvictContext; 5 | 6 | /** 7 | * 驱除策略 8 | * 9 | * 1. 新加的 key 10 | * 2. map 实现 11 | * 3. 淘汰监听器 12 | * @author lujiaxin 13 | * @date 2023/5/8 14 | */ 15 | public class CacheEvictContext implements ICacheEvictContext { 16 | 17 | /** 18 | * 新加的 key 19 | * @since 0.0.2 20 | */ 21 | private K key; 22 | 23 | /** 24 | * cache 实现 25 | * @since 0.0.2 26 | */ 27 | private ICache cache; 28 | 29 | /** 30 | * 最大的大小 31 | * @since 0.0.2 32 | */ 33 | private int size; 34 | 35 | @Override 36 | public K key() { 37 | return key; 38 | } 39 | 40 | public CacheEvictContext key(K key) { 41 | this.key = key; 42 | return this; 43 | } 44 | 45 | @Override 46 | public ICache cache() { 47 | return cache; 48 | } 49 | 50 | public CacheEvictContext cache(ICache cache) { 51 | this.cache = cache; 52 | return this; 53 | } 54 | 55 | @Override 56 | public int size() { 57 | return size; 58 | } 59 | 60 | public CacheEvictContext size(int size) { 61 | this.size = size; 62 | return this; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/evict/CacheEvictFifo.java: -------------------------------------------------------------------------------- 1 | package core.support.evict; 2 | 3 | import api.ICache; 4 | import api.ICacheEvictContext; 5 | import core.constant.enums.model.CacheEntry; 6 | //import core.model.CacheEntry; 7 | 8 | import java.util.LinkedList; 9 | import java.util.Queue; 10 | 11 | /** 12 | * 丢弃策略-先进先出 13 | * @author lujiaxin 14 | * @date 2023/5/8 15 | */ 16 | public class CacheEvictFifo extends AbstractCacheEvict { 17 | 18 | //双向链表 储存 19 | private final Queue queue = new LinkedList<>(); 20 | 21 | @Override 22 | public CacheEntry doEvict(ICacheEvictContext context) { 23 | CacheEntry result = null; 24 | 25 | final ICache cache = context.cache(); 26 | // 超过限制,执行移除 27 | if(cache.size() >= context.size()) { 28 | K evictKey = queue.remove(); 29 | 30 | // 移除最开始的元素 31 | V evictValue = cache.remove(evictKey); 32 | result = new CacheEntry<>(evictKey, evictValue); 33 | } 34 | 35 | // 将新加的元素放入队尾 36 | final K key = context.key(); 37 | queue.add(key); 38 | 39 | return result; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/evict/CacheEvictLfu.java: -------------------------------------------------------------------------------- 1 | package core.support.evict; 2 | 3 | import api.ICache; 4 | import api.ICacheEntry; 5 | import api.ICacheEvictContext; 6 | //import core.exception.CacheRuntimeException; 7 | //import core.core.exception.CacheRuntimeException; 8 | import core.constant.enums.model.CacheEntry; 9 | import core.constant.enums.model.FreqNode; 10 | import core.core.exception.CacheRuntimeException; 11 | //import core.model.CacheEntry; 12 | //mport core.model.FreqNode; 13 | import com.github.houbb.heaven.util.lang.ObjectUtil; 14 | import com.github.houbb.heaven.util.util.CollectionUtil; 15 | import com.github.houbb.log.integration.core.Log; 16 | import com.github.houbb.log.integration.core.LogFactory; 17 | 18 | import java.util.HashMap; 19 | import java.util.LinkedHashSet; 20 | import java.util.Map; 21 | 22 | /** 23 | * 丢弃策略-LFU 最少使用频次 24 | * @author lujiaxin 25 | * @date 2023/5/8 26 | */ 27 | public class CacheEvictLfu extends AbstractCacheEvict { 28 | 29 | private static final Log log = LogFactory.getLog(CacheEvictLfu.class); 30 | 31 | /** 32 | * key 映射信息 33 | * @since 0.0.14 34 | */ 35 | private final Map> keyMap; 36 | 37 | /** 38 | * 频率 map 39 | * @since 0.0.14 40 | */ 41 | private final Map>> freqMap; 42 | 43 | /** 44 | * 45 | * 最小频率 46 | * @since 0.0.14 47 | */ 48 | private int minFreq; 49 | 50 | public CacheEvictLfu() { 51 | this.keyMap = new HashMap<>(); 52 | this.freqMap = new HashMap<>(); 53 | this.minFreq = 1; 54 | } 55 | 56 | @Override 57 | protected ICacheEntry doEvict(ICacheEvictContext context) { 58 | ICacheEntry result = null; 59 | final ICache cache = context.cache(); 60 | // 超过限制,移除频次最低的元素 61 | if(cache.size() >= context.size()) { 62 | FreqNode evictNode = this.getMinFreqNode(); 63 | K evictKey = evictNode.key(); 64 | V evictValue = cache.remove(evictKey); 65 | 66 | log.debug("淘汰最小频率信息, key: {}, value: {}, freq: {}", 67 | evictKey, evictValue, evictNode.frequency()); 68 | result = new CacheEntry<>(evictKey, evictValue); 69 | } 70 | 71 | return result; 72 | } 73 | 74 | /** 75 | * 获取最小频率的 节点 76 | * 77 | * @return 结果 78 | * @since 0.0.14 79 | */ 80 | private FreqNode getMinFreqNode() { 81 | LinkedHashSet> set = freqMap.get(minFreq); 82 | 83 | if(CollectionUtil.isNotEmpty(set)) { 84 | return set.iterator().next(); 85 | } 86 | 87 | throw new CacheRuntimeException("未发现最小频率的 Key"); 88 | } 89 | 90 | 91 | /** 92 | * 更新元素,更新 minFreq 信息 93 | * @param key 元素 94 | * @since 0.0.14 95 | */ 96 | @Override 97 | public void updateKey(final K key) { 98 | FreqNode freqNode = keyMap.get(key); 99 | 100 | //1. 已经存在 101 | if(ObjectUtil.isNotNull(freqNode)) { 102 | //1.1 移除原始的节点信息 103 | int frequency = freqNode.frequency(); 104 | LinkedHashSet> oldSet = freqMap.get(frequency); 105 | oldSet.remove(freqNode); 106 | //1.2 更新最小数据频率 107 | if (minFreq == frequency && oldSet.isEmpty()) { 108 | minFreq++; 109 | log.debug("minFreq 增加为:{}", minFreq); 110 | } 111 | //1.3 更新频率信息 112 | frequency++; 113 | freqNode.frequency(frequency); 114 | //1.4 放入新的集合 115 | this.addToFreqMap(frequency, freqNode); 116 | } else { 117 | //2. 不存在 118 | //2.1 构建新的元素 119 | FreqNode newNode = new FreqNode<>(key); 120 | 121 | //2.2 固定放入到频率为1的列表中 122 | this.addToFreqMap(1, newNode); 123 | 124 | //2.3 更新 minFreq 信息 125 | this.minFreq = 1; 126 | 127 | //2.4 添加到 keyMap 128 | this.keyMap.put(key, newNode); 129 | } 130 | } 131 | 132 | /** 133 | * 加入到频率 MAP 134 | * @param frequency 频率 135 | * @param freqNode 节点 136 | */ 137 | private void addToFreqMap(final int frequency, FreqNode freqNode) { 138 | LinkedHashSet> set = freqMap.get(frequency); 139 | if (set == null) { 140 | set = new LinkedHashSet<>(); 141 | } 142 | set.add(freqNode); 143 | freqMap.put(frequency, set); 144 | log.debug("freq={} 添加元素节点:{}", frequency, freqNode); 145 | } 146 | 147 | /** 148 | * 移除元素 149 | * 150 | * 1. 从 freqMap 中移除 151 | * 2. 从 keyMap 中移除 152 | * 3. 更新 minFreq 信息 153 | * 154 | * @param key 元素 155 | * @since 0.0.14 156 | */ 157 | @Override 158 | public void removeKey(final K key) { 159 | FreqNode freqNode = this.keyMap.remove(key); 160 | 161 | //1. 根据 key 获取频率 162 | int freq = freqNode.frequency(); 163 | LinkedHashSet> set = this.freqMap.get(freq); 164 | 165 | //2. 移除频率中对应的节点 166 | set.remove(freqNode); 167 | log.debug("freq={} 移除元素节点:{}", freq, freqNode); 168 | 169 | //3. 更新 minFreq 170 | if(CollectionUtil.isEmpty(set) && minFreq == freq) { 171 | minFreq--; 172 | log.debug("minFreq 降低为:{}", minFreq); 173 | } 174 | } 175 | 176 | } 177 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/evict/CacheEvictLru.java: -------------------------------------------------------------------------------- 1 | package core.support.evict; 2 | 3 | import api.ICache; 4 | import api.ICacheEntry; 5 | import api.ICacheEvictContext; 6 | //import core.model.CacheEntry; 7 | import com.github.houbb.log.integration.core.Log; 8 | import com.github.houbb.log.integration.core.LogFactory; 9 | import core.constant.enums.model.CacheEntry; 10 | 11 | import java.util.LinkedList; 12 | import java.util.List; 13 | 14 | /** 15 | * 丢弃策略-LRU 最近最少使用 16 | * @author lujiaxin 17 | * @date 2023/5/8 18 | */ 19 | public class CacheEvictLru extends AbstractCacheEvict { 20 | 21 | private static final Log log = LogFactory.getLog(CacheEvictLru.class); 22 | 23 | /** 24 | * list 信息 25 | * @since 0.0.11 26 | */ 27 | private final List list = new LinkedList<>(); 28 | 29 | @Override 30 | protected ICacheEntry doEvict(ICacheEvictContext context) { 31 | ICacheEntry result = null; 32 | final ICache cache = context.cache(); 33 | // 超过限制,移除队尾的元素 34 | if(cache.size() >= context.size()) { 35 | K evictKey = list.get(list.size()-1); 36 | V evictValue = cache.remove(evictKey); 37 | result = new CacheEntry<>(evictKey, evictValue); 38 | } 39 | 40 | return result; 41 | } 42 | 43 | 44 | /** 45 | * 放入元素 46 | * (1)删除已经存在的 47 | * (2)新元素放到元素头部 48 | * 49 | * @param key 元素 50 | * @since 0.0.11 51 | */ 52 | @Override 53 | public void updateKey(final K key) { 54 | this.list.remove(key); 55 | this.list.add(0, key); 56 | } 57 | 58 | /** 59 | * 移除元素 60 | * @param key 元素 61 | * @since 0.0.11 62 | */ 63 | @Override 64 | public void removeKey(final K key) { 65 | this.list.remove(key); 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/evict/CacheEvictLru2.java: -------------------------------------------------------------------------------- 1 | package core.support.evict; 2 | 3 | import api.ICache; 4 | import api.ICacheEntry; 5 | import api.ICacheEvictContext; 6 | //import core.model.CacheEntry; 7 | import core.constant.enums.model.CacheEntry; 8 | import core.support.struct.lru.ILruMap; 9 | import core.support.struct.lru.impl.LruMapDoubleList; 10 | import com.github.houbb.log.integration.core.Log; 11 | import com.github.houbb.log.integration.core.LogFactory; 12 | 13 | /** 14 | * 淘汰策略-LRU 最近最少使用 15 | * 16 | * 实现方式:Lru2 17 | * @author lujiaxin 18 | * @date 2023/5/8 19 | */ 20 | public class CacheEvictLru2 extends AbstractCacheEvict { 21 | 22 | private static final Log log = LogFactory.getLog(CacheEvictLru2.class); 23 | 24 | /** 25 | * 第一次访问的 lru 26 | * @since 0.0.13 27 | */ 28 | private final ILruMap firstLruMap; 29 | 30 | /** 31 | * 2次及其以上的 lru 32 | * @since 0.0.13 33 | */ 34 | private final ILruMap moreLruMap; 35 | 36 | public CacheEvictLru2() { 37 | this.firstLruMap = new LruMapDoubleList<>(); 38 | this.moreLruMap = new LruMapDoubleList<>(); 39 | } 40 | 41 | @Override 42 | protected ICacheEntry doEvict(ICacheEvictContext context) { 43 | ICacheEntry result = null; 44 | final ICache cache = context.cache(); 45 | // 超过限制,移除队尾的元素 46 | if(cache.size() >= context.size()) { 47 | ICacheEntry evictEntry = null; 48 | 49 | //1. firstLruMap 不为空,优先移除队列中元素 50 | if(!firstLruMap.isEmpty()) { 51 | evictEntry = firstLruMap.removeEldest(); 52 | log.debug("从 firstLruMap 中淘汰数据:{}", evictEntry); 53 | } else { 54 | //2. 否则从 moreLruMap 中淘汰数据 55 | evictEntry = moreLruMap.removeEldest(); 56 | log.debug("从 moreLruMap 中淘汰数据:{}", evictEntry); 57 | } 58 | 59 | // 执行缓存移除操作 60 | final K evictKey = evictEntry.key(); 61 | V evictValue = cache.remove(evictKey); 62 | result = new CacheEntry<>(evictKey, evictValue); 63 | } 64 | 65 | return result; 66 | } 67 | 68 | 69 | /** 70 | * 更新信息 71 | * 1. 如果 moreLruMap 已经存在,则处理 more 队列,先删除,再插入。 72 | * 2. 如果 firstLruMap 中已经存在,则处理 first 队列,先删除 firstLruMap,然后插入 Lru。 73 | * 1 和 2 是不同的场景,但是代码实际上是一样的,删除逻辑中做了二种场景的兼容。 74 | * 75 | * 3. 如果不在1、2中,说明是新元素,直接插入到 firstLruMap 的开始即可。 76 | * 77 | * @param key 元素 78 | * @since 0.0.13 79 | */ 80 | @Override 81 | public void updateKey(final K key) { 82 | //1. 元素已经在多次访问,或者第一次访问的 lru 中 83 | if(moreLruMap.contains(key) 84 | || firstLruMap.contains(key)) { 85 | //1.1 删除信息 86 | this.removeKey(key); 87 | 88 | //1.2 加入到多次 LRU 中 89 | moreLruMap.updateKey(key); 90 | log.debug("key: {} 多次访问,加入到 moreLruMap 中", key); 91 | } else { 92 | // 2. 加入到第一次访问 LRU 中 93 | firstLruMap.updateKey(key); 94 | log.debug("key: {} 为第一次访问,加入到 firstLruMap 中", key); 95 | } 96 | } 97 | 98 | /** 99 | * 移除元素 100 | * 101 | * 1. 多次 lru 中存在,删除 102 | * 2. 初次 lru 中存在,删除 103 | * 104 | * @param key 元素 105 | * @since 0.0.13 106 | */ 107 | @Override 108 | public void removeKey(final K key) { 109 | //1. 多次LRU 删除逻辑 110 | if(moreLruMap.contains(key)) { 111 | moreLruMap.removeKey(key); 112 | log.debug("key: {} 从 moreLruMap 中移除", key); 113 | } else { 114 | firstLruMap.removeKey(key); 115 | log.debug("key: {} 从 firstLruMap 中移除", key); 116 | } 117 | } 118 | 119 | } 120 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/evict/CacheEvictLru2Q.java: -------------------------------------------------------------------------------- 1 | package core.support.evict; 2 | 3 | import api.ICache; 4 | import api.ICacheEntry; 5 | import api.ICacheEvictContext; 6 | //import core.exception.CacheRuntimeException; 7 | import core.constant.enums.model.CacheEntry; 8 | import core.constant.enums.model.DoubleListNode; 9 | import core.core.exception.CacheRuntimeException; 10 | //import core.model.CacheEntry; 11 | //import core.model.DoubleListNode; 12 | import com.github.houbb.heaven.util.lang.ObjectUtil; 13 | import com.github.houbb.log.integration.core.Log; 14 | import com.github.houbb.log.integration.core.LogFactory; 15 | 16 | import java.util.HashMap; 17 | import java.util.LinkedList; 18 | import java.util.Map; 19 | import java.util.Queue; 20 | 21 | /** 22 | * 淘汰策略-LRU 最近最少使用 23 | * 24 | * 实现方式:Lru + FIFO 25 | * @author lujiaxin 26 | * @date 2023/5/8 27 | */ 28 | public class CacheEvictLru2Q extends AbstractCacheEvict { 29 | 30 | private static final Log log = LogFactory.getLog(CacheEvictLru2Q.class); 31 | 32 | /** 33 | * 队列大小限制 34 | * 35 | * 降低 O(n) 的消耗,避免耗时过长。 36 | * @since 0.0.13 37 | */ 38 | private static final int LIMIT_QUEUE_SIZE = 1024; 39 | 40 | /** 41 | * 第一次访问的队列 42 | * @since 0.0.13 43 | */ 44 | private Queue firstQueue; 45 | 46 | /** 47 | * 头结点 48 | * @since 0.0.13 49 | */ 50 | private DoubleListNode head; 51 | 52 | /** 53 | * 尾巴结点 54 | * @since 0.0.13 55 | */ 56 | private DoubleListNode tail; 57 | 58 | /** 59 | * map 信息 60 | * 61 | * key: 元素信息 62 | * value: 元素在 list 中对应的节点信息 63 | * @since 0.0.13 64 | */ 65 | private Map> lruIndexMap; 66 | 67 | public CacheEvictLru2Q() { 68 | this.firstQueue = new LinkedList<>(); 69 | this.lruIndexMap = new HashMap<>(); 70 | this.head = new DoubleListNode<>(); 71 | this.tail = new DoubleListNode<>(); 72 | 73 | this.head.next(this.tail); 74 | this.tail.pre(this.head); 75 | } 76 | 77 | @Override 78 | protected ICacheEntry doEvict(ICacheEvictContext context) { 79 | ICacheEntry result = null; 80 | final ICache cache = context.cache(); 81 | // 超过限制,移除队尾的元素 82 | if(cache.size() >= context.size()) { 83 | K evictKey = null; 84 | 85 | //1. firstQueue 不为空,优先移除队列中元素 86 | if(!firstQueue.isEmpty()) { 87 | evictKey = firstQueue.remove(); 88 | } else { 89 | // 获取尾巴节点的前一个元素 90 | DoubleListNode tailPre = this.tail.pre(); 91 | if(tailPre == this.head) { 92 | log.error("当前列表为空,无法进行删除"); 93 | throw new CacheRuntimeException("不可删除头结点!"); 94 | } 95 | 96 | evictKey = tailPre.key(); 97 | } 98 | 99 | // 执行移除操作 100 | V evictValue = cache.remove(evictKey); 101 | result = new CacheEntry<>(evictKey, evictValue); 102 | } 103 | 104 | return result; 105 | } 106 | 107 | 108 | /** 109 | * 放入元素 110 | * 1. 如果 lruIndexMap 已经存在,则处理 lru 队列,先删除,再插入。 111 | * 2. 如果 firstQueue 中已经存在,则处理 first 队列,先删除 firstQueue,然后插入 Lru。 112 | * 1 和 2 是不同的场景,但是代码实际上是一样的,删除逻辑中做了二种场景的兼容。 113 | * 114 | * 3. 如果不在1、2中,说明是新元素,直接插入到 firstQueue 的开始即可。 115 | * 116 | * @param key 元素 117 | * @since 0.0.13 118 | */ 119 | @Override 120 | public void updateKey(final K key) { 121 | //1.1 是否在 LRU MAP 中 122 | //1.2 是否在 firstQueue 中 123 | DoubleListNode node = lruIndexMap.get(key); 124 | if(ObjectUtil.isNotNull(node) 125 | || firstQueue.contains(key)) { 126 | //1.3 删除信息 127 | this.removeKey(key); 128 | 129 | //1.4 加入到 LRU 中 130 | this.addToLruMapHead(key); 131 | return; 132 | } 133 | 134 | //2. 直接加入到 firstQueue 队尾 135 | // if(firstQueue.size() >= LIMIT_QUEUE_SIZE) { 136 | // // 避免第一次访问的列表一直增长,移除队头的元素 137 | // firstQueue.remove(); 138 | // } 139 | firstQueue.add(key); 140 | } 141 | 142 | /** 143 | * 插入到 LRU Map 头部 144 | * @param key 元素 145 | * @since 0.0.13 146 | */ 147 | private void addToLruMapHead(final K key) { 148 | //2. 新元素插入到头部 149 | //head<->next 150 | //变成:head<->new<->next 151 | DoubleListNode newNode = new DoubleListNode<>(); 152 | newNode.key(key); 153 | 154 | DoubleListNode next = this.head.next(); 155 | this.head.next(newNode); 156 | newNode.pre(this.head); 157 | next.pre(newNode); 158 | newNode.next(next); 159 | 160 | //2.2 插入到 map 中 161 | lruIndexMap.put(key, newNode); 162 | } 163 | 164 | /** 165 | * 移除元素 166 | * 167 | * 1. 获取 map 中的元素 168 | * 2. 不存在直接返回,存在执行以下步骤: 169 | * 2.1 删除双向链表中的元素 170 | * 2.2 删除 map 中的元素 171 | * 172 | * @param key 元素 173 | * @since 0.0.13 174 | */ 175 | @Override 176 | public void removeKey(final K key) { 177 | DoubleListNode node = lruIndexMap.get(key); 178 | 179 | //1. LRU 删除逻辑 180 | if(ObjectUtil.isNotNull(node)) { 181 | // A<->B<->C 182 | // 删除 B,需要变成: A<->C 183 | DoubleListNode pre = node.pre(); 184 | DoubleListNode next = node.next(); 185 | 186 | pre.next(next); 187 | next.pre(pre); 188 | 189 | // 删除 map 中对应信息 190 | this.lruIndexMap.remove(node.key()); 191 | } else { 192 | //2. FIFO 删除逻辑(O(n) 时间复杂度) 193 | firstQueue.remove(key); 194 | } 195 | } 196 | 197 | } 198 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/evict/CacheEvictLruDoubleListMap.java: -------------------------------------------------------------------------------- 1 | package core.support.evict; 2 | 3 | import api.ICache; 4 | import api.ICacheEntry; 5 | import api.ICacheEvictContext; 6 | import core.constant.enums.model.CacheEntry; 7 | import core.core.exception.CacheRuntimeException; 8 | //import core.model.CacheEntry; 9 | //import core.model.DoubleListNode; 10 | import com.github.houbb.heaven.util.lang.ObjectUtil; 11 | import com.github.houbb.log.integration.core.Log; 12 | import com.github.houbb.log.integration.core.LogFactory; 13 | import core.constant.enums.model.DoubleListNode; 14 | 15 | import java.util.HashMap; 16 | import java.util.Map; 17 | 18 | /** 19 | * 丢弃策略-LRU 最近最少使用 20 | * 21 | * 实现方式:HashMap + list 实现策略 22 | * @author lujiaxin 23 | * @date 2023/5/8 24 | */ 25 | public class CacheEvictLruDoubleListMap extends AbstractCacheEvict { 26 | 27 | private static final Log log = LogFactory.getLog(CacheEvictLruDoubleListMap.class); 28 | 29 | 30 | /** 31 | * 头结点 32 | * @since 0.0.12 33 | */ 34 | private DoubleListNode head; 35 | 36 | /** 37 | * 尾巴结点 38 | * @since 0.0.12 39 | */ 40 | private DoubleListNode tail; 41 | 42 | /** 43 | * map 信息 44 | * 45 | * key: 元素信息 46 | * value: 元素在 list 中对应的节点信息 47 | * @since 0.0.12 48 | */ 49 | private Map> indexMap; 50 | 51 | public CacheEvictLruDoubleListMap() { 52 | this.indexMap = new HashMap<>(); 53 | this.head = new DoubleListNode<>(); 54 | this.tail = new DoubleListNode<>(); 55 | 56 | this.head.next(this.tail); 57 | this.tail.pre(this.head); 58 | } 59 | 60 | @Override 61 | protected ICacheEntry doEvict(ICacheEvictContext context) { 62 | ICacheEntry result = null; 63 | final ICache cache = context.cache(); 64 | // 超过限制,移除队尾的元素 65 | if(cache.size() >= context.size()) { 66 | // 获取尾巴节点的前一个元素 67 | DoubleListNode tailPre = this.tail.pre(); 68 | if(tailPre == this.head) { 69 | log.error("当前列表为空,无法进行删除"); 70 | throw new CacheRuntimeException("不可删除头结点!"); 71 | } 72 | 73 | K evictKey = tailPre.key(); 74 | V evictValue = cache.remove(evictKey); 75 | result = new CacheEntry<>(evictKey, evictValue); 76 | } 77 | 78 | return result; 79 | } 80 | 81 | 82 | /** 83 | * 放入元素 84 | * 85 | * (1)删除已经存在的 86 | * (2)新元素放到元素头部 87 | * 88 | * @param key 元素 89 | * @since 0.0.12 90 | */ 91 | @Override 92 | public void updateKey(final K key) { 93 | //1. 执行删除 94 | this.removeKey(key); 95 | 96 | //2. 新元素插入到头部 97 | //head<->next 98 | //变成:head<->new<->next 99 | DoubleListNode newNode = new DoubleListNode<>(); 100 | newNode.key(key); 101 | 102 | DoubleListNode next = this.head.next(); 103 | this.head.next(newNode); 104 | newNode.pre(this.head); 105 | next.pre(newNode); 106 | newNode.next(next); 107 | 108 | //2.2 插入到 map 中 109 | indexMap.put(key, newNode); 110 | } 111 | 112 | /** 113 | * 移除元素 114 | * 115 | * 1. 获取 map 中的元素 116 | * 2. 不存在直接返回,存在执行以下步骤: 117 | * 2.1 删除双向链表中的元素 118 | * 2.2 删除 map 中的元素 119 | * 120 | * @param key 元素 121 | * @since 0.0.12 122 | */ 123 | @Override 124 | public void removeKey(final K key) { 125 | DoubleListNode node = indexMap.get(key); 126 | 127 | if(ObjectUtil.isNull(node)) { 128 | return; 129 | } 130 | 131 | // 删除 list node 132 | // A<->B<->C 133 | // 删除 B,需要变成: A<->C 134 | DoubleListNode pre = node.pre(); 135 | DoubleListNode next = node.next(); 136 | 137 | pre.next(next); 138 | next.pre(pre); 139 | 140 | // 删除 map 中对应信息 141 | this.indexMap.remove(key); 142 | } 143 | 144 | } 145 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/evict/CacheEvictLruLinkedHashMap.java: -------------------------------------------------------------------------------- 1 | package core.support.evict; 2 | 3 | import api.ICache; 4 | import api.ICacheEntry; 5 | import api.ICacheEvict; 6 | import api.ICacheEvictContext; 7 | //import core.model.CacheEntry; 8 | import com.github.houbb.log.integration.core.Log; 9 | import com.github.houbb.log.integration.core.LogFactory; 10 | import core.constant.enums.model.CacheEntry; 11 | 12 | import java.util.LinkedHashMap; 13 | import java.util.Map; 14 | 15 | /** 16 | * 丢弃策略-LRU 最近最少使用 17 | * 18 | * 实现方式:LinkedHashMap 19 | * @author lujiaxin 20 | * @date 2023/5/8 21 | */ 22 | public class CacheEvictLruLinkedHashMap extends LinkedHashMap 23 | implements ICacheEvict { 24 | 25 | private static final Log log = LogFactory.getLog(CacheEvictLruDoubleListMap.class); 26 | 27 | /** 28 | * 是否移除标识 29 | * @since 0.0.12 30 | */ 31 | private volatile boolean removeFlag = false; 32 | 33 | /** 34 | * 最旧的一个元素 35 | * @since 0.0.12 36 | */ 37 | private transient Map.Entry eldest = null; 38 | 39 | public CacheEvictLruLinkedHashMap() { 40 | super(16, 0.75f, true); 41 | } 42 | 43 | @Override 44 | public ICacheEntry evict(ICacheEvictContext context) { 45 | ICacheEntry result = null; 46 | final ICache cache = context.cache(); 47 | // 超过限制,移除队尾的元素 48 | if(cache.size() >= context.size()) { 49 | removeFlag = true; 50 | 51 | // 执行 put 操作 52 | super.put(context.key(), null); 53 | 54 | // 构建淘汰的元素 55 | K evictKey = eldest.getKey(); 56 | V evictValue = cache.remove(evictKey); 57 | result = new CacheEntry<>(evictKey, evictValue); 58 | } else { 59 | removeFlag = false; 60 | } 61 | 62 | return result; 63 | } 64 | 65 | @Override 66 | protected boolean removeEldestEntry(Map.Entry eldest) { 67 | this.eldest = eldest; 68 | return removeFlag; 69 | } 70 | 71 | @Override 72 | public void updateKey(K key) { 73 | super.put(key, null); 74 | } 75 | 76 | @Override 77 | public void removeKey(K key) { 78 | super.remove(key); 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/evict/CacheEvictNone.java: -------------------------------------------------------------------------------- 1 | package core.support.evict; 2 | 3 | import api.ICacheEntry; 4 | import api.ICacheEvictContext; 5 | 6 | /** 7 | * 丢弃策略 8 | * @author lujiaxin 9 | * @date 2023/5/8 10 | */ 11 | public class CacheEvictNone extends AbstractCacheEvict { 12 | 13 | @Override 14 | protected ICacheEntry doEvict(ICacheEvictContext context) { 15 | return null; 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/evict/CacheEvicts.java: -------------------------------------------------------------------------------- 1 | package core.support.evict; 2 | 3 | import api.ICacheEvict; 4 | 5 | /** 6 | * 7 | * @author lujiaxin 8 | * @date 2023/5/8 9 | */ 10 | public final class CacheEvicts { 11 | 12 | private CacheEvicts(){} 13 | 14 | /** 15 | * 无策略 16 | * 17 | * @param key 18 | * @param value 19 | * @return 结果 20 | * @since 0.0.2 21 | */ 22 | public static ICacheEvict none() { 23 | return (ICacheEvict) new CacheEvictNone<>(); 24 | } 25 | 26 | /** 27 | * 先进先出 28 | * 29 | * @param key 30 | * @param value 31 | * @return 结果 32 | * @since 0.0.2 33 | */ 34 | public static ICacheEvict fifo() { 35 | return (ICacheEvict) new CacheEvictFifo<>(); 36 | } 37 | 38 | /** 39 | * LRU 驱除策略 40 | * 41 | * @param key 42 | * @param value 43 | * @return 结果 44 | * @since 0.0.11 45 | */ 46 | public static ICacheEvict lru() { 47 | return (ICacheEvict) new CacheEvictLru<>(); 48 | } 49 | 50 | /** 51 | * LRU 驱除策略 52 | * 53 | * 基于双向链表 + map 实现 54 | * @param key 55 | * @param value 56 | * @return 结果 57 | * @since 0.0.12 58 | */ 59 | public static ICacheEvict lruDoubleListMap() { 60 | return new CacheEvictLruDoubleListMap<>(); 61 | } 62 | 63 | 64 | /** 65 | * LRU 驱除策略 66 | * 67 | * 基于LinkedHashMap 68 | * @param key 69 | * @param value 70 | * @return 结果 71 | * @since 0.0.12 72 | */ 73 | public static ICacheEvict lruLinkedHashMap() { 74 | return new CacheEvictLruLinkedHashMap<>(); 75 | } 76 | 77 | /** 78 | * LRU 驱除策略 79 | * 80 | * 基于 2Q 实现 81 | * @param key 82 | * @param value 83 | * @return 结果 84 | * @since 0.0.13 85 | */ 86 | public static ICacheEvict lru2Q() { 87 | return new CacheEvictLru2Q<>(); 88 | } 89 | 90 | /** 91 | * LRU 驱除策略 92 | * 93 | * 基于 LRU-2 实现 94 | * @param key 95 | * @param value 96 | * @return 结果 97 | * @since 0.0.13 98 | */ 99 | public static ICacheEvict lru2() { 100 | return new CacheEvictLru2<>(); 101 | } 102 | 103 | /** 104 | * LFU 驱除策略 105 | * 106 | * 基于 LFU 实现 107 | * @param key 108 | * @param value 109 | * @return 结果 110 | * @since 0.0.14 111 | */ 112 | public static ICacheEvict lfu() { 113 | return new CacheEvictLfu<>(); 114 | } 115 | 116 | /** 117 | * 时钟算法 118 | * @param key 119 | * @param value 120 | * @return 结果 121 | * @since 0.0.15 122 | */ 123 | public static ICacheEvict clock() { 124 | return new CacheEvictClock<>(); 125 | } 126 | 127 | } 128 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/evict/package-info.java: -------------------------------------------------------------------------------- 1 | package core.support.evict; -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/expire/CacheExpire.java: -------------------------------------------------------------------------------- 1 | package core.support.expire; 2 | 3 | import api.ICache; 4 | import api.ICacheExpire; 5 | import api.ICacheRemoveListener; 6 | import api.ICacheRemoveListenerContext; 7 | import core.constant.enums.CacheRemoveType; 8 | import core.support.listener.remove.CacheRemoveListenerContext; 9 | import com.github.houbb.heaven.util.util.CollectionUtil; 10 | import com.github.houbb.heaven.util.util.MapUtil; 11 | 12 | import java.util.Collection; 13 | import java.util.HashMap; 14 | import java.util.Map; 15 | import java.util.concurrent.Executors; 16 | import java.util.concurrent.ScheduledExecutorService; 17 | import java.util.concurrent.TimeUnit; 18 | 19 | /** 20 | * 缓存过期-普通策略 21 | * @author lujiaxin 22 | * @date 2023/5/8 23 | */ 24 | //Cache在初始化时会调用CacheExpire带参构造,传入cache对象 25 | public class CacheExpire implements ICacheExpire { 26 | 27 | /** 28 | * 单次清空的数量限制 29 | * @since 0.0.3 30 | */ 31 | private static final int LIMIT = 100; 32 | 33 | /** 34 | * 过期 map 35 | * 36 | * 空间换时间 37 | * @since 0.0.3 38 | */ 39 | private final Map expireMap = new HashMap<>(); 40 | 41 | /** 42 | * 缓存实现 43 | * @since 0.0.3 44 | */ 45 | private final ICache cache; 46 | 47 | /** 48 | * 线程执行类 49 | * @since 0.0.3 50 | */ 51 | private static final ScheduledExecutorService EXECUTOR_SERVICE = Executors.newSingleThreadScheduledExecutor(); 52 | 53 | public CacheExpire(ICache cache) { 54 | this.cache = cache; 55 | this.init(); 56 | } 57 | 58 | /** 59 | * 初始化任务 60 | * @since 0.0.3 61 | */ 62 | private void init() { 63 | EXECUTOR_SERVICE.scheduleAtFixedRate(new ExpireThread(), 100, 100, TimeUnit.MILLISECONDS); 64 | } 65 | 66 | /** 67 | * 定时执行任务 68 | * @since 0.0.3 69 | */ 70 | private class ExpireThread implements Runnable { 71 | @Override 72 | public void run() { 73 | //1.判断是否为空 74 | if(MapUtil.isEmpty(expireMap)) { 75 | return; 76 | } 77 | 78 | //2. 获取 key 进行处理 79 | int count = 0; 80 | for(Map.Entry entry : expireMap.entrySet()) { 81 | if(count >= LIMIT) { 82 | return; 83 | } 84 | 85 | expireKey(entry.getKey(), entry.getValue()); 86 | count++; 87 | } 88 | } 89 | } 90 | 91 | @Override 92 | public void expire(K key, long expireAt) { 93 | expireMap.put(key, expireAt); 94 | } 95 | 96 | @Override 97 | public void refreshExpire(Collection keyList) { 98 | if(CollectionUtil.isEmpty(keyList)) { 99 | return; 100 | } 101 | 102 | // 判断大小,小的作为外循环。一般都是过期的 keys 比较小。 103 | if(keyList.size() <= expireMap.size()) { 104 | for(K key : keyList) { 105 | Long expireAt = expireMap.get(key); 106 | expireKey(key, expireAt); 107 | } 108 | } else { 109 | for(Map.Entry entry : expireMap.entrySet()) { 110 | this.expireKey(entry.getKey(), entry.getValue()); 111 | } 112 | } 113 | } 114 | 115 | @Override 116 | public Long expireTime(K key) { 117 | return expireMap.get(key); 118 | } 119 | 120 | 121 | //判断key是否过期,过期则删除key 122 | private void expireKey(final K key, final Long expireAt) { 123 | if(expireAt == null) { 124 | return; 125 | } 126 | 127 | long currentTime = System.currentTimeMillis(); 128 | if(currentTime >= expireAt) { 129 | expireMap.remove(key); 130 | // 再移除缓存,后续可以通过惰性删除做补偿 131 | V removeValue = cache.remove(key); 132 | 133 | // 执行淘汰监听器 134 | ICacheRemoveListenerContext removeListenerContext = CacheRemoveListenerContext.newInstance().key(key).value(removeValue).type(CacheRemoveType.EXPIRE.code()); 135 | for(ICacheRemoveListener listener : cache.removeListeners()) { 136 | listener.listen(removeListenerContext); 137 | } 138 | } 139 | } 140 | 141 | } 142 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/expire/CacheExpireRandom.java: -------------------------------------------------------------------------------- 1 | package core.support.expire; 2 | 3 | import api.ICache; 4 | import api.ICacheExpire; 5 | import api.ICacheRemoveListener; 6 | import api.ICacheRemoveListenerContext; 7 | import core.constant.enums.CacheRemoveType; 8 | //import core.exception.CacheRuntimeException; 9 | import core.core.exception.CacheRuntimeException; 10 | import core.support.listener.remove.CacheRemoveListenerContext; 11 | import com.github.houbb.heaven.util.util.CollectionUtil; 12 | import com.github.houbb.heaven.util.util.MapUtil; 13 | import com.github.houbb.log.integration.core.Log; 14 | import com.github.houbb.log.integration.core.LogFactory; 15 | 16 | import java.util.*; 17 | import java.util.concurrent.Executors; 18 | import java.util.concurrent.ScheduledExecutorService; 19 | import java.util.concurrent.ThreadLocalRandom; 20 | import java.util.concurrent.TimeUnit; 21 | 22 | /** 23 | * 缓存过期-普通策略随机 24 | * @author lujiaxin 25 | * @date 2023/5/8 26 | */ 27 | public class CacheExpireRandom implements ICacheExpire { 28 | 29 | private static final Log log = LogFactory.getLog(CacheExpireRandom.class); 30 | 31 | /** 32 | * 单次清空的数量限制 33 | * @since 0.0.16 34 | */ 35 | private static final int COUNT_LIMIT = 100; 36 | 37 | /** 38 | * 过期 map 39 | * 40 | * 空间换时间 41 | * @since 0.0.16 42 | */ 43 | private final Map expireMap = new HashMap<>(); 44 | 45 | /** 46 | * 缓存实现 47 | * @since 0.0.16 48 | */ 49 | private final ICache cache; 50 | 51 | /** 52 | * 是否启用快模式 53 | * @since 0.0.16 54 | */ 55 | private volatile boolean fastMode = false; 56 | 57 | /** 58 | * 线程执行类 59 | * @since 0.0.16 60 | */ 61 | private static final ScheduledExecutorService EXECUTOR_SERVICE = Executors.newSingleThreadScheduledExecutor(); 62 | 63 | public CacheExpireRandom(ICache cache) { 64 | this.cache = cache; 65 | this.init(); 66 | } 67 | 68 | /** 69 | * 初始化任务 70 | * @since 0.0.16 71 | */ 72 | private void init() { 73 | EXECUTOR_SERVICE.scheduleAtFixedRate(new ExpireThreadRandom(), 10, 10, TimeUnit.SECONDS); 74 | } 75 | 76 | /** 77 | * 定时执行任务 78 | * @since 0.0.16 79 | */ 80 | private class ExpireThreadRandom implements Runnable { 81 | @Override 82 | public void run() { 83 | //1.判断是否为空 84 | if(MapUtil.isEmpty(expireMap)) { 85 | log.info("expireMap 信息为空,直接跳过本次处理。"); 86 | return; 87 | } 88 | 89 | //2. 是否启用快模式 90 | if(fastMode) { 91 | expireKeys(10L); 92 | } 93 | 94 | //3. 缓慢模式 95 | expireKeys(100L); 96 | } 97 | } 98 | 99 | 100 | /** 101 | * 过期信息 102 | * @param timeoutMills 超时时间 103 | * @since 0.0.16 104 | */ 105 | private void expireKeys(final long timeoutMills) { 106 | // 设置超时时间 100ms 107 | final long timeLimit = System.currentTimeMillis() + timeoutMills; 108 | // 恢复 fastMode 109 | this.fastMode = false; 110 | 111 | //2. 获取 key 进行处理 112 | int count = 0; 113 | while (true) { 114 | //2.1 返回判断 115 | if(count >= COUNT_LIMIT) { 116 | log.info("过期淘汰次数已经达到最大次数: {},完成本次执行。", COUNT_LIMIT); 117 | return; 118 | } 119 | if(System.currentTimeMillis() >= timeLimit) { 120 | this.fastMode = true; 121 | log.info("过期淘汰已经达到限制时间,中断本次执行,设置 fastMode=true;"); 122 | return; 123 | } 124 | 125 | //2.2 随机过期 126 | K key = getRandomKey(); 127 | Long expireAt = expireMap.get(key); 128 | boolean expireFlag = expireKey(key, expireAt); 129 | log.debug("key: {} 过期执行结果 {}", key, expireFlag); 130 | 131 | //2.3 信息更新 132 | count++; 133 | } 134 | } 135 | 136 | 137 | /** 138 | * 随机获取一个 key 信息 139 | * @return 随机返回的 keys 140 | * @since 0.0.16 141 | */ 142 | private K getRandomKey() { 143 | Random random = ThreadLocalRandom.current(); 144 | 145 | Set keySet = expireMap.keySet(); 146 | List list = new ArrayList<>(keySet); 147 | int randomIndex = random.nextInt(list.size()); 148 | return list.get(randomIndex); 149 | } 150 | 151 | /** 152 | * 随机获取一个 key 信息 153 | * @return 随机返回的 keys 154 | * @since 0.0.16 155 | */ 156 | private K getRandomKey2() { 157 | Random random = ThreadLocalRandom.current(); 158 | int randomIndex = random.nextInt(expireMap.size()); 159 | 160 | // 遍历 keys 161 | Iterator iterator = expireMap.keySet().iterator(); 162 | int count = 0; 163 | while (iterator.hasNext()) { 164 | K key = iterator.next(); 165 | 166 | if(count == randomIndex) { 167 | return key; 168 | } 169 | count++; 170 | } 171 | 172 | // 正常逻辑不会到这里 173 | throw new CacheRuntimeException("对应信息不存在"); 174 | } 175 | 176 | /** 177 | * 批量获取多个 key 信息 178 | * @param sizeLimit 大小限制 179 | * @return 随机返回的 keys 180 | * @since 0.0.16 181 | */ 182 | private Set getRandomKeyBatch(final int sizeLimit) { 183 | Random random = ThreadLocalRandom.current(); 184 | int randomIndex = random.nextInt(expireMap.size()); 185 | 186 | // 遍历 keys 187 | Iterator iterator = expireMap.keySet().iterator(); 188 | int count = 0; 189 | 190 | Set keySet = new HashSet<>(); 191 | while (iterator.hasNext()) { 192 | // 判断列表大小 193 | if(keySet.size() >= sizeLimit) { 194 | return keySet; 195 | } 196 | 197 | K key = iterator.next(); 198 | // index 向后的位置,全部放进来。 199 | if(count >= randomIndex) { 200 | keySet.add(key); 201 | } 202 | count++; 203 | } 204 | 205 | // 正常逻辑不会到这里 206 | throw new CacheRuntimeException("对应信息不存在"); 207 | } 208 | 209 | @Override 210 | public void expire(K key, long expireAt) { 211 | expireMap.put(key, expireAt); 212 | } 213 | 214 | @Override 215 | public void refreshExpire(Collection keyList) { 216 | if(CollectionUtil.isEmpty(keyList)) { 217 | return; 218 | } 219 | 220 | // 判断大小,小的作为外循环。一般都是过期的 keys 比较小。 221 | if(keyList.size() <= expireMap.size()) { 222 | for(K key : keyList) { 223 | Long expireAt = expireMap.get(key); 224 | expireKey(key, expireAt); 225 | } 226 | } else { 227 | for(Map.Entry entry : expireMap.entrySet()) { 228 | this.expireKey(entry.getKey(), entry.getValue()); 229 | } 230 | } 231 | } 232 | 233 | @Override 234 | public Long expireTime(K key) { 235 | return expireMap.get(key); 236 | } 237 | 238 | /** 239 | * 过期处理 key 240 | * @param key key 241 | * @param expireAt 过期时间 242 | * @since 0.0.16 243 | * @return 是否执行过期 244 | */ 245 | private boolean expireKey(final K key, final Long expireAt) { 246 | if(expireAt == null) { 247 | return false; 248 | } 249 | 250 | long currentTime = System.currentTimeMillis(); 251 | if(currentTime >= expireAt) { 252 | expireMap.remove(key); 253 | // 再移除缓存,后续可以通过惰性删除做补偿 254 | V removeValue = cache.remove(key); 255 | 256 | // 执行淘汰监听器 257 | ICacheRemoveListenerContext removeListenerContext = CacheRemoveListenerContext.newInstance().key(key).value(removeValue).type(CacheRemoveType.EXPIRE.code()); 258 | for(ICacheRemoveListener listener : cache.removeListeners()) { 259 | listener.listen(removeListenerContext); 260 | } 261 | 262 | return true; 263 | } 264 | 265 | return false; 266 | } 267 | 268 | } 269 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/expire/CacheExpireSort.java: -------------------------------------------------------------------------------- 1 | package core.support.expire; 2 | 3 | import api.ICache; 4 | import api.ICacheExpire; 5 | import com.github.houbb.heaven.util.util.CollectionUtil; 6 | import com.github.houbb.heaven.util.util.MapUtil; 7 | 8 | import java.util.*; 9 | import java.util.concurrent.Executors; 10 | import java.util.concurrent.ScheduledExecutorService; 11 | import java.util.concurrent.TimeUnit; 12 | 13 | /** 14 | * 缓存过期-时间排序策略 15 | * 16 | * 优点:定时删除时不用做过多消耗 17 | * 缺点:惰性删除不友好 18 | * @author lujiaxin 19 | * @date 2023/5/8 20 | */ 21 | public class CacheExpireSort implements ICacheExpire { 22 | 23 | /** 24 | * 单次清空的数量限制 25 | * @since 0.0.3 26 | */ 27 | private static final int LIMIT = 100; 28 | 29 | /** 30 | * 排序缓存存储 31 | * 32 | * 使用按照时间排序的缓存处理。 33 | * @since 0.0.3 34 | */ 35 | private final Map> sortMap = new TreeMap<>(new Comparator() { 36 | @Override 37 | public int compare(Long o1, Long o2) { 38 | return (int) (o1-o2); 39 | } 40 | }); 41 | 42 | /** 43 | * 过期 map 44 | * 45 | * 空间换时间 46 | * @since 0.0.3 47 | */ 48 | private final Map expireMap = new HashMap<>(); 49 | 50 | /** 51 | * 缓存实现 52 | * @since 0.0.3 53 | */ 54 | private final ICache cache; 55 | 56 | /** 57 | * 线程执行类 58 | * @since 0.0.3 59 | */ 60 | private static final ScheduledExecutorService EXECUTOR_SERVICE = Executors.newSingleThreadScheduledExecutor(); 61 | 62 | public CacheExpireSort(ICache cache) { 63 | this.cache = cache; 64 | this.init(); 65 | } 66 | 67 | /** 68 | * 初始化任务 69 | * @since 0.0.3 70 | */ 71 | private void init() { 72 | EXECUTOR_SERVICE.scheduleAtFixedRate(new ExpireThread(), 100, 100, TimeUnit.MILLISECONDS); 73 | } 74 | 75 | /** 76 | * 定时执行任务 77 | * @since 0.0.3 78 | */ 79 | private class ExpireThread implements Runnable { 80 | @Override 81 | public void run() { 82 | //1.判断是否为空 83 | if(MapUtil.isEmpty(sortMap)) { 84 | return; 85 | } 86 | 87 | //2. 获取 key 进行处理 88 | int count = 0; 89 | for(Map.Entry> entry : sortMap.entrySet()) { 90 | final Long expireAt = entry.getKey(); 91 | List expireKeys = entry.getValue(); 92 | 93 | // 判断队列是否为空 94 | if(CollectionUtil.isEmpty(expireKeys)) { 95 | sortMap.remove(expireAt); 96 | continue; 97 | } 98 | if(count >= LIMIT) { 99 | return; 100 | } 101 | 102 | // 删除的逻辑处理 103 | long currentTime = System.currentTimeMillis(); 104 | if(currentTime >= expireAt) { 105 | Iterator iterator = expireKeys.iterator(); 106 | while (iterator.hasNext()) { 107 | K key = iterator.next(); 108 | // 先移除本身 109 | iterator.remove(); 110 | expireMap.remove(key); 111 | 112 | // 再移除缓存,后续可以通过惰性删除做补偿 113 | cache.remove(key); 114 | 115 | count++; 116 | } 117 | } else { 118 | // 直接跳过,没有过期的信息 119 | return; 120 | } 121 | } 122 | } 123 | } 124 | 125 | @Override 126 | public void expire(K key, long expireAt) { 127 | List keys = sortMap.get(expireAt); 128 | if(keys == null) { 129 | keys = new ArrayList<>(); 130 | } 131 | keys.add(key); 132 | 133 | // 设置对应的信息 134 | sortMap.put(expireAt, keys); 135 | expireMap.put(key, expireAt); 136 | } 137 | 138 | @Override 139 | public void refreshExpire(Collection keyList) { 140 | if(CollectionUtil.isEmpty(keyList)) { 141 | return; 142 | } 143 | 144 | // 这样维护两套的代价太大,后续优化,暂时不用。 145 | // 判断大小,小的作为外循环 146 | final int expireSize = expireMap.size(); 147 | if(expireSize <= keyList.size()) { 148 | // 一般过期的数量都是较少的 149 | for(Map.Entry entry : expireMap.entrySet()) { 150 | K key = entry.getKey(); 151 | 152 | // 这里直接执行过期处理,不再判断是否存在于集合中。 153 | // 因为基于集合的判断,时间复杂度为 O(n) 154 | this.removeExpireKey(key); 155 | } 156 | } else { 157 | for(K key : keyList) { 158 | this.removeExpireKey(key); 159 | } 160 | } 161 | } 162 | 163 | /** 164 | * 移除过期信息 165 | * @param key key 166 | * @since 0.0.10 167 | */ 168 | private void removeExpireKey(final K key) { 169 | Long expireTime = expireMap.get(key); 170 | if(expireTime != null) { 171 | final long currentTime = System.currentTimeMillis(); 172 | if(currentTime >= expireTime) { 173 | expireMap.remove(key); 174 | 175 | List expireKeys = sortMap.get(expireTime); 176 | expireKeys.remove(key); 177 | sortMap.put(expireTime, expireKeys); 178 | } 179 | } 180 | } 181 | 182 | @Override 183 | public Long expireTime(K key) { 184 | return expireMap.get(key); 185 | } 186 | 187 | } 188 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/expire/package-info.java: -------------------------------------------------------------------------------- 1 | package core.support.expire; -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/interceptor/CacheInterceptorContext.java: -------------------------------------------------------------------------------- 1 | package core.support.interceptor; 2 | 3 | import api.ICacheInterceptorContext; 4 | import api.ICache; 5 | 6 | import java.lang.reflect.Method; 7 | 8 | /** 9 | * 耗时统计 10 | * 11 | * (1)耗时 12 | * (2)慢日志 13 | * @author lujiaxin 14 | * @date 2023/5/8 15 | */ 16 | public class CacheInterceptorContext implements ICacheInterceptorContext { 17 | 18 | private ICache cache; 19 | 20 | /** 21 | * 执行的方法信息 22 | * @since 0.0.5 23 | */ 24 | private Method method; 25 | 26 | /** 27 | * 执行的参数 28 | * @since 0.0.5 29 | */ 30 | private Object[] params; 31 | 32 | /** 33 | * 方法执行的结果 34 | * @since 0.0.5 35 | */ 36 | private Object result; 37 | 38 | /** 39 | * 开始时间 40 | * @since 0.0.5 41 | */ 42 | private long startMills; 43 | 44 | /** 45 | * 结束时间 46 | * @since 0.0.5 47 | */ 48 | private long endMills; 49 | 50 | public static CacheInterceptorContext newInstance() { 51 | return new CacheInterceptorContext<>(); 52 | } 53 | 54 | @Override 55 | public ICache cache() { 56 | return cache; 57 | } 58 | 59 | public CacheInterceptorContext cache(ICache cache) { 60 | this.cache = cache; 61 | return this; 62 | } 63 | 64 | @Override 65 | public Method method() { 66 | return method; 67 | } 68 | 69 | public CacheInterceptorContext method(Method method) { 70 | this.method = method; 71 | return this; 72 | } 73 | 74 | @Override 75 | public Object[] params() { 76 | return params; 77 | } 78 | 79 | public CacheInterceptorContext params(Object[] params) { 80 | this.params = params; 81 | return this; 82 | } 83 | 84 | @Override 85 | public Object result() { 86 | return result; 87 | } 88 | 89 | public CacheInterceptorContext result(Object result) { 90 | this.result = result; 91 | return this; 92 | } 93 | 94 | @Override 95 | public long startMills() { 96 | return startMills; 97 | } 98 | 99 | public CacheInterceptorContext startMills(long startMills) { 100 | this.startMills = startMills; 101 | return this; 102 | } 103 | 104 | @Override 105 | public long endMills() { 106 | return endMills; 107 | } 108 | 109 | public CacheInterceptorContext endMills(long endMills) { 110 | this.endMills = endMills; 111 | return this; 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/interceptor/CacheInterceptors.java: -------------------------------------------------------------------------------- 1 | package core.support.interceptor; 2 | 3 | import api.ICacheInterceptor; 4 | import core.support.interceptor.aof.CacheInterceptorAof; 5 | import core.support.interceptor.common.CacheInterceptorCost; 6 | import core.support.interceptor.evict.CacheInterceptorEvict; 7 | import core.support.interceptor.refresh.CacheInterceptorRefresh; 8 | 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | /** 13 | * 缓存拦截器工具类 14 | * @author lujiaxin 15 | * @date 2023/5/8 16 | */ 17 | public final class CacheInterceptors { 18 | 19 | /** 20 | * 默认通用 21 | * @return 结果 22 | * @since 0.0.5 23 | */ 24 | @SuppressWarnings("all") 25 | public static List defaultCommonList() { 26 | List list = new ArrayList<>(); 27 | list.add(new CacheInterceptorCost()); 28 | return list; 29 | } 30 | 31 | /** 32 | * 默认刷新 33 | * @return 结果 34 | * @since 0.0.5 35 | */ 36 | @SuppressWarnings("all") 37 | public static List defaultRefreshList() { 38 | List list = new ArrayList<>(); 39 | list.add(new CacheInterceptorRefresh()); 40 | return list; 41 | } 42 | 43 | /** 44 | * AOF 模式 45 | * @return 结果 46 | * @since 0.0.10 47 | */ 48 | @SuppressWarnings("all") 49 | public static ICacheInterceptor aof() { 50 | return new CacheInterceptorAof(); 51 | } 52 | 53 | /** 54 | * 驱除策略拦截器 55 | * @return 结果 56 | * @since 0.0.11 57 | */ 58 | @SuppressWarnings("all") 59 | public static ICacheInterceptor evict() { 60 | return new CacheInterceptorEvict(); 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/interceptor/aof/CacheInterceptorAof.java: -------------------------------------------------------------------------------- 1 | package core.support.interceptor.aof; 2 | 3 | import api.ICache; 4 | import api.ICacheInterceptor; 5 | import api.ICacheInterceptorContext; 6 | import api.ICachePersist; 7 | import com.alibaba.fastjson.JSON; 8 | import com.github.houbb.log.integration.core.Log; 9 | import com.github.houbb.log.integration.core.LogFactory; 10 | import core.constant.enums.model.PersistAofEntry; 11 | import core.support.persist.CachePersistAof; 12 | 13 | /** 14 | * 顺序追加模式 15 | * 16 | * AOF 持久化到文件,暂时不考虑 buffer 等特性。 17 | * @author lujiaxin 18 | * @date 2023/5/8 19 | */ 20 | public class CacheInterceptorAof implements ICacheInterceptor { 21 | 22 | private static final Log log = LogFactory.getLog(CacheInterceptorAof.class); 23 | 24 | @Override 25 | public void before(ICacheInterceptorContext context) { 26 | } 27 | 28 | @Override 29 | public void after(ICacheInterceptorContext context) { 30 | // 持久化类 31 | ICache cache = context.cache(); 32 | ICachePersist persist = cache.persist(); 33 | 34 | if(persist instanceof CachePersistAof) { 35 | CachePersistAof cachePersistAof = (CachePersistAof) persist; 36 | 37 | String methodName = context.method().getName(); 38 | PersistAofEntry aofEntry = PersistAofEntry.newInstance(); 39 | aofEntry.setMethodName(methodName); 40 | aofEntry.setParams(context.params()); 41 | 42 | String json = JSON.toJSONString(aofEntry); 43 | 44 | // 直接持久化 45 | log.debug("AOF 开始追加文件内容:{}", json); 46 | cachePersistAof.append(json); 47 | log.debug("AOF 完成追加文件内容:{}", json); 48 | } 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/interceptor/common/CacheInterceptorCost.java: -------------------------------------------------------------------------------- 1 | package core.support.interceptor.common; 2 | 3 | import api.ICacheInterceptor; 4 | import api.ICacheInterceptorContext; 5 | import api.ICacheSlowListener; 6 | import com.github.houbb.heaven.util.util.CollectionUtil; 7 | import com.github.houbb.log.integration.core.Log; 8 | import com.github.houbb.log.integration.core.LogFactory; 9 | import core.support.listener.slow.CacheSlowListenerContext; 10 | 11 | import java.util.List; 12 | 13 | /** 14 | * 耗时统计 15 | * 16 | * (1)耗时 17 | * (2)慢日志 18 | * @author lujiaxin 19 | * @date 2023/5/8 20 | */ 21 | public class CacheInterceptorCost implements ICacheInterceptor { 22 | 23 | private static final Log log = LogFactory.getLog(CacheInterceptorCost.class); 24 | 25 | @Override 26 | public void before(ICacheInterceptorContext context) { 27 | log.debug("Cost start, method: {}", context.method().getName()); 28 | } 29 | 30 | @Override 31 | public void after(ICacheInterceptorContext context) { 32 | long costMills = context.endMills()-context.startMills(); 33 | final String methodName = context.method().getName(); 34 | log.debug("Cost end, method: {}, cost: {}ms", methodName, costMills); 35 | 36 | // 添加慢日志操作 37 | List slowListeners = context.cache().slowListeners(); 38 | if(CollectionUtil.isNotEmpty(slowListeners)) { 39 | CacheSlowListenerContext listenerContext = CacheSlowListenerContext.newInstance().startTimeMills(context.startMills()) 40 | .endTimeMills(context.endMills()) 41 | .costTimeMills(costMills) 42 | .methodName(methodName) 43 | .params(context.params()) 44 | .result(context.result()) 45 | ; 46 | 47 | // 设置多个,可以考虑不同的慢日志级别,做不同的处理 48 | for(ICacheSlowListener slowListener : slowListeners) { 49 | long slowThanMills = slowListener.slowerThanMills(); 50 | if(costMills >= slowThanMills) { 51 | slowListener.listen(listenerContext); 52 | } 53 | } 54 | } 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/interceptor/evict/CacheInterceptorEvict.java: -------------------------------------------------------------------------------- 1 | package core.support.interceptor.evict; 2 | 3 | import api.ICacheEvict; 4 | import api.ICacheInterceptor; 5 | import api.ICacheInterceptorContext; 6 | import com.github.houbb.log.integration.core.Log; 7 | import com.github.houbb.log.integration.core.LogFactory; 8 | 9 | import java.lang.reflect.Method; 10 | 11 | /** 12 | * 驱除策略拦截器 13 | * @author lujiaxin 14 | * @date 2023/5/8 15 | */ 16 | public class CacheInterceptorEvict implements ICacheInterceptor { 17 | 18 | private static final Log log = LogFactory.getLog(CacheInterceptorEvict.class); 19 | 20 | @Override 21 | public void before(ICacheInterceptorContext context) { 22 | } 23 | 24 | @Override 25 | @SuppressWarnings("all") 26 | public void after(ICacheInterceptorContext context) { 27 | ICacheEvict evict = context.cache().evict(); 28 | 29 | Method method = context.method(); 30 | final K key = (K) context.params()[0]; 31 | if("remove".equals(method.getName())) { 32 | evict.removeKey(key); 33 | } else { 34 | evict.updateKey(key); 35 | } 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/interceptor/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * @author binbin.hou 3 | * @since 1.0.0 4 | */ 5 | package core.support.interceptor; -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/interceptor/refresh/CacheInterceptorRefresh.java: -------------------------------------------------------------------------------- 1 | package core.support.interceptor.refresh; 2 | 3 | import api.ICache; 4 | import api.ICacheInterceptor; 5 | import api.ICacheInterceptorContext; 6 | import com.github.houbb.log.integration.core.Log; 7 | import com.github.houbb.log.integration.core.LogFactory; 8 | 9 | /** 10 | * 刷新 11 | * 12 | * @author binbin.hou 13 | * @since 0.0.5 14 | */ 15 | public class CacheInterceptorRefresh implements ICacheInterceptor { 16 | 17 | private static final Log log = LogFactory.getLog(CacheInterceptorRefresh.class); 18 | 19 | @Override 20 | public void before(ICacheInterceptorContext context) { 21 | log.debug("Refresh start"); 22 | final ICache cache = context.cache(); 23 | cache.expire().refreshExpire(cache.keySet()); 24 | } 25 | 26 | @Override 27 | public void after(ICacheInterceptorContext context) { 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/listener/package-info.java: -------------------------------------------------------------------------------- 1 | package core.support.listener; -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/listener/remove/CacheRemoveListener.java: -------------------------------------------------------------------------------- 1 | package core.support.listener.remove; 2 | 3 | import api.ICacheRemoveListener; 4 | import api.ICacheRemoveListenerContext; 5 | import com.github.houbb.log.integration.core.Log; 6 | import com.github.houbb.log.integration.core.LogFactory; 7 | 8 | /** 9 | * 默认的删除监听类 10 | * @author lujiaxin 11 | * @date 2023/5/8 12 | */ 13 | public class CacheRemoveListener implements ICacheRemoveListener { 14 | 15 | private static final Log log = LogFactory.getLog(CacheRemoveListener.class); 16 | 17 | @Override 18 | public void listen(ICacheRemoveListenerContext context) { 19 | log.debug("Remove key: {}, value: {}, type: {}", 20 | context.key(), context.value(), context.type()); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/listener/remove/CacheRemoveListenerContext.java: -------------------------------------------------------------------------------- 1 | package core.support.listener.remove; 2 | 3 | import api.ICacheRemoveListenerContext; 4 | 5 | /** 6 | * 删除的监听器 7 | * @author lujiaxin 8 | * @date 2023/5/8 9 | */ 10 | public class CacheRemoveListenerContext implements ICacheRemoveListenerContext { 11 | 12 | /** 13 | * key 14 | * @since 0.0.6 15 | */ 16 | private K key; 17 | /** 18 | * 值 19 | * @since 0.0.6 20 | */ 21 | private V value; 22 | 23 | /** 24 | * 删除类型 25 | * @since 0.0.6 26 | */ 27 | private String type; 28 | 29 | /** 30 | * 新建实例 31 | * @param key 32 | * @param value 33 | * @return 结果 34 | * @since 0.0.6 35 | */ 36 | public static CacheRemoveListenerContext newInstance() { 37 | return new CacheRemoveListenerContext<>(); 38 | } 39 | 40 | @Override 41 | public K key() { 42 | return key; 43 | } 44 | 45 | public CacheRemoveListenerContext key(K key) { 46 | this.key = key; 47 | return this; 48 | } 49 | 50 | @Override 51 | public V value() { 52 | return value; 53 | } 54 | 55 | public CacheRemoveListenerContext value(V value) { 56 | 57 | this.value = value; 58 | return this; 59 | } 60 | 61 | 62 | 63 | 64 | @Override 65 | public String type() { 66 | return type; 67 | } 68 | 69 | public CacheRemoveListenerContext type(String type) { 70 | this.type = type; 71 | return this; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/listener/remove/CacheRemoveListeners.java: -------------------------------------------------------------------------------- 1 | package core.support.listener.remove; 2 | 3 | import api.ICacheRemoveListener; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | /** 9 | * 缓存删除监听类 10 | * @author lujiaxin 11 | * @date 2023/5/8 12 | */ 13 | public class CacheRemoveListeners { 14 | 15 | private CacheRemoveListeners(){} 16 | 17 | /** 18 | * 默认监听类 19 | * @return 监听类列表 20 | * @param key 21 | * @param value 22 | * @since 0.0.6 23 | */ 24 | @SuppressWarnings("all") 25 | public static List> defaults() { 26 | List> listeners = new ArrayList<>(); 27 | listeners.add(new CacheRemoveListener()); 28 | return listeners; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/listener/slow/CacheSlowListener.java: -------------------------------------------------------------------------------- 1 | package core.support.listener.slow; 2 | 3 | import api.ICacheSlowListener; 4 | import api.ICacheSlowListenerContext; 5 | import com.alibaba.fastjson.JSON; 6 | import com.github.houbb.log.integration.core.Log; 7 | import com.github.houbb.log.integration.core.LogFactory; 8 | import core.support.interceptor.common.CacheInterceptorCost; 9 | 10 | /** 11 | * 慢日志监听类 12 | * @author lujiaxin 13 | * @date 2023/5/8 14 | */ 15 | public class CacheSlowListener implements ICacheSlowListener { 16 | 17 | private static final Log log = LogFactory.getLog(CacheInterceptorCost.class); 18 | 19 | @Override 20 | public void listen(ICacheSlowListenerContext context) { 21 | log.warn("[Slow] methodName: {}, params: {}, cost time: {}", 22 | context.methodName(), JSON.toJSON(context.params()), context.costTimeMills()); 23 | } 24 | 25 | @Override 26 | public long slowerThanMills() { 27 | return 1000L; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/listener/slow/CacheSlowListenerContext.java: -------------------------------------------------------------------------------- 1 | package core.support.listener.slow; 2 | 3 | import api.ICacheSlowListenerContext; 4 | 5 | /** 6 | * @author lujiaxin 7 | * @date 2023/5/8 8 | */ 9 | public class CacheSlowListenerContext implements ICacheSlowListenerContext { 10 | 11 | /** 12 | * 方法名称 13 | * @since 0.0.9 14 | */ 15 | private String methodName; 16 | 17 | /** 18 | * 参数信息 19 | * @since 0.0.9 20 | */ 21 | private Object[] params; 22 | 23 | /** 24 | * 方法结果 25 | * @since 0.0.9 26 | */ 27 | private Object result; 28 | 29 | /** 30 | * 开始时间 31 | * @since 0.0.9 32 | */ 33 | private long startTimeMills; 34 | 35 | /** 36 | * 结束时间 37 | * @since 0.0.9 38 | */ 39 | private long endTimeMills; 40 | 41 | /** 42 | * 消耗时间 43 | * @since 0.0.9 44 | */ 45 | private long costTimeMills; 46 | 47 | /** 48 | * @since 0.0.9 49 | * @return 实例 50 | */ 51 | public static CacheSlowListenerContext newInstance() { 52 | return new CacheSlowListenerContext(); 53 | } 54 | 55 | @Override 56 | public String methodName() { 57 | return methodName; 58 | } 59 | 60 | public CacheSlowListenerContext methodName(String methodName) { 61 | this.methodName = methodName; 62 | return this; 63 | } 64 | 65 | @Override 66 | public Object[] params() { 67 | return params; 68 | } 69 | 70 | public CacheSlowListenerContext params(Object[] params) { 71 | this.params = params; 72 | return this; 73 | } 74 | 75 | @Override 76 | public Object result() { 77 | return result; 78 | } 79 | 80 | public CacheSlowListenerContext result(Object result) { 81 | this.result = result; 82 | return this; 83 | } 84 | 85 | @Override 86 | public long startTimeMills() { 87 | return startTimeMills; 88 | } 89 | 90 | public CacheSlowListenerContext startTimeMills(long startTimeMills) { 91 | this.startTimeMills = startTimeMills; 92 | return this; 93 | } 94 | 95 | @Override 96 | public long endTimeMills() { 97 | return endTimeMills; 98 | } 99 | 100 | public CacheSlowListenerContext endTimeMills(long endTimeMills) { 101 | this.endTimeMills = endTimeMills; 102 | return this; 103 | } 104 | 105 | @Override 106 | public long costTimeMills() { 107 | return costTimeMills; 108 | } 109 | 110 | public CacheSlowListenerContext costTimeMills(long costTimeMills) { 111 | this.costTimeMills = costTimeMills; 112 | return this; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/listener/slow/CacheSlowListeners.java: -------------------------------------------------------------------------------- 1 | package core.support.listener.slow; 2 | 3 | import api.ICacheSlowListener; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | /** 9 | * 慢日志监听工具类 10 | * @author lujiaxin 11 | * @date 2023/5/8 12 | */ 13 | public final class CacheSlowListeners { 14 | 15 | private CacheSlowListeners(){} 16 | 17 | /** 18 | * 无 19 | * @return 监听类列表 20 | * @since 0.0.9 21 | */ 22 | public static List none() { 23 | return new ArrayList<>(); 24 | } 25 | 26 | /** 27 | * 默认实现 28 | * @return 默认 29 | * @since 0.0.9 30 | */ 31 | public static ICacheSlowListener defaults() { 32 | return new CacheSlowListener(); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/listener/slow/package-info.java: -------------------------------------------------------------------------------- 1 | package core.support.listener.slow; -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/load/CacheLoadAof.java: -------------------------------------------------------------------------------- 1 | package core.support.load; 2 | 3 | import annotation.CacheInterceptor; 4 | import api.ICache; 5 | import api.ICacheLoad; 6 | import com.alibaba.fastjson.JSON; 7 | import com.github.houbb.heaven.util.io.FileUtil; 8 | import com.github.houbb.heaven.util.lang.StringUtil; 9 | import com.github.houbb.heaven.util.lang.reflect.ReflectMethodUtil; 10 | import com.github.houbb.heaven.util.util.CollectionUtil; 11 | import com.github.houbb.log.integration.core.Log; 12 | import com.github.houbb.log.integration.core.LogFactory; 13 | import core.constant.enums.model.PersistAofEntry; 14 | import core.core.Cache; 15 | 16 | import java.lang.reflect.Method; 17 | import java.util.HashMap; 18 | import java.util.List; 19 | import java.util.Map; 20 | 21 | /** 22 | * 加载策略-AOF文件模式 23 | * @author lujiaxin 24 | * @date 2023/5/8 25 | */ 26 | public class CacheLoadAof implements ICacheLoad { 27 | 28 | private static final Log log = LogFactory.getLog(CacheLoadAof.class); 29 | 30 | /** 31 | * 方法缓存 32 | * 33 | * 暂时比较简单,直接通过方法判断即可,不必引入参数类型增加复杂度。 34 | * @since 0.0.10 35 | */ 36 | private static final Map METHOD_MAP = new HashMap<>(); 37 | 38 | static { 39 | Method[] methods = Cache.class.getMethods(); 40 | 41 | for(Method method : methods){ 42 | CacheInterceptor cacheInterceptor = method.getAnnotation(CacheInterceptor.class); 43 | 44 | if(cacheInterceptor != null) { 45 | // 暂时 46 | if(cacheInterceptor.aof()) { 47 | String methodName = method.getName(); 48 | 49 | METHOD_MAP.put(methodName, method); 50 | } 51 | } 52 | } 53 | 54 | } 55 | 56 | /** 57 | * 文件路径 58 | * @since 0.0.8 59 | */ 60 | private final String dbPath; 61 | 62 | public CacheLoadAof(String dbPath) { 63 | this.dbPath = dbPath; 64 | } 65 | 66 | @Override 67 | public void load(ICache cache) { 68 | List lines = FileUtil.readAllLines(dbPath); 69 | log.info("[load] 开始处理 path: {}", dbPath); 70 | if(CollectionUtil.isEmpty(lines)) { 71 | log.info("[load] path: {} 文件内容为空,直接返回", dbPath); 72 | return; 73 | } 74 | 75 | for(String line : lines) { 76 | if(StringUtil.isEmpty(line)) { 77 | continue; 78 | } 79 | 80 | // 执行 81 | // 简单的类型还行,复杂的这种反序列化会失败 82 | PersistAofEntry entry = JSON.parseObject(line, PersistAofEntry.class); 83 | 84 | final String methodName = entry.getMethodName(); 85 | final Object[] objects = entry.getParams(); 86 | 87 | final Method method = METHOD_MAP.get(methodName); 88 | // 反射调用 89 | ReflectMethodUtil.invoke(cache, method, objects); 90 | } 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/load/CacheLoadDbJson.java: -------------------------------------------------------------------------------- 1 | package core.support.load; 2 | 3 | import api.ICache; 4 | import api.ICacheLoad; 5 | import com.alibaba.fastjson.JSON; 6 | import com.github.houbb.heaven.util.io.FileUtil; 7 | import com.github.houbb.heaven.util.lang.ObjectUtil; 8 | import com.github.houbb.heaven.util.lang.StringUtil; 9 | import com.github.houbb.heaven.util.util.CollectionUtil; 10 | import com.github.houbb.log.integration.core.Log; 11 | import com.github.houbb.log.integration.core.LogFactory; 12 | import core.constant.enums.model.PersistRdbEntry; 13 | 14 | import java.util.List; 15 | 16 | /** 17 | * 加载策略-文件路径 18 | * @author lujiaxin 19 | * @date 2023/5/8 20 | */ 21 | public class CacheLoadDbJson implements ICacheLoad { 22 | 23 | private static final Log log = LogFactory.getLog(CacheLoadDbJson.class); 24 | 25 | /** 26 | * 文件路径 27 | * @since 0.0.8 28 | */ 29 | private final String dbPath; 30 | 31 | public CacheLoadDbJson(String dbPath) { 32 | this.dbPath = dbPath; 33 | } 34 | 35 | @Override 36 | public void load(ICache cache) { 37 | List lines = FileUtil.readAllLines(dbPath); 38 | log.info("[load] 开始处理 path: {}", dbPath); 39 | if(CollectionUtil.isEmpty(lines)) { 40 | log.info("[load] path: {} 文件内容为空,直接返回", dbPath); 41 | return; 42 | } 43 | 44 | for(String line : lines) { 45 | if(StringUtil.isEmpty(line)) { 46 | continue; 47 | } 48 | 49 | // 执行 50 | // 简单的类型还行,复杂的这种反序列化会失败 51 | PersistRdbEntry entry = JSON.parseObject(line, PersistRdbEntry.class); 52 | 53 | K key = entry.getKey(); 54 | V value = entry.getValue(); 55 | Long expire = entry.getExpire(); 56 | 57 | cache.put(key, value); 58 | if(ObjectUtil.isNotNull(expire)) { 59 | cache.expireAt(key, expire); 60 | } 61 | } 62 | //nothing... 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/load/CacheLoadNone.java: -------------------------------------------------------------------------------- 1 | package core.support.load; 2 | 3 | import api.ICache; 4 | import api.ICacheLoad; 5 | 6 | /** 7 | * 加载策略-无 8 | * @author lujiaxin 9 | * @date 2023/5/8 10 | */ 11 | public class CacheLoadNone implements ICacheLoad { 12 | 13 | @Override 14 | public void load(ICache cache) { 15 | //nothing... 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/load/CacheLoads.java: -------------------------------------------------------------------------------- 1 | package core.support.load; 2 | 3 | import api.ICacheLoad; 4 | 5 | /** 6 | * 7 | * 加载策略工具类 8 | * @author lujiaxin 9 | * @date 2023/5/8 10 | */ 11 | public final class CacheLoads { 12 | 13 | private CacheLoads(){} 14 | 15 | /** 16 | * 无加载 17 | * @param key 18 | * @param value 19 | * @return 值 20 | * @since 0.0.7 21 | */ 22 | public static ICacheLoad none() { 23 | return new CacheLoadNone<>(); 24 | } 25 | 26 | /** 27 | * 文件 JSON 28 | * @param dbPath 文件路径 29 | * @param key 30 | * @param value 31 | * @return 值 32 | * @since 0.0.8 33 | */ 34 | public static ICacheLoad dbJson(final String dbPath) { 35 | return new CacheLoadDbJson<>(dbPath); 36 | } 37 | 38 | /** 39 | * AOF 文件加载模式 40 | * @param dbPath 文件路径 41 | * @param key 42 | * @param value 43 | * @return 值 44 | * @since 0.0.10 45 | */ 46 | public static ICacheLoad aof(final String dbPath) { 47 | return new CacheLoadAof<>(dbPath); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/load/package-info.java: -------------------------------------------------------------------------------- 1 | package core.support.load; -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/map/Maps.java: -------------------------------------------------------------------------------- 1 | package core.support.map; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | /** 7 | * 8 | * @author lujiaxin 9 | * @date 2023/5/8 10 | */ 11 | public final class Maps { 12 | 13 | private Maps(){} 14 | 15 | /** 16 | * hashMap 实现策略 17 | * @param key 18 | * @param value 19 | * @return map 实现 20 | * @since 0.0.3 21 | */ 22 | public static Map hashMap() { 23 | return new HashMap<>(); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/map/package-info.java: -------------------------------------------------------------------------------- 1 | package core.support.map; -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/package-info.java: -------------------------------------------------------------------------------- 1 | package core.support; -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/persist/CachePersistAdaptor.java: -------------------------------------------------------------------------------- 1 | package core.support.persist; 2 | 3 | import api.ICache; 4 | import api.ICachePersist; 5 | import java.util.concurrent.TimeUnit; 6 | 7 | /** 8 | * 缓存持久化-适配器模式 9 | * @author lujiaxin 10 | * @date 2023/5/8 11 | */ 12 | public class CachePersistAdaptor implements ICachePersist { 13 | 14 | /** 15 | * 持久化 16 | * key长度 key+value 17 | * 第一个空格,获取 key 的长度,然后截取 18 | * @param cache 缓存 19 | */ 20 | @Override 21 | public void persist(ICache cache) { 22 | } 23 | 24 | @Override 25 | public long delay() { 26 | return this.period(); 27 | } 28 | 29 | @Override 30 | public long period() { 31 | return 1; 32 | } 33 | 34 | @Override 35 | public TimeUnit timeUnit() { 36 | return TimeUnit.SECONDS; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/persist/CachePersistAof.java: -------------------------------------------------------------------------------- 1 | package core.support.persist; 2 | 3 | import api.ICache; 4 | import com.github.houbb.heaven.util.io.FileUtil; 5 | import com.github.houbb.heaven.util.lang.StringUtil; 6 | import com.github.houbb.log.integration.core.Log; 7 | import com.github.houbb.log.integration.core.LogFactory; 8 | 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | import java.util.concurrent.TimeUnit; 12 | 13 | /** 14 | * @author lujiaxin 15 | * @date 2023/5/8 16 | */ 17 | public class CachePersistAof extends CachePersistAdaptor { 18 | 19 | private static final Log log = LogFactory.getLog(CachePersistAof.class); 20 | 21 | /** 22 | * 缓存列表 23 | * @since 0.0.10 24 | */ 25 | private final List bufferList = new ArrayList<>(); 26 | 27 | /** 28 | * 数据持久化路径 29 | * @since 0.0.10 30 | */ 31 | private final String dbPath; 32 | 33 | public CachePersistAof(String dbPath) { 34 | this.dbPath = dbPath; 35 | } 36 | 37 | /** 38 | * 持久化 39 | * key长度 key+value 40 | * 第一个空格,获取 key 的长度,然后截取 41 | * @param cache 缓存 42 | */ 43 | @Override 44 | public void persist(ICache cache) { 45 | log.info("开始 AOF 持久化到文件"); 46 | // 1. 创建文件 47 | if(!FileUtil.exists(dbPath)) { 48 | FileUtil.createFile(dbPath); 49 | } 50 | // 2. 持久化追加到文件中 51 | FileUtil.append(dbPath, bufferList); 52 | 53 | // 3. 清空 buffer 列表 54 | bufferList.clear(); 55 | log.info("完成 AOF 持久化到文件"); 56 | } 57 | 58 | @Override 59 | public long delay() { 60 | return 1; 61 | } 62 | 63 | @Override 64 | public long period() { 65 | return 1; 66 | } 67 | 68 | @Override 69 | public TimeUnit timeUnit() { 70 | return TimeUnit.SECONDS; 71 | } 72 | 73 | /** 74 | * 添加文件内容到 buffer 列表中 75 | * @param json json 信息 76 | * @since 0.0.10 77 | */ 78 | public void append(final String json) { 79 | if(StringUtil.isNotEmpty(json)) { 80 | bufferList.add(json); 81 | } 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/persist/CachePersistDbJson.java: -------------------------------------------------------------------------------- 1 | package core.support.persist; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import api.ICache; 5 | //import core.model.PersistRdbEntry; 6 | import com.github.houbb.heaven.util.io.FileUtil; 7 | import core.constant.enums.model.PersistRdbEntry; 8 | 9 | import java.nio.file.StandardOpenOption; 10 | import java.util.Map; 11 | import java.util.Set; 12 | import java.util.concurrent.TimeUnit; 13 | 14 | /** 15 | * 缓存持久化-db-基于 JSON 16 | * @author binbin.hou 17 | * @since 0.0.8 18 | */ 19 | public class CachePersistDbJson extends CachePersistAdaptor { 20 | 21 | /** 22 | * 数据库路径 23 | * @since 0.0.8 24 | */ 25 | private final String dbPath; 26 | 27 | public CachePersistDbJson(String dbPath) { 28 | this.dbPath = dbPath; 29 | } 30 | 31 | /** 32 | * 持久化 33 | * key长度 key+value 34 | * 第一个空格,获取 key 的长度,然后截取 35 | * @param cache 缓存 36 | */ 37 | @Override 38 | public void persist(ICache cache) { 39 | Set> entrySet = cache.entrySet(); 40 | 41 | // 创建文件 42 | FileUtil.createFile(dbPath); 43 | // 清空文件 44 | FileUtil.truncate(dbPath); 45 | 46 | for(Map.Entry entry : entrySet) { 47 | K key = entry.getKey(); 48 | Long expireTime = cache.expire().expireTime(key); 49 | PersistRdbEntry persistRdbEntry = new PersistRdbEntry<>(); 50 | persistRdbEntry.setKey(key); 51 | persistRdbEntry.setValue(entry.getValue()); 52 | persistRdbEntry.setExpire(expireTime); 53 | 54 | String line = JSON.toJSONString(persistRdbEntry); 55 | FileUtil.write(dbPath, line, StandardOpenOption.APPEND); 56 | } 57 | } 58 | 59 | @Override 60 | public long delay() { 61 | return 5; 62 | } 63 | 64 | @Override 65 | public long period() { 66 | return 5; 67 | } 68 | 69 | @Override 70 | public TimeUnit timeUnit() { 71 | return TimeUnit.MINUTES; 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/persist/CachePersistNone.java: -------------------------------------------------------------------------------- 1 | package core.support.persist; 2 | 3 | /** 4 | * 缓存持久化-无任何操作 5 | * @author lujiaxin 6 | * @date 2023/5/8 7 | */ 8 | public class CachePersistNone extends CachePersistAdaptor { 9 | } 10 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/persist/CachePersists.java: -------------------------------------------------------------------------------- 1 | package core.support.persist; 2 | 3 | import api.ICachePersist; 4 | 5 | /** 6 | * 缓存持久化工具类 7 | * @author lujiaxin 8 | * @date 2023/5/8 9 | */ 10 | public final class CachePersists { 11 | 12 | private CachePersists(){} 13 | 14 | /** 15 | * 无操作 16 | * @param key 17 | * @param value 18 | * @return 结果 19 | * @since 0.0.8 20 | */ 21 | public static ICachePersist none() { 22 | return new CachePersistNone<>(); 23 | } 24 | 25 | /** 26 | * DB json 操作 27 | * @param key 28 | * @param value 29 | * @param path 文件路径 30 | * @return 结果 31 | * @since 0.0.8 32 | */ 33 | public static ICachePersist dbJson(final String path) { 34 | return new CachePersistDbJson<>(path); 35 | } 36 | 37 | /** 38 | * AOF 持久化 39 | * @param key 40 | * @param value 41 | * @param path 文件路径 42 | * @return 结果 43 | * @since 0.0.10 44 | */ 45 | public static ICachePersist aof(final String path) { 46 | return new CachePersistAof<>(path); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/persist/InnerCachePersist.java: -------------------------------------------------------------------------------- 1 | package core.support.persist; 2 | 3 | import api.ICache; 4 | import api.ICachePersist; 5 | import com.github.houbb.log.integration.core.Log; 6 | import com.github.houbb.log.integration.core.LogFactory; 7 | 8 | import java.util.concurrent.Executors; 9 | import java.util.concurrent.ScheduledExecutorService; 10 | 11 | /** 12 | * 内部缓存持久化类 13 | * @author lujiaxin 14 | * @date 2023/5/8 15 | */ 16 | public class InnerCachePersist { 17 | 18 | private static final Log log = LogFactory.getLog(InnerCachePersist.class); 19 | 20 | /** 21 | * 缓存信息 22 | * @since 0.0.8 23 | */ 24 | private final ICache cache; 25 | 26 | /** 27 | * 缓存持久化策略 28 | * @since 0.0.8 29 | */ 30 | private final ICachePersist persist; 31 | 32 | /** 33 | * 线程执行类 34 | * @since 0.0.3 35 | */ 36 | private static final ScheduledExecutorService EXECUTOR_SERVICE = Executors.newSingleThreadScheduledExecutor(); 37 | 38 | public InnerCachePersist(ICache cache, ICachePersist persist) { 39 | this.cache = cache; 40 | this.persist = persist; 41 | 42 | // 初始化 43 | this.init(); 44 | } 45 | 46 | /** 47 | * 初始化 48 | * @since 0.0.8 49 | */ 50 | private void init() { 51 | EXECUTOR_SERVICE.scheduleAtFixedRate(new Runnable() { 52 | @Override 53 | public void run() { 54 | try { 55 | log.info("开始持久化缓存信息"); 56 | persist.persist(cache); 57 | log.info("完成持久化缓存信息"); 58 | } catch (Exception exception) { 59 | log.error("文件持久化异常", exception); 60 | } 61 | } 62 | }, persist.delay(), persist.period(), persist.timeUnit()); 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/persist/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 持久化 3 | * 1. AOF 4 | * 2. DB 5 | * 6 | * @since 0.0.2 7 | */ 8 | package core.support.persist; -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/proxy/CacheProxy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019. houbinbin Inc. 3 | * async All rights reserved. 4 | */ 5 | 6 | package core.support.proxy; 7 | 8 | import api.ICache; 9 | import core.support.proxy.cglib.CglibProxy; 10 | import core.support.proxy.dynamic.DynamicProxy; 11 | import core.support.proxy.none.NoneProxy; 12 | import com.github.houbb.heaven.util.lang.ObjectUtil; 13 | 14 | import java.lang.reflect.Proxy; 15 | 16 | /** 17 | *

代理信息

18 | * @author lujiaxin 19 | * @date 2023/5/8 20 | */ 21 | public final class CacheProxy { 22 | 23 | private CacheProxy(){} 24 | 25 | /** 26 | * 获取对象代理 27 | * @param 泛型 key 28 | * @param 泛型 value 29 | * @param cache 对象代理 30 | * @return 代理信息 31 | * @since 0.0.4 32 | */ 33 | @SuppressWarnings("all") 34 | public static ICache getProxy(final ICache cache) { 35 | if(ObjectUtil.isNull(cache)) { 36 | return (ICache) new NoneProxy(cache).proxy(); 37 | } 38 | 39 | final Class clazz = cache.getClass(); 40 | 41 | // 如果targetClass本身是个接口或者targetClass是JDK Proxy生成的,则使用JDK动态代理。 42 | // 参考 spring 的 AOP 判断 43 | if (clazz.isInterface() || Proxy.isProxyClass(clazz)) { 44 | return (ICache) new DynamicProxy(cache).proxy(); 45 | } 46 | 47 | return (ICache) new CglibProxy(cache).proxy(); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/proxy/ICacheProxy.java: -------------------------------------------------------------------------------- 1 | package core.support.proxy; 2 | 3 | /** 4 | * 缓存代理接口 5 | * @author lujiaxin 6 | * @date 2023/5/8 7 | */ 8 | public interface ICacheProxy { 9 | 10 | /** 11 | * 获取代理实现 12 | * @return 代理 13 | * @since 0.0.4 14 | */ 15 | Object proxy(); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/proxy/bs/CacheProxyBs.java: -------------------------------------------------------------------------------- 1 | package core.support.proxy.bs; 2 | 3 | 4 | 5 | import annotation.CacheInterceptor; 6 | import api.ICache; 7 | import api.ICacheInterceptor; 8 | import api.ICachePersist; 9 | import core.support.interceptor.CacheInterceptorContext; 10 | import core.support.interceptor.CacheInterceptors; 11 | import core.support.persist.CachePersistAof; 12 | 13 | import java.util.List; 14 | 15 | /** 16 | * 代理引导类 17 | * @author lujiaxin 18 | * @date 2023/5/8 19 | */ 20 | public final class CacheProxyBs { 21 | 22 | private CacheProxyBs(){} 23 | 24 | /** 25 | * 代理上下文 26 | * @since 0.0.4 27 | */ 28 | private ICacheProxyBsContext context; 29 | 30 | /** 31 | * 默认通用拦截器 32 | * 33 | * JDK 的泛型擦除导致这里不能使用泛型 34 | * @since 0.0.5 35 | */ 36 | @SuppressWarnings("all") 37 | private final List commonInterceptors = CacheInterceptors.defaultCommonList(); 38 | 39 | /** 40 | * 默认刷新拦截器 41 | * @since 0.0.5 42 | */ 43 | @SuppressWarnings("all") 44 | private final List refreshInterceptors = CacheInterceptors.defaultRefreshList(); 45 | 46 | /** 47 | * 持久化拦截器 48 | * @since 0.0.10 49 | */ 50 | @SuppressWarnings("all") 51 | private final ICacheInterceptor persistInterceptors = CacheInterceptors.aof(); 52 | 53 | /** 54 | * 驱除拦截器 55 | * @since 0.0.11 56 | */ 57 | @SuppressWarnings("all") 58 | private final ICacheInterceptor evictInterceptors = CacheInterceptors.evict(); 59 | 60 | /** 61 | * 新建对象实例 62 | * @return 实例 63 | * @since 0.0.4 64 | */ 65 | public static CacheProxyBs newInstance() { 66 | return new CacheProxyBs(); 67 | } 68 | 69 | public CacheProxyBs context(ICacheProxyBsContext context) { 70 | this.context = context; 71 | return this; 72 | } 73 | 74 | /** 75 | * 执行 76 | * @return 结果 77 | * @since 0.0.4 78 | * @throws Throwable 异常 79 | */ 80 | @SuppressWarnings("all") 81 | public Object execute() throws Throwable { 82 | //1. 开始的时间 83 | final long startMills = System.currentTimeMillis(); 84 | final ICache cache = context.target(); 85 | CacheInterceptorContext interceptorContext = CacheInterceptorContext.newInstance() 86 | .startMills(startMills) 87 | .method(context.method()) 88 | .params(context.params()) 89 | .cache(context.target()) 90 | ; 91 | 92 | //1. 获取刷新注解信息 93 | CacheInterceptor cacheInterceptor = context.interceptor(); 94 | this.interceptorHandler(cacheInterceptor, interceptorContext, cache, true); 95 | 96 | //2. 正常执行 97 | Object result = context.process(); 98 | 99 | final long endMills = System.currentTimeMillis(); 100 | interceptorContext.endMills(endMills).result(result); 101 | 102 | // 方法执行完成 103 | this.interceptorHandler(cacheInterceptor, interceptorContext, cache, false); 104 | return result; 105 | } 106 | 107 | /** 108 | * 拦截器执行类 109 | * @param cacheInterceptor 缓存拦截器 110 | * @param interceptorContext 上下文 111 | * @param cache 缓存 112 | * @param before 是否执行执行 113 | * @since 0.0.5 114 | */ 115 | @SuppressWarnings("all") 116 | private void interceptorHandler(CacheInterceptor cacheInterceptor, 117 | CacheInterceptorContext interceptorContext, 118 | ICache cache, 119 | boolean before) { 120 | if(cacheInterceptor != null) { 121 | //1. 通用 122 | if(cacheInterceptor.common()) { 123 | for(ICacheInterceptor interceptor : commonInterceptors) { 124 | if(before) { 125 | interceptor.before(interceptorContext); 126 | } else { 127 | interceptor.after(interceptorContext); 128 | } 129 | } 130 | } 131 | 132 | //2. 刷新 133 | if(cacheInterceptor.refresh()) { 134 | for(ICacheInterceptor interceptor : refreshInterceptors) { 135 | if(before) { 136 | interceptor.before(interceptorContext); 137 | } else { 138 | interceptor.after(interceptorContext); 139 | } 140 | } 141 | } 142 | 143 | //3. AOF 追加 144 | final ICachePersist cachePersist = cache.persist(); 145 | if(cacheInterceptor.aof() && (cachePersist instanceof CachePersistAof)) { 146 | if(before) { 147 | persistInterceptors.before(interceptorContext); 148 | } else { 149 | persistInterceptors.after(interceptorContext); 150 | } 151 | } 152 | 153 | //4. 驱除策略更新 154 | if(cacheInterceptor.evict()) { 155 | if(before) { 156 | evictInterceptors.before(interceptorContext); 157 | } else { 158 | evictInterceptors.after(interceptorContext); 159 | } 160 | } 161 | } 162 | } 163 | 164 | } 165 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/proxy/bs/CacheProxyBsContext.java: -------------------------------------------------------------------------------- 1 | package core.support.proxy.bs; 2 | 3 | import annotation.CacheInterceptor; 4 | import api.ICache; 5 | 6 | import java.lang.reflect.Method; 7 | 8 | /** 9 | * 代理引导类上下文 10 | * @author lujiaxin 11 | * @date 2023/5/8 12 | */ 13 | public class CacheProxyBsContext implements ICacheProxyBsContext { 14 | 15 | /** 16 | * 目标 17 | * @since 0.0.4 18 | */ 19 | private ICache target; 20 | 21 | /** 22 | * 入参 23 | * @since 0.0.4 24 | */ 25 | private Object[] params; 26 | 27 | /** 28 | * 方法 29 | * @since 0.0.4 30 | */ 31 | private Method method; 32 | 33 | /** 34 | * 拦截器 35 | * @since 0.0.5 36 | */ 37 | private CacheInterceptor interceptor; 38 | 39 | /** 40 | * 新建对象 41 | * @return 对象 42 | * @since 0.0.4 43 | */ 44 | public static CacheProxyBsContext newInstance(){ 45 | return new CacheProxyBsContext(); 46 | } 47 | 48 | @Override 49 | public ICache target() { 50 | return target; 51 | } 52 | 53 | @Override 54 | public CacheProxyBsContext target(ICache target) { 55 | this.target = target; 56 | return this; 57 | } 58 | 59 | @Override 60 | public Object[] params() { 61 | return params; 62 | } 63 | 64 | public CacheProxyBsContext params(Object[] params) { 65 | this.params = params; 66 | return this; 67 | } 68 | 69 | @Override 70 | public Method method() { 71 | return method; 72 | } 73 | 74 | @Override 75 | public Object process() throws Throwable { 76 | return this.method.invoke(target, params); 77 | } 78 | 79 | public CacheProxyBsContext method(Method method) { 80 | this.method = method; 81 | this.interceptor = method.getAnnotation(CacheInterceptor.class); 82 | return this; 83 | } 84 | 85 | @Override 86 | public CacheInterceptor interceptor() { 87 | return interceptor; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/proxy/bs/ICacheProxyBsContext.java: -------------------------------------------------------------------------------- 1 | package core.support.proxy.bs; 2 | 3 | import api.ICache; 4 | import annotation.CacheInterceptor; 5 | 6 | import java.lang.reflect.Method; 7 | 8 | /** 9 | * @author lujiaxin 10 | * @date 2023/5/8 11 | */ 12 | public interface ICacheProxyBsContext { 13 | 14 | /** 15 | * 拦截器信息 16 | * @return 拦截器 17 | * @since 0.0.5 18 | */ 19 | CacheInterceptor interceptor(); 20 | 21 | /** 22 | * 获取代理对象信息 23 | * @return 代理 24 | * @since 0.0.4 25 | */ 26 | ICache target(); 27 | 28 | /** 29 | * 目标对象 30 | * @param target 对象 31 | * @return 结果 32 | * @since 0.0.4 33 | */ 34 | ICacheProxyBsContext target(final ICache target); 35 | 36 | /** 37 | * 参数信息 38 | * @return 参数信息 39 | * @since 0.0.4 40 | */ 41 | Object[] params(); 42 | 43 | /** 44 | * 方法信息 45 | * @return 方法信息 46 | * @since 0.0.4 47 | */ 48 | Method method(); 49 | 50 | /** 51 | * 方法执行 52 | * @return 执行 53 | * @since 0.0.4 54 | * @throws Throwable 异常信息 55 | */ 56 | Object process() throws Throwable; 57 | 58 | } 59 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/proxy/cglib/CglibProxy.java: -------------------------------------------------------------------------------- 1 | package core.support.proxy.cglib; 2 | 3 | import api.ICache; 4 | import core.support.proxy.ICacheProxy; 5 | import core.support.proxy.bs.CacheProxyBs; 6 | import core.support.proxy.bs.CacheProxyBsContext; 7 | import core.support.proxy.bs.ICacheProxyBsContext; 8 | import net.sf.cglib.proxy.Enhancer; 9 | import net.sf.cglib.proxy.MethodInterceptor; 10 | import net.sf.cglib.proxy.MethodProxy; 11 | 12 | import java.lang.reflect.Method; 13 | 14 | /** 15 | * CGLIB 代理类 16 | * @author lujiaxin 17 | * @date 2023/5/8 18 | */ 19 | public class CglibProxy implements MethodInterceptor, ICacheProxy { 20 | 21 | /** 22 | * 被代理的对象 23 | */ 24 | private final ICache target; 25 | 26 | public CglibProxy(ICache target) { 27 | this.target = target; 28 | } 29 | 30 | @Override 31 | public Object intercept(Object o, Method method, Object[] params, MethodProxy methodProxy) throws Throwable { 32 | ICacheProxyBsContext context = CacheProxyBsContext.newInstance() 33 | .method(method).params(params).target(target); 34 | 35 | return CacheProxyBs.newInstance().context(context).execute(); 36 | } 37 | 38 | @Override 39 | public Object proxy() { 40 | Enhancer enhancer = new Enhancer(); 41 | //目标对象类 42 | enhancer.setSuperclass(target.getClass()); 43 | enhancer.setCallback(this); 44 | //通过字节码技术创建目标对象类的子类实例作为代理 45 | return enhancer.create(); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/proxy/dynamic/DynamicProxy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019. houbinbin Inc. 3 | * async All rights reserved. 4 | */ 5 | 6 | package core.support.proxy.dynamic; 7 | 8 | import api.ICache; 9 | import core.support.proxy.ICacheProxy; 10 | import core.support.proxy.bs.CacheProxyBs; 11 | import core.support.proxy.bs.CacheProxyBsContext; 12 | import core.support.proxy.bs.ICacheProxyBsContext; 13 | 14 | import java.lang.reflect.InvocationHandler; 15 | import java.lang.reflect.Method; 16 | import java.lang.reflect.Proxy; 17 | import java.util.concurrent.CompletionService; 18 | 19 | /** 20 | *

动态代理

21 | * @author lujiaxin 22 | * @date 2023/5/8 23 | */ 24 | public class DynamicProxy implements InvocationHandler, ICacheProxy { 25 | 26 | /** 27 | * 被代理的对象 28 | */ 29 | private final ICache target; 30 | 31 | public DynamicProxy(ICache target) { 32 | this.target = target; 33 | } 34 | 35 | /** 36 | * 这种方式虽然实现了异步执行,但是存在一个缺陷: 37 | * 强制用户返回值为 Future 的子类。 38 | * 39 | * 如何实现不影响原来的值,要怎么实现呢? 40 | * @param proxy 原始对象 41 | * @param method 方法 42 | * @param args 入参 43 | * @return 结果 44 | * @throws Throwable 异常 45 | */ 46 | @Override 47 | @SuppressWarnings("all") 48 | public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 49 | ICacheProxyBsContext context = CacheProxyBsContext.newInstance() 50 | .method(method).params(args).target(target); 51 | return CacheProxyBs.newInstance().context(context).execute(); 52 | } 53 | 54 | @Override 55 | public Object proxy() { 56 | // 我们要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法的 57 | InvocationHandler handler = new DynamicProxy(target); 58 | 59 | return Proxy.newProxyInstance(handler.getClass().getClassLoader(), 60 | target.getClass().getInterfaces(), handler); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/proxy/dynamic/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019. houbinbin Inc. 3 | * async All rights reserved. 4 | */ 5 | 6 | /** 7 | *

动态代理

8 | * 9 | *
 Created: 2019-03-05 22:23  
10 | *
 Project: async  
11 | * 12 | * @author houbinbin 13 | */ 14 | package core.support.proxy.dynamic; -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/proxy/none/NoneProxy.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2019. houbinbin Inc. 3 | * async All rights reserved. 4 | */ 5 | 6 | package core.support.proxy.none; 7 | 8 | import core.support.proxy.ICacheProxy; 9 | 10 | import java.lang.reflect.InvocationHandler; 11 | import java.lang.reflect.Method; 12 | 13 | /** 14 | *

没有代理

15 | * @author lujiaxin 16 | * @date 2023/5/8 17 | */ 18 | public class NoneProxy implements InvocationHandler, ICacheProxy { 19 | 20 | /** 21 | * 代理对象 22 | */ 23 | private final Object target; 24 | 25 | public NoneProxy(Object target) { 26 | this.target = target; 27 | } 28 | 29 | @Override 30 | public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 31 | return method.invoke(proxy, args); 32 | } 33 | 34 | /** 35 | * 返回原始对象,没有代理 36 | * @return 原始对象 37 | */ 38 | @Override 39 | public Object proxy() { 40 | return this.target; 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/proxy/package-info.java: -------------------------------------------------------------------------------- 1 | package core.support.proxy; -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/struct/lru/ILruMap.java: -------------------------------------------------------------------------------- 1 | package core.support.struct.lru; 2 | 3 | import api.ICacheEntry; 4 | 5 | /** 6 | * LRU map 接口 7 | * @author lujiaxin 8 | * @date 2023/5/8 9 | */ 10 | public interface ILruMap { 11 | 12 | /** 13 | * 移除最老的元素 14 | * @return 移除的明细 15 | * @since 0.0.13 16 | */ 17 | ICacheEntry removeEldest(); 18 | 19 | /** 20 | * 更新 key 的信息 21 | * @param key key 22 | * @since 0.0.13 23 | */ 24 | void updateKey(final K key); 25 | 26 | /** 27 | * 移除对应的 key 信息 28 | * @param key key 29 | * @since 0.0.13 30 | */ 31 | void removeKey(final K key); 32 | 33 | /** 34 | * 是否为空 35 | * @return 是否 36 | * @since 0.0.13 37 | */ 38 | boolean isEmpty(); 39 | 40 | /** 41 | * 是否包含元素 42 | * @param key 元素 43 | * @return 结果 44 | * @since 0.0.13 45 | */ 46 | boolean contains(final K key); 47 | 48 | } 49 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/struct/lru/impl/LruMapCircleList.java: -------------------------------------------------------------------------------- 1 | package core.support.struct.lru.impl; 2 | 3 | import api.ICacheEntry; 4 | import core.constant.enums.model.CacheEntry; 5 | import core.constant.enums.model.CircleListNode; 6 | //import core.exception.CacheRuntimeException; 7 | //import core.model.CacheEntry; 8 | //import core.model.CircleListNode; 9 | import core.core.exception.CacheRuntimeException; 10 | import core.support.struct.lru.ILruMap; 11 | import com.github.houbb.heaven.util.lang.ObjectUtil; 12 | import com.github.houbb.log.integration.core.Log; 13 | import com.github.houbb.log.integration.core.LogFactory; 14 | 15 | import java.util.HashMap; 16 | import java.util.Map; 17 | 18 | /** 19 | * 基于循环列表的实现 20 | * @author lujiaxin 21 | * @date 2023/5/8 22 | */ 23 | public class LruMapCircleList implements ILruMap { 24 | 25 | private static final Log log = LogFactory.getLog(LruMapCircleList.class); 26 | 27 | /** 28 | * 头结点 29 | * @since 0.0.15 30 | */ 31 | private CircleListNode head; 32 | 33 | /** 34 | * 映射 map 35 | * @since 0.0.15 36 | */ 37 | private Map> indexMap; 38 | 39 | public LruMapCircleList() { 40 | // 双向循环链表 41 | this.head = new CircleListNode<>(null); 42 | this.head.next(this.head); 43 | this.head.pre(this.head); 44 | 45 | indexMap = new HashMap<>(); 46 | } 47 | 48 | /** 49 | * 删除最老的元素 50 | * 51 | * (1)从 head.next 开始遍历,如果元素 accessFlag = 0,则直接移除 52 | * (2)如果 accessFlag=1,则设置其值为0,循环下一个节点。 53 | * 54 | * @return 结果 55 | * @since 0.0.15 56 | */ 57 | @Override 58 | public ICacheEntry removeEldest() { 59 | //fast-fail 60 | if(isEmpty()) { 61 | log.error("当前列表为空,无法进行删除"); 62 | throw new CacheRuntimeException("不可删除头结点!"); 63 | } 64 | 65 | // 从最老的元素开始,此处直接从 head.next 开始,后续可以考虑优化记录这个 key 66 | CircleListNode node = this.head; 67 | while (node.next() != this.head) { 68 | // 下一个元素 69 | node = node.next(); 70 | 71 | if(!node.accessFlag()) { 72 | // 未访问,直接淘汰 73 | K key = node.key(); 74 | 75 | this.removeKey(key); 76 | return CacheEntry.of(key, node.value()); 77 | } else { 78 | // 设置当前 accessFlag = 0,继续下一个 79 | node.accessFlag(false); 80 | } 81 | } 82 | 83 | // 如果循环一遍都没找到,直接取第一个元素即可。 84 | CircleListNode firstNode = this.head.next(); 85 | return CacheEntry.of(firstNode.key(), firstNode.value()); 86 | } 87 | 88 | /** 89 | * 放入元素 90 | * 91 | * 类似于 FIFO,直接放在队列的最后 92 | * 93 | * head==1==head 94 | * 加入元素: 95 | * 96 | * head==1==2==head 97 | * 98 | * (1)如果元素不存在,则直接插入。 99 | * 默认 accessFlag = 0; 100 | * (2)如果已经存在,则更新 accessFlag=1; 101 | * 102 | * @param key 元素 103 | * @since 0.0.15 104 | */ 105 | @Override 106 | public void updateKey(final K key) { 107 | CircleListNode node = indexMap.get(key); 108 | 109 | // 存在 110 | if(ObjectUtil.isNotNull(node)) { 111 | node.accessFlag(true); 112 | log.debug("节点已存在,设置节点访问标识为 true, key: {}", key); 113 | } else { 114 | // 不存在,则插入到最后 115 | node = new CircleListNode<>(key); 116 | 117 | CircleListNode tail = head.pre(); 118 | tail.next(node); 119 | node.pre(tail); 120 | node.next(head); 121 | head.pre(node); 122 | 123 | // 放入 indexMap 中,便于快速定位 124 | indexMap.put(key, node); 125 | log.debug("节点不存在,新增节点到链表中:{}", key); 126 | } 127 | } 128 | 129 | /** 130 | * 移除元素 131 | * 132 | * 1. 是否存在,不存在则忽略 133 | * 2. 存在则移除,从链表+map中移除 134 | * 135 | * head==1==2==head 136 | * 137 | * 删除 2 之后: 138 | * head==1==head 139 | * @param key 元素 140 | * @since 0.0.15 141 | */ 142 | @Override 143 | public void removeKey(final K key) { 144 | CircleListNode node = indexMap.get(key); 145 | if(ObjectUtil.isNull(node)) { 146 | log.warn("对应的删除信息不存在:{}", key); 147 | return; 148 | } 149 | 150 | CircleListNode pre = node.pre(); 151 | CircleListNode next = node.next(); 152 | 153 | //1-->(x2)-->3 直接移除2 154 | pre.next(next); 155 | next.pre(pre); 156 | indexMap.remove(key); 157 | 158 | log.debug("Key: {} 从循环链表中移除", key); 159 | } 160 | 161 | @Override 162 | public boolean isEmpty() { 163 | return indexMap.isEmpty(); 164 | } 165 | 166 | @Override 167 | public boolean contains(K key) { 168 | return indexMap.containsKey(key); 169 | } 170 | 171 | } 172 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/struct/lru/impl/LruMapDoubleList.java: -------------------------------------------------------------------------------- 1 | package core.support.struct.lru.impl; 2 | 3 | import api.ICacheEntry; 4 | //import core.exception.CacheRuntimeException; 5 | import core.constant.enums.model.CacheEntry; 6 | import core.constant.enums.model.DoubleListNode; 7 | import core.core.exception.CacheRuntimeException; 8 | //import core.model.CacheEntry; 9 | //import core.model.DoubleListNode; 10 | import core.support.struct.lru.ILruMap; 11 | import com.github.houbb.heaven.util.lang.ObjectUtil; 12 | import com.github.houbb.log.integration.core.Log; 13 | import com.github.houbb.log.integration.core.LogFactory; 14 | 15 | import java.util.HashMap; 16 | import java.util.Map; 17 | 18 | /** 19 | * 基于双向列表的实现 20 | * @author lujiaxin 21 | * @date 2023/5/8 22 | */ 23 | public class LruMapDoubleList implements ILruMap { 24 | 25 | private static final Log log = LogFactory.getLog(LruMapDoubleList.class); 26 | 27 | /** 28 | * 头结点 29 | * @since 0.0.13 30 | */ 31 | private DoubleListNode head; 32 | 33 | /** 34 | * 尾巴结点 35 | * @since 0.0.13 36 | */ 37 | private DoubleListNode tail; 38 | 39 | /** 40 | * map 信息 41 | * 42 | * key: 元素信息 43 | * value: 元素在 list 中对应的节点信息 44 | * @since 0.0.13 45 | */ 46 | private Map> indexMap; 47 | 48 | public LruMapDoubleList() { 49 | this.indexMap = new HashMap<>(); 50 | this.head = new DoubleListNode<>(); 51 | this.tail = new DoubleListNode<>(); 52 | 53 | this.head.next(this.tail); 54 | this.tail.pre(this.head); 55 | } 56 | 57 | @Override 58 | public ICacheEntry removeEldest() { 59 | // 获取尾巴节点的前一个元素 60 | DoubleListNode tailPre = this.tail.pre(); 61 | if(tailPre == this.head) { 62 | log.error("当前列表为空,无法进行删除"); 63 | throw new CacheRuntimeException("不可删除头结点!"); 64 | } 65 | 66 | K evictKey = tailPre.key(); 67 | V evictValue = tailPre.value(); 68 | 69 | // 执行删除 70 | this.removeKey(evictKey); 71 | 72 | return CacheEntry.of(evictKey, evictValue); 73 | } 74 | 75 | /** 76 | * 放入元素 77 | * 78 | * (1)删除已经存在的 79 | * (2)新元素放到元素头部 80 | * 81 | * @param key 元素 82 | * @since 0.0.13 83 | */ 84 | @Override 85 | public void updateKey(final K key) { 86 | //1. 执行删除 87 | this.removeKey(key); 88 | 89 | //2. 新元素插入到头部 90 | //head<->next 91 | //变成:head<->new<->next 92 | DoubleListNode newNode = new DoubleListNode<>(); 93 | newNode.key(key); 94 | 95 | DoubleListNode next = this.head.next(); 96 | this.head.next(newNode); 97 | newNode.pre(this.head); 98 | next.pre(newNode); 99 | newNode.next(next); 100 | 101 | //2.2 插入到 map 中 102 | indexMap.put(key, newNode); 103 | } 104 | 105 | /** 106 | * 移除元素 107 | * 108 | * 1. 获取 map 中的元素 109 | * 2. 不存在直接返回,存在执行以下步骤: 110 | * 2.1 删除双向链表中的元素 111 | * 2.2 删除 map 中的元素 112 | * 113 | * @param key 元素 114 | * @since 0.0.13 115 | */ 116 | @Override 117 | public void removeKey(final K key) { 118 | DoubleListNode node = indexMap.get(key); 119 | 120 | if(ObjectUtil.isNull(node)) { 121 | return; 122 | } 123 | 124 | // 删除 list node 125 | // A<->B<->C 126 | // 删除 B,需要变成: A<->C 127 | DoubleListNode pre = node.pre(); 128 | DoubleListNode next = node.next(); 129 | 130 | pre.next(next); 131 | next.pre(pre); 132 | 133 | // 删除 map 中对应信息 134 | this.indexMap.remove(key); 135 | log.debug("从 LruMapDoubleList 中移除 key: {}", key); 136 | } 137 | 138 | @Override 139 | public boolean isEmpty() { 140 | return indexMap.isEmpty(); 141 | } 142 | 143 | @Override 144 | public boolean contains(K key) { 145 | return indexMap.containsKey(key); 146 | } 147 | 148 | } 149 | -------------------------------------------------------------------------------- /CR-core/src/main/java/core/support/struct/package-info.java: -------------------------------------------------------------------------------- 1 | package core.support.struct; -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | CacheRedis 是一个使用 Java 语言制作的仿 Redis 本地缓存。 2 | 简述一下它的优点: 3 | 4 | - **较强的可拓展性**,可以实现自定义淘汰策略、驱逐策略、过期策略等 5 | - **实现多种原生特性**,支持数据缓存、缓存失效时间、数据淘汰策略(如FIFO 、 LRU )、RDB 和 AOF 持久化等等。 6 | - **较为完善的日志体系**,提供删除日志与慢日志记录 7 | 8 | 截至2023.05.09 更新,新发现问题记录如下:(会不断解决) 9 | 10 | String 类型 get 方法返回值自动识别问题 11 | 12 | 13 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.example 8 | CacheRedis 9 | pom 10 | 1.0-SNAPSHOT 11 | 12 | CR-api 13 | CR-core 14 | 15 | 16 | 17 | 18 | 3.2 19 | 3.2 20 | 2.18.1 21 | false 22 | false 23 | 24 | 2.2.1 25 | 2.9.1 26 | 1.5 27 | 28 | 4.3.0 29 | 2.7 30 | 31 | 32 | UTF-8 33 | 1.7 34 | 35 | 36 | 0.1.117 37 | 0.0.1 38 | 0.0.3 39 | 1.1.8 40 | 41 | 42 | 4.12 43 | 1.2.70 44 | 45 | 17 46 | 17 47 | 48 | 49 | 50 | 51 | com.github.houbb 52 | log-integration 53 | ${log-integration.version} 54 | 55 | 56 | com.github.houbb 57 | heaven 58 | ${heaven.version} 59 | 60 | 61 | com.github.houbb 62 | aop-core 63 | ${aop.version} 64 | 65 | 66 | org.example 67 | CR-api 68 | 1.0-SNAPSHOT 69 | 70 | 71 | org.example 72 | CR-core 73 | 1.0-SNAPSHOT 74 | 75 | 76 | com.alibaba 77 | fastjson 78 | ${fastjson.version} 79 | 80 | 81 | 82 | --------------------------------------------------------------------------------