博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
fhs-framework jetcache 缓存维护之自动清除缓存
阅读量:4071 次
发布时间:2019-05-25

本文共 4984 字,大约阅读时间需要 16 分钟。

@Cached(name = "contractOrPdInfo",timeUnit = TimeUnit.HOURS,expire = 24) @CacheRefresh(refresh = 1,timeUnit = TimeUnit.HOURS)     public ContractDetailVO findDetailByPdBaseIdAndContractBaseIdAndVersion(Integer pdBaseId, Integer contractBaseId, Double version) {     code.....}

 比如我使用注解创建了方法缓存,我方法返回的vo是 几张表的数据组合而成的,这几张表的数据有改动的话,这个方法的缓存也会过期.JetCache 提供了CacheRefresh  注解,我们可以设置缓存自动刷新时间,到了时间,他会解析出每个缓存key对应的方法参数,然后调用你这个方法,把得到的结果更新到缓存的value中.但是实时性不高.不满足我的需求.

   于是我就想办法如何主动通知jetcache,去清除这个方法的所有缓存,因为方法参数并不包含我那几张表的全部id,所以只能吧缓存全部清除,让他下一次读取不到缓存.

  要解决这个问题要有以下几个步骤:

   1  给表定义别名  我称之为 namespace   比如t_user的namespace是 user

   2 添加自定义注解,获取一个方法的缓存数据依赖哪几张表. 注解名字为:AutoClearCache

    

/** * fhs framework 对于 jetcahce的扩展注解 * 用于namespaces  的数据改变之后 自动清除缓存 * by wanglei */@Documented@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.METHOD, ElementType.FIELD,ElementType.TYPE,})public @interface AutoClearCache {    /**     * 需要自动清除缓存的命名空间     * @return     */    String[] namespaces() default {};}

   

    3  搞一个管理器,允许业务根据namespace 去清除此namespace相关的 方法缓存.

         管理器大概这么几个部分:

         A   项目启动后,根据注解找到所有的需要CacheUpdateManager  管理的所有的方法,缓存起来,建立好和namespace的关系

        B  当有业务要调用clearcache的时候,根据namespace找到 相关的方法对象.

             然后根据方法对象找到缓存对象(不同版本的jetcache 实现方法不同,我用的2.5.16)

             根据方法对象找到所有的刷新缓存的task,根据task可以找到缓存的key

              然后调用缓存的.remove方法吧对应的key干掉.      

 

** * 缓存刷新管理器 * 在项目启动完成后获取所有的@AutoRefresCache  标记的方法 */@Datapublic class CacheUpdateManager implements ApplicationContextAware, ApplicationListener
{ /** * service的包路径 */ private String[] packageNames = new String[]{}; @Autowired private ConfigMap cacheConfigMap; private ApplicationContext applicationContext; private GlobalCacheConfig globalCacheConfig; /** * key namespace value value namespace 对应的刷新器 */ private Map
> methodPontMap = new HashMap<>(); @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } /** * 清除某个namespace的所有缓存 * * @param namespace */ public void clearCache(String namespace) { List
methodPoints = methodPontMap.get(namespace); if (methodPoints == null || methodPoints.isEmpty()) { return; } for (MethodPoint methodPoint : methodPoints) { clearAndRefreshMethodCache(methodPoint); } } /** * 清除并且自动刷新方法缓存 * * @param point 方法 */ public void clearAndRefreshMethodCache(MethodPoint point) { if (globalCacheConfig == null) { globalCacheConfig = applicationContext.getBean(GlobalCacheConfig.class); } if (globalCacheConfig == null || !globalCacheConfig.isEnableMethodCache()) { return; } String key = CachePointcut.getKey(point.getMethod(), point.getClazz()); CacheInvokeConfig cac = cacheConfigMap.getByMethodInfo(key); if (cac == null || cac == CacheInvokeConfig.getNoCacheInvokeConfigInstance()) { return; } CacheInvokeContext context = globalCacheConfig.getCacheContext().createCacheInvokeContext(cacheConfigMap); context.setCacheInvokeConfig(cac); context.setHiddenPackages(globalCacheConfig.getHiddenPackages()); CacheInvokeConfig cic = context.getCacheInvokeConfig(); CachedAnnoConfig cachedAnnoConfig = cic.getCachedAnnoConfig(); Cache cache = context.getCacheFunction().apply(context, cachedAnnoConfig); if(cache == null){ return; } if (cache instanceof RefreshCache) { ConcurrentHashMap
taskMap = (ConcurrentHashMap
) ReflectUtils.getValue(cache, "taskMap"); if (taskMap != null && !taskMap.isEmpty()) { Collection
tasks = taskMap.values(); for (RefreshCache.RefreshTask task : tasks) { cache.remove(ReflectUtils.getValue(task, "key")); } } } } @Override public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) { //spring容器初始化完成之后,就会自行此方法。 Set
> entitySet = ScannerUtils.scan(AutoClearCache.class, packageNames); // 遍历所有class,获取所有用@autowareYLM注释的字段 if (entitySet != null) { String[] namespaces = null; for (Class
entity : entitySet) { //过滤 包含注解并且是public的缓存 List
methods = ReflectUtils.getAllMethod(entity).stream().filter(method -> (method.getModifiers() & 1) == 1) .filter(method -> method.isAnnotationPresent(AutoClearCache.class)).collect(Collectors.toList()); for (Method method : methods) { namespaces = method.getAnnotation(AutoClearCache.class).namespaces(); for (String namespace : namespaces) { MethodPoint tempPoint = MethodPoint.builder().clazz(entity) .method(method).build(); List
points = methodPontMap.containsKey(namespace) ? methodPontMap.get(namespace) : new ArrayList<>(); points.add(tempPoint); methodPontMap.put(namespace, points); } } } } }}/** * 方法 */@Data@AllArgsConstructor@NoArgsConstructor@Builderclass MethodPoint { private Method method; private Class clazz;}

全部源码地址:

开源项目地址:

fhs framework qq群:976278956

转载地址:http://yhwni.baihongyu.com/

你可能感兴趣的文章
java接口不能实例化原因浅谈
查看>>
Https加密及攻防
查看>>
Java生成随机不重复推广码邀请码
查看>>
Java8 Lambda表达式介绍
查看>>
Java8 stream流介绍
查看>>
Java多线程之synchronized及死锁编写
查看>>
Java NIO源码剖析及使用实例(一):Buffer
查看>>
[swift实战入门]手把手教你编写2048(一)
查看>>
[swift实战入门]手把手教你编写2048(二)
查看>>
Java 爬虫入门(网易云音乐和知乎实例)
查看>>
[swift实战入门]手把手教你编写2048(三)
查看>>
堆排序原理(图)及java版代码
查看>>
【JAVA数据结构】栈(数组实现)
查看>>
【JAVA数据结构】双向链表
查看>>
【JAVA数据结构】先进先出队列
查看>>
String类的intern方法随笔
查看>>
【泛型】一个简易的对象间转换的工具类(DO转VO)
查看>>
flex编译时,会把trace语句也编译进去
查看>>
Timer的repeatCount和currentCount的区别
查看>>
as3工程和flex工程的区别
查看>>