当前位置: 移动技术网 > IT编程>开发语言>Java > ehcache模糊批量移除缓存的方法

ehcache模糊批量移除缓存的方法

2019年07月19日  | 移动技术网IT编程  | 我要评论
前言 众所周知,encache是现在最流行的java开源缓存框架,配置简单,结构清晰,功能强大。通过注解 @cacheable 可以快速添加方法结果到缓存。通过 @cac

前言

众所周知,encache是现在最流行的java开源缓存框架,配置简单,结构清晰,功能强大。通过注解 @cacheable 可以快速添加方法结果到缓存。通过 @cacheevict 可以快速清除掉指定的缓存。

但由于 @cacheevict 注解使用的是key-value的,不支持模糊删除,就会遇到问题。当我用 @cacheable 配合spring el表达式添加了同一方法的多个缓存比如:

@getmapping("/listoftask/{page}/")
@cacheable(value = "businesscache", key = "'listoftask_'+ #page")
public responsemessage<pagetaskvo> gettasklist(@pathvariable("page") string page) {
  do something...
}

上述代码是分页获取任务信息。用el表达式获取到参数中的page,并作为缓存的key,使用 @cacheable 添加到ehcache的缓存中。此时,在缓存中就会出现 listoftask_1 , listoftask_2 , listoftask_3 这种类型的key。

当添加、删除任务时,列表就会发生改变。这时候,就需要把 listoftask_* 相关的缓存全部去掉。而这时,我不知道缓存中到底缓存了多少和 listoftask_* 相关的内容,不可能调用 @cacheevict 挨个删除。

既然ehcache本身无法支持,那就只能靠我们自己实现了。

实现

考虑到使用的注解添加的缓存,那么移除缓存也使用注解处理,可以保持开发的一致性。注解对开发者来说也很友好。那么我们就考虑使用自定义注解来来模糊批量移除缓存。

首先,定义注解 cacheremove :

@target({ java.lang.annotation.elementtype.method })
@retention(retentionpolicy.runtime)
public @interface cacheremove {
  string value();
  string[] key();
}

其中,value 同 ehcache 一样,用于定义要操作的缓存名。key 是一个数组,用于存放多种缓存 key 的正则表达式。起名 cacheremove 清晰易懂,也不与 ehcache 本身的注解冲突。注解的定义到此为止。接下来,就需要处理注解了,由于使用的 spring 框架,很自然的,就会想到用 aop 来做注解的具体实现。

注解的目的是批量模糊移除缓存。需考虑如下两个问题:

  1. 用什么方式模糊匹配
  2. 怎么批量删除key

我给出的处理方式,也是我认为最简单的处理方式是:

  1. 用什么方式模糊匹配 —— cacheremove 中的key传正则,可以传多个,使用正则匹配
  2. 怎么批量删除key —— 循环所有的key,找到匹配正则的就删除

首先定义类名 cacheremoveaspect :

@aspect
@component
public class cacheremoveaspect {
  @pointcut(value = "(execution(* *.*(..)) && @annotation(com.example.cacheremove))")
  private void pointcut() {}

  do something...
}

在切面中定义切点,使用 execution(* *.*(..) && @annotation(com.example.cacheremove)) 表示所有带注解类 cacheremove 都执行, @annotation 中的值是注解的全限定名。

切点定义完毕,下面的重头戏就是切面的具体实现了。一般来说,缓存会在增删改的方法执行完后才要移除。所以使用 @afterreturning() 来实现。在具体实现中需要做以下几件事:

  1. 拦截方法上的注解
  2. 判断注解是不是 cacheremove
  3. 由于注解传入的 key 是个数组,循环处理每个key
  4. 在循环中编制每个 key 为 pattern, 并循环所有的缓存,移除匹配上的缓存

具体实现如下:

@afterreturning(value = "pointcut()")
private void process(joinpoint joinpoint){
  methodsignature signature = (methodsignature) joinpoint.getsignature();
  method method = signature.getmethod();
  cacheremove cacheremove = method.getannotation(cacheremove.class);

  if (cacheremove != null){
    string value = cacheremove.value();
    string[] keys = cacheremove.key(); //需要移除的正则key

    list cachekeys = cacheutils.cachekeys(value);
    for (string key : keys){
      pattern pattern = pattern.compile(key);
      for (object cachekey: cachekeys) {
        string cachekeystr = string.valueof(cachekey);
        if (pattern.matcher(cachekeystr).find()){
          cacheutils.remove(value, cachekeystr);
        }
      }
    }
  }
}

以上,为 ehcache 模糊批量移除缓存的具体实现。其中 businesscacheutils 为自己封装的 ehcache 工具类。主要实现获取缓存池,获取缓存,移除缓存,添加缓存,查看所有缓存等正常功能。代码如下:

public class cacheutils {

  private static cachemanager cachemanager = springcontextholder.getbean("ehcachemanagerfactory");

  public static object get(string cachename, string key) {
    element element = getcache(cachename).get(key);
    return element == null ? null : element.getobjectvalue();
  }

  public static void put(string cachename, string key, object value) {
    element element = new element(key, value);
    getcache(cachename).put(element);
  }

  public static void remove(string cachename, string key) {
    getcache(cachename).remove(key);
  }

  public static list cachekeys(string cachename){
    return getcache(cachename).getkeys();
  }

  /**
   * 获得一个cache,没有则创建一个。
   * @param cachename
   * @return
   */
  private static cache getcache(string cachename) {
    cache cache = cachemanager.getcache(cachename);
    if (cache == null) {
      cachemanager.addcache(cachename);
      cache = cachemanager.getcache(cachename);
      cache.getcacheconfiguration().seteternal(true);
    }
    return cache;
  }

  public static cachemanager getcachemanager() {
    return cachemanager;
  }

}

至此,整个ehcache 模糊批量移除缓存的功能就实现了。

总结

整个过程思路简单,用到了一些 aop 的知识就完成了需要的功能。但具体的移除部分代码可考虑进行优化。通过一次缓存的全部循环,就把需要移除的缓存都移除干净,而不是想现在这样有几个key,就全缓存遍历几次。具体实现留给读者自行完成。希望对各位有所帮助。也希望大家多多支持移动技术网。

如您对本文有疑问或者有任何想说的,请 点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网