java - Spring @CacheEvict using wildcards -


is there way of using wildcards in @cacheevict?

i have application multi-tenancy needs evict data cache of tenant, not of tenants in system.

consider following method:

@cacheable(value="users", key="t(security).gettenant() + #user.key") public list<user> getusers(user user) {     ... } 

so, like:

@cacheevict(value="users", key="t(security).gettenant() + *") public void deleteorganization(organization organization) {     ... } 

is there anyway it?

as 99% of every question in universe, answer is: depends. if cache manager implements deals that, great. doesn't seem case.

if you're using simplecachemanager, basic in-memory cache manager provided spring, you're using concurrentmapcache comes spring. although it's not possible extend concurrentmapcache deal wildcards in keys (because cache store private , can't access it), use inspiration own implementation.

below there's possible implementation (i didn't test other check if it's working). plain copy of concurrentmapcache modification on evict() method. difference version of evict() treats key see if it's regex. in case, iterates through keys in store , evict ones match regex.

package com.sigraweb.cache;  import java.io.serializable; import java.util.concurrent.concurrenthashmap; import java.util.concurrent.concurrentmap;  import org.springframework.cache.cache; import org.springframework.cache.support.simplevaluewrapper; import org.springframework.util.assert;  public class regexkeycache implements cache {     private static final object null_holder = new nullholder();      private final string name;      private final concurrentmap<object, object> store;      private final boolean allownullvalues;      public regexkeycache(string name) {         this(name, new concurrenthashmap<object, object>(256), true);     }      public regexkeycache(string name, boolean allownullvalues) {         this(name, new concurrenthashmap<object, object>(256), allownullvalues);     }      public regexkeycache(string name, concurrentmap<object, object> store, boolean allownullvalues) {         assert.notnull(name, "name must not null");         assert.notnull(store, "store must not null");         this.name = name;         this.store = store;         this.allownullvalues = allownullvalues;     }      @override     public final string getname() {         return this.name;     }      @override     public final concurrentmap<object, object> getnativecache() {         return this.store;     }      public final boolean isallownullvalues() {         return this.allownullvalues;     }      @override     public valuewrapper get(object key) {         object value = this.store.get(key);         return towrapper(value);     }      @override     @suppresswarnings("unchecked")     public <t> t get(object key, class<t> type) {         object value = fromstorevalue(this.store.get(key));         if (value != null && type != null && !type.isinstance(value)) {             throw new illegalstateexception("cached value not of required type [" + type.getname() + "]: " + value);         }         return (t) value;     }      @override     public void put(object key, object value) {         this.store.put(key, tostorevalue(value));     }      @override     public valuewrapper putifabsent(object key, object value) {         object existing = this.store.putifabsent(key, value);         return towrapper(existing);     }      @override     public void evict(object key) {         this.store.remove(key);         if (key.tostring().startswith("regex:")) {             string r = key.tostring().replace("regex:", "");             (object k : this.store.keyset()) {                 if (k.tostring().matches(r)) {                     this.store.remove(k);                 }             }         }     }      @override     public void clear() {         this.store.clear();     }      protected object fromstorevalue(object storevalue) {         if (this.allownullvalues && storevalue == null_holder) {             return null;         }         return storevalue;     }      protected object tostorevalue(object uservalue) {         if (this.allownullvalues && uservalue == null) {             return null_holder;         }         return uservalue;     }      private valuewrapper towrapper(object value) {         return (value != null ? new simplevaluewrapper(fromstorevalue(value)) : null);     }      @suppresswarnings("serial")     private static class nullholder implements serializable {     } } 

i trust readers know how initialize cache manager custom cache implementation. there's lots of documentation out there shows how that. after project configured, can use annotation so:

@cacheevict(value = { "cachename" }, key = "'regex:#tenant'+'.*'") public mymethod(string tenant){ ... } 

again, far being tested, gives way want. if you're using cache manager, extends cache implementation similarly.


Comments