# Jetcache踩坑合集

## 写在前面

本文主要是记录个人在使用jetcache时遇到的一些问题以及相应的解决方案，次之是将这些问题和解决方案发布到互联网中希望能帮助到一些人，如果觉得文章写得还不错，可以点赞收藏以鼓励我继续更新博客，这将对我非常重要。

流水账子标题中重复带上jetcache关键字主要是为了提高搜索的准确性，本身文章上下文已足够表达含义，但是为了优化搜索情况特意加上的。

## 踩坑流水账

### jetcache默认返回值为null时候，不会缓存

这个是jetcache的默认策略，我之所以遇到这个问题是我自己写的测试代码时直接返回了null，我误认为是我spring aop配置有问题，导致缓存没有生效，实则是jetcache默认策略。

在`com.alicp.jetcache.anno.Cached`注解中有一个属性`cacheNullValue`，默认值为false，表示不缓存空值。

### jetcache不支持模糊清空缓存

这点其实在GitHub issue清单中有好几个[issue](https://github.com/alibaba/jetcache/issues?q=is%3Aissue+is%3Aopen+%E6%A8%A1%E7%B3%8A) 都是与这个问题相关的，如果你也是从Spring Cache转到jetcache，由于缺少模糊清空缓存，会导致整个系统原有的实现都必须调整。

这个特性主要影响到缓存的数据是一个列表或者是一整颗树的情况，当列表或树中部分值更新以后，这个列表的缓存或树的缓存没有办法更新。

### jetcache多节点缓存清空需要先有@Cached注册

这个是jetcache比较新的特性了，利用了`CacheMonitor`接口，并且在这个的基础上抽象了一个`com.alicp.jetcache.support.BroadcastManager`支持了更多的中间件，并且对于循环通知的问题有一个很好的解决方案。

但是jetcache只考虑到了同一份代码多节点部署的情况，我的实际应用场景比这个更复杂一些。

```java
private void processCacheMessage(CacheMessage cacheMessage) {  
    if (sourceId.equals(cacheMessage.getSourceId())) {  
        return;  
    }  
    Cache cache = cacheManager.getCache(cacheMessage.getArea(), cacheMessage.getCacheName());  
    if (cache == null) {  
        logger.warn("Cache instance not exists: {},{}", cacheMessage.getArea(), cacheMessage.getCacheName());  
        return;    }  
    Cache absCache = CacheUtil.getAbstractCache(cache);  
    if (!(absCache instanceof MultiLevelCache)) {  
        logger.warn("Cache instance is not MultiLevelCache: {},{}", cacheMessage.getArea(), cacheMessage.getCacheName());  
        return;    }  
    Cache[] caches = ((MultiLevelCache) absCache).caches();  
    Set<Object> keys = Stream.of(cacheMessage.getKeys()).collect(Collectors.toSet());  
    for (Cache c : caches) {  
        Cache localCache = CacheUtil.getAbstractCache(c);  
        if (localCache instanceof AbstractEmbeddedCache) {  
            ((AbstractEmbeddedCache) localCache).__removeAll(keys);  
        } else {  
            break;  
        }  
    }  
}
```

在这个方法中，是直接通过`cacheManager`实例去获取的，

当然这个问题也很好解决，你可以把这个模块的代码抽取出来，新建maven的module即可解决。

又或是直接增加`@Cached`注解声明即可。

### jetcache的key必须是一个EL表达式的key，不能是固定字符串

不太确定是不是jetcache特意为之，但是在使用过程中稍微注意一下即可

### jetcache在遇到参数是集合的时候，key不可以是EL表达式

在这个[方法](https://github.com/alibaba/jetcache/blob/cc5e9407202855dd2391d6f6dd0e319b3a9a01ad/jetcache-anno/src/main/java/com/alicp/jetcache/anno/method/CacheHandler.java#L183-L229) 中，你可以看到当`@CacheInvalidate`中的`multi`属性声明为true时，可以看到调用了一个`toIterable`方法，而这个方法的实现则是

```java
private static Iterable toIterable(Object obj) {  
    if (obj.getClass().isArray()) {  
        if (obj instanceof Object[]) {  
            return Arrays.asList((Object[]) obj);  
        } else {  
            List list = new ArrayList();  
            int len = Array.getLength(obj);  
            for (int i = 0; i < len; i++) {  
                list.add(Array.get(obj, i));  
            }  
            return list;  
        }  
    } else if (obj instanceof Iterable) {  
        return (Iterable) obj;  
    } else {  
        return null;  
    }  
}
```

只能说jetcache支持了EL表达式，但是又没有完全支持。
