Est-il possible d’utiliser des caractères génériques dans @CacheEvict?
J’ai une application avec plusieurs locataires qui nécessite parfois d’expulser toutes les données du cache du locataire, mais pas de tous les locataires du système.
Considérez la méthode suivante:
@Cacheable(value="users", key="T(Security).getTenant() + #user.key") public List getUsers(User user) { ... }
Comme pour 99% des questions de l’univers, la réponse est: cela dépend. Si votre gestionnaire de cache implémente quelque chose qui traite de cela, tant mieux. Mais cela ne semble pas être le cas.
Si vous utilisez SimpleCacheManager , un gestionnaire de cache en mémoire de base fourni par Spring, vous utilisez probablement ConcurrentMapCache fourni avec Spring. Bien qu’il ne soit pas possible d’étendre ConcurrentMapCache pour traiter les caractères génériques dans les clés (car le magasin de cache est privé et vous ne pouvez pas y accéder), vous pouvez simplement l’utiliser comme source d’inspiration pour votre propre implémentation.
Ci-dessous, une implémentation possible (je ne l’ai pas vraiment testée à part pour vérifier si elle fonctionnait). Ceci est une copie ConcurrentMapCache de ConcurrentMapCache avec une modification de la méthode evict() . La différence est que cette version de evict() traite la clé pour voir si c’est une regex. Dans ce cas, il parcourt toutes les clés du magasin et supprime celles qui correspondent à la 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 Ssortingng name; private final ConcurrentMap
J’espère que les lecteurs sauront initialiser le gestionnaire de cache avec une implémentation de cache personnalisée. Il existe de nombreux documents qui vous montrent comment faire cela. Une fois votre projet correctement configuré, vous pouvez utiliser l’annotation normalement comme suit:
Encore une fois, ceci est loin d’être correctement testé, mais cela vous donne le moyen de faire ce que vous voulez. Si vous utilisez un autre gestionnaire de cache, vous pouvez également étendre son implémentation de cache.
La réponse est: non.
Et ce n’est pas un moyen facile d’atteindre ce que vous voulez.
Les annotations Spring Cache doivent être simples pour pouvoir être facilement implémentées par le fournisseur de cache.
La mise en cache efficace doit être simple. Il y a une clé et une valeur. Si key est trouvé dans le cache, utilisez la valeur, sinon calculez la valeur et mettez-la en cache. La clé efficace doit avoir des équals rapides et honnêtes () et hashcode () . Supposons que vous ayez mis en cache plusieurs paires (clé, valeur) d’un client hébergé. Pour des raisons d’ efficacité, les différentes clés doivent avoir un hashcode () différent . Et vous décidez d’expulser tout le locataire. Il n’est pas facile de trouver des éléments locataires dans le cache. Vous devez itérer toutes les paires mises en cache et ignorer les paires appartenant au locataire. Ce n’est pas efficace. Ce n’est plutôt pas atomique, donc c’est compliqué et a besoin d’une certaine synchronisation. La synchronisation n’est pas efficace.
Donc non
Mais si vous trouvez une solution, dites-moi, car la fonctionnalité que vous souhaitez est vraiment utile.
Ci-dessous a fonctionné pour moi sur Redis Cache. Supposons que vous souhaitiez supprimer toutes les entrées du cache avec le préfixe de clé: ‘nom-cache: nom-object: clé-parent’. Méthode d’appel avec valeur de clé cache-name:object-name:parentKey* .
import org.springframework.data.redis.core.RedisOperations; ... private final RedisOperations redisTemplate; ... public void evict(Object key) { redisTemplate.delete(redisTemplate.keys(key)); }
De RedisOperations.java
/** * Delete given {@code keys}. * * @param keys must not be {@literal null}. * @return The number of keys that were removed. * @see Redis Documentation: DEL */ void delete(Collection keys); /** * Find all keys matching the given {@code pattern}. * * @param pattern must not be {@literal null}. * @return * @see Redis Documentation: KEYS */ Set keys(K pattern);