Как настроить конфигурацию менеджера кэшей в spring кеш-java

Я хочу, чтобы в моем веб-приложении было настроено несколько менеджеров кэшей spring, и я мог бы использовать другой менеджер кэша в разных местах моего проекта. Есть ли способ сделать это.

Ответ 1

Есть несколько способов сделать это, и правильный ответ зависит от того, как вы используете кеш.

У вас есть "главный" менеджер кэша

Если вы используете CacheManager A для 90% вашего варианта использования и B для 10%, я бы посоветовал создать по умолчанию CacheManager для A (вам нужно будет указать его с помощью расширения CacheConfigurerSupport), что-то вроде:

@Configuration
@EnableCaching
public class CacheConfig extends CachingConfigurerSupport {

    @Override
    @Bean // not strictly necessary
    public CacheManager cacheManager() { ... CacheManager A }

    @Bean
    public CacheManager bCacheManager() { ... CacheManager B }
}

Затем для 10% сценария использования вы добавляете CacheConfig вверху классов, которые должны использовать другой менеджер кэша

@CacheConfig(cacheManager="bCacheManager")
public class MyService { /*...*/ }

Если вам нужно использовать другой диспетчер кэша только для одного метода, вы можете указать это и на уровне метода

@Cacheable(cacheNames = "books", cacheManager = "bCacheManager")
public Book findById(long id) { /*...*/ }

Более мелкозернистое разрешение

Если вы не в такой ситуации, вам нужен способ узнать, какой менеджер кэша нужно использовать в каждом конкретном случае. Вы можете сделать это на основе типа цели (MyService) или имени кэша (books). Вам нужно будет реализовать CacheResolver, который сделает этот перевод за вас.

@Configuration
@EnableCaching
public class CacheConfig extends CachingConfigurerSupport {

    @Override
    public CacheResolver cacheResolver() { ... }
}

Проверьте Javadoc CacheResolver для более подробной информации. В этой реализации у вас может быть несколько экземпляров CacheManager (в виде бина или нет), которые вы будете вызывать внутри системы на основе вашей логики, чтобы определить, какой менеджер следует использовать.

Я видел в комментарии, что вы имели в виду "модуль". Кэширование - это вопрос инфраструктуры, поэтому я настоятельно рекомендую вам перенести это решение на уровень приложений. Вы можете пометить кеш как локальный, а другие как кластерный. Но вам, вероятно, нужно иметь какую-то номенклатуру для названия, чтобы было легче. Не выбирайте менеджер кеша на уровне модуля.

этот пост иллюстрирует это другими примерами.

Ответ 2

Как объяснил @Stephane Nicoll, у вас есть несколько вариантов. Я постараюсь дать некоторую информацию о кастомах CacheResolver. CacheResolver имеет один метод:

Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context);

который предоставляет контекст кешируемому классу операций, методу, аргументам и т.д.

В своей основной форме:

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());
    }
}

Здесь я использую один CacheManager для краткости. Но вы можете привязать разные CacheManager к CacheResolver и сделать более детальный выбор: если имя класса - X, тогда используйте GuavaCacheManager, в противном случае используйте EhCacheCacheManager.

После этого шага вы должны зарегистрировать CacheResolver, (снова вы можете связать больше CacheManagers здесь):

@Configuration
@EnableCaching
public class CacheConfiguration extends CachingConfigurerSupport {

    @Bean
    @Override
    public CacheManager cacheManager() {
        // Desired CacheManager
    }

    @Bean
    @Override
    public CacheResolver cacheResolver() {
        return new CustomCacheResolver(cacheManager());
    }
}

И в качестве последнего шага вы должны указать CustomCacheResolver в одной из аннотаций @Cacheable, @CachePut, @CacheConfig и т.д.

@Cacheable(cacheResolver="cacheResolver")

Вы можете посмотреть здесь примеры кода.