Je veux avoir plusieurs gestionnaires de cache de printemps configurés dans mon application Web et je pourrais utiliser différents gestionnaires de cache à différents endroits de mon projet. Est-ce qu'il y a un moyen de faire ça.
Vous pouvez procéder de plusieurs manières et la bonne réponse dépend de votre utilisation du cache.
Si vous utilisez CacheManager A pour 90% de votre cas d'utilisation et B pour 10%, je vous conseille de créer un CacheManager
par défaut pour A (vous devrez le spécifier via une extension CacheConfigurerSupport
), quelque chose comme:
@Configuration
@EnableCaching
public class CacheConfig extends CachingConfigurerSupport {
@Override
@Bean // not strictly necessary
public CacheManager cacheManager() { ... CacheManager A }
@Bean
public CacheManager bCacheManager() { ... CacheManager B }
}
Ensuite, pour le cas d'utilisation de 10%, vous ajoutez un CacheConfig
en haut des classes qui doivent utiliser l'autre gestionnaire de cache
@CacheConfig(cacheManager="bCacheManager")
public class MyService { /*...*/ }
Si vous devez utiliser l'autre gestionnaire de cache pour une seule méthode, vous pouvez également le spécifier au niveau de la méthode
@Cacheable(cacheNames = "books", cacheManager = "bCacheManager")
public Book findById(long id) { /*...*/ }
Si vous n'êtes pas dans cette situation, vous avez besoin d'un moyen de savoir quel gestionnaire de cache doit être utilisé au cas par cas. Vous pouvez le faire en fonction du type de cible (MyService
) ou du nom du cache (books
). Vous devrez implémenter un CacheResolver
qui fera cette traduction pour vous.
@Configuration
@EnableCaching
public class CacheConfig extends CachingConfigurerSupport {
@Override
public CacheResolver cacheResolver() { ... }
}
Vérifiez le javadoc de CacheResolver
pour plus de détails. Dans l'implémentation, vous pouvez avoir plusieurs instances CacheManager
(en tant que bean ou non) que vous appellerez en interne en fonction de votre logique pour déterminer le gestionnaire à utiliser.
J'ai vu dans un commentaire que vous parliez de "module". La mise en cache est vraiment une question d'infrastructure, je vous conseille donc fortement de déplacer cette décision au niveau de l'application. Vous pouvez marquer le cache comme étant "local" et d'autres étant "en cluster". Mais vous devriez probablement avoir une sorte de nomenclature pour le nom pour le rendre plus facile. Ne choisissez pas un gestionnaire de cache au niveau du module.
ce billet de blog illustre cela avec d'autres exemples.
Comme l'explique @Stephane Nicoll, vous avez plusieurs options. Je vais essayer de donner quelques informations sur les CacheResolver
personnalisés. CacheResolver
a une méthode:
Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context);
qui donne un contexte à la classe, la méthode, les arguments, etc. de l'opération pouvant être mise en cache.
Dans sa forme de base:
public class CustomCacheResolver implements CacheResolver {
private final CacheManager cacheManager;
public CustomCacheResolver(CacheManager cacheManager){
this.cacheManager = cacheManager;
}
@Override
public Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context) {
Collection<Cache> caches = getCaches(cacheManager, context);
return caches;
}
private Collection<Cache> getCaches(CacheManager cacheManager, CacheOperationInvocationContext<?> context) {
return context.getOperation().getCacheNames().stream()
.map(cacheName -> cacheManager.getCache(cacheName))
.filter(cache -> cache != null)
.collect(Collectors.toList());
}
}
Ici, j'utilise un CacheManager
par souci de concision. Mais vous pouvez lier différents CacheManager
à CacheResolver
et effectuer des sélections plus granulaires: si le nom de la classe est X
, alors utilisez GuavaCacheManager
, sinon utilisez EhCacheCacheManager
.
Après cette étape, vous devez enregistrer CacheResolver
, (encore une fois, vous pouvez lier plus CacheManagers
ici):
@Configuration
@EnableCaching
public class CacheConfiguration extends CachingConfigurerSupport {
@Bean
@Override
public CacheManager cacheManager() {
// Desired CacheManager
}
@Bean
@Override
public CacheResolver cacheResolver() {
return new CustomCacheResolver(cacheManager());
}
}
Et comme dernière étape, vous devez spécifier CustomCacheResolver
dans l'un des @Cacheable
, @CachePut
, @CacheConfig
etc. annotations.
@Cacheable(cacheResolver="cacheResolver")
Vous pouvez regarder ici pour des exemples de code.