Хорошо, мне удалось решить это:
public class IndexedCache<K,V> implements Cache<K,V> {
@Delegate
private Cache<K, V> cache;
private Map<Class<?>, Map<Object, Set<K>>> indexes;
private IndexedCache(Builder<K, V> bldr){
this.indexes = bldr.indexes;
cache = bldr.caf.build();
}
public <R> void invalidateAllWithIndex(Class<R> clazz, R value) {
cache.invalidateAll(indexes.get(clazz).getOrDefault(value, new HashSet<>()));
}
public static class Builder<K, V>{
Map<Class<?>, Function<K, ?>> functions = new HashMap<>();
Map<Class<?>, Map<Object, Set<K>>> indexes = new ConcurrentHashMap<>();
Caffeine<K,V> caf;
public <R> Builder<K,V> withIndex(Class<R> clazz, Function<K, R> function){
functions.put(clazz, function);
indexes.put(clazz, new ConcurrentHashMap<>());
return this;
}
public IndexedCache<K, V> buildFromCaffeine(Caffeine<Object, Object> caffeine) {
caf = caffeine.writer(new CacheWriter<K, V>() {
@Override
public void write( K k, V v) {
for(Map.Entry<Class<?>, Map<Object, Set<K>>> indexesEntry : indexes.entrySet()){
indexesEntry.getValue().computeIfAbsent(functions.get(indexesEntry.getKey()).apply(k), (ky)-> new HashSet<>())
.add(k);
}
}
@Override
public void delete( K k, V v, RemovalCause removalCause) {
for(Map.Entry<Class<?>, Map<Object, Set<K>>> indexesEntry : indexes.entrySet()){
indexesEntry.getValue().remove(functions.get(indexesEntry.getKey()).apply(k));
}
}
});
return new IndexedCache<>(this);
}
}
}
и это вариант использования:
@AllArgsConstructor
@Data
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
static class CompositeKey{
@EqualsAndHashCode.Include
Integer k1;
String k2;
Long k3;
}
public static void main(String[] args) {
Caffeine<Object, Object> cfein = Caffeine.newBuilder().softValues().maximumSize(200_000);
IndexedCache<CompositeKey, String> cache = new IndexedCache.Builder<CompositeKey, String>()
.withIndex(Long.class, ck -> ck.getK3())
.withIndex(String.class, ck -> ck.getK2())
.buildFromCaffeine(cfein);
for(int i=0; i<100; i++){
cache.put(new CompositeKey(i, String.valueOf(i), Long.valueOf(i)), "sdfsdf");
}
for(int i=0; i<10; i++){
//use equals method of CompositeKey to do equals comp.
cache.invalidate(new CompositeKey(i, String.valueOf(i), Long.valueOf(i)));
}
for(int i=10; i<20; i++){
//use Long index
cache.invalidateAllWithIndex(Long.class, Long.valueOf(i));
}
for(int i=20; i<30; i++){
//use String index
cache.invalidateAllWithIndex(String.class, String.valueOf(i));
}
int y = 4;
}
вот ссылка на обсуждение, которое у меня было: https://github.com/ben-manes/caffeine/issues/279