Как заметил Эндрюс С., в автоконфигурации это звучит как столкновение кэшей. В javadoc
@EnableCaching
есть некоторые полезные замечания о том, как выбран cacheManager
иВ частности, идея о том, как действовать.В этом случае вы должны установить CachingConfigurer
для выбора вашего кэша - возможно, вы можете просто расширить CachingConfigurerSupport
(как в примере ниже) и все готово.
Бин типаCacheManager
должен быть зарегистрирован, так как нет разумного значения по умолчанию, которое фреймворк может использовать в качестве соглашения.А в то время как элемент <cache:annotation-driven>
предполагает bean-компонент с именем cacheManager, @EnableCaching
ищет bean-компонент типа cache.Поэтому наименование метода компонента управления кешем не имеет значения.
Для тех, кто хочет установить более прямую связь между @EnableCaching
и точным компонентом управления кешем, который будет использоваться, интерфейс обратного вызова CachingConfigurer
можетбыть реализованным.Обратите внимание на @Override
-аннотированные методы ниже:
@Configuration
@EnableCaching
public class AppConfig extends CachingConfigurerSupport {
@Bean
public MyService myService() {
// configure and return a class having @Cacheable methods
return new MyService();
}
@Bean
@Override
public CacheManager cacheManager() {
// configure and return an implementation of Spring's CacheManager SPI
SimpleCacheManager cacheManager = new SimpleCacheManager();
cacheManager.setCaches(Arrays.asList(new ConcurrentMapCache("default")));
return cacheManager;
}
@Bean
@Override
public KeyGenerator keyGenerator() {
// configure and return an implementation of Spring's KeyGenerator SPI
return new MyKeyGenerator();
}
}
Этот подход может быть желательным просто потому, что он более явный, или он может быть необходим для того, чтобы различать два CacheManager
бобы присутствуют в том же контейнере.
Обратите внимание также на метод keyGenerator
в приведенном выше примере.Это позволяет настроить стратегию генерации ключа кэша для KeyGenerator
SPI Spring.Обычно @EnableCaching
настраивает Spring 10 * для этой цели, но при реализации CachingConfigurer
генератор ключей должен быть предоставлен явно.Возврат null
или new SimpleKeyGenerator()
из этого метода, если настройка не требуется.
CachingConfigurer
предлагает дополнительные параметры настройки: рекомендуется расширить с CachingConfigurerSupport
, что обеспечивает реализацию по умолчанию для всех методов, которые могутбыть полезным, если вам не нужно все настраиватьСм. CachingConfigurer
Javadoc для получения более подробной информации.
Вы также можете найти эту ветку полезной: Как иметь конфигурацию с несколькими кэш-менеджерами в весеннем кеше java
Редактировать:
Так что, к счастью, у меня есть проект, использующий кэширование, и я написал этот небольшой кусочек:
@Bean
@Override
public CacheResolver cacheResolver() {
return new SimpleCacheResolver(cacheManager()) {
@Override
protected Collection<String> getCacheNames(CacheOperationInvocationContext<?> context) {
Collection<String> toReturn = super.getCacheNames(context);
toReturn.forEach(System.out::println);
return toReturn;
}
@Override
public Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context) {
System.out.println(Arrays.toString(context.getArgs()));
System.out.println(context.getClass());
System.out.println(context.getMethod());
System.out.println(context.getOperation());
return super.resolveCaches(context);
}
};
}
Помимо того, что мои установленные имена кэша всплывают, я отмечаюконтекст выводит:
[]
класс org.springframework.cache.interceptor.CacheAspectSupport $ CacheOperationContext public abstract ... Transferobjects.CacheContainer ... service.LookupService.getCacheSelections ()
Builder [public ... Transferobjects.CacheContainer ... dao.LookupFacade.getCacheSelections ()] caches = [cacheselections] |ключ = '' |keyGenerator = '' |cacheManager = '' |cacheResolver = '' |условие = '' |разве что = '' |sync = 'true'
Вывод context.getClass()
представляет интерес, учитывая ваш вопрос об аспектах.Тем не менее, у меня есть очень похожий аспект ведения журнала / синхронизации в моем собственном коде, который не вызывает путаницы в остальной части кэширования.Попробуйте мой распознаватель и посмотрите, поучителен ли вывод о том, какие вызовы выполняются для кода кэша.
Edit # 2:
Кажется, проблема TLDR в том, что мы ожидаем @Cacheable
работать в местах, где это невозможно - в основном из-за того, что фреймворк еще не полностью себя зарекомендовал.Вы используете InitializingBean
, и я попытался заменить эту функциональность на @PostConstruct
, который не работает.
Кэш Spring с использованием @Cacheable во время @PostConstruct не работает
Iполучил ваш код GitHubСначала я столкнулся с проблемой блокирования, о которой вы сообщали в другом потоке, но, чтобы преследовать одну вещь за раз, я просто закомментировал этот код блокировки и вызвал service.cachedMethod()
напрямую.
Я запустил ваш файл jar с помощью --trace и заметил, что cacheManager был отсканирован и создан, но изначально он не был очевиден для меня, когда он вызывался.Так что, ничего страшного, у меня только что был метод bean RuntimeException
.После этого я заметил, что обе ваши строки NOT CACHED
печатаются до этого вызова - еще один намек на то, что все настроено не так, как ожидалось.
Наконец, я добавил System.out.println(service.toString());
в методе вашего контроллера afterPropertiesSet () и увидел com.company.client.api.domain.CachedServiceImpl@2bbfb8b
- ваш объект, а не объект с прокси.Таким образом, нет кэширования.
Итак, в общем, вам нужно переделать, как вы пытаетесь включить эту функцию.