Spring-кэшируемые аннотации не работают до завершения развертывания
У меня есть следующие классы и интерфейсы (упрощены, чтобы прояснить ситуацию).
@Serivce
class Service1 {
@Cacheable("cacheName")
public Metadata preLoadMetadata() {
// load data from database
}
}
@Service
class Service2 implements Loader {
@Autowired @Lazy
private Service1 service1;
@Overrride
public CacheWrapper getCacheWrapper() {
return new CacheWrapper(() -> service1.preLoadMetadata());
}
}
interface Loader {
CacheWrapper getCacheWrapper();
}
class CacheWrapper {
private Callable callable;
public CacheWrapper(Callable callable) {
this.callable = callable;
}
public getCallable() {
return callable;
}
}
Компонент Spring, отвечающий за загрузку кэша во время развертывания.
@Component
class LoadCache {
@Autowired
private List<Loader> allLoaders;
@PostConstruct
public void load() {
allLoaders.getCacheWrapper().getCallable().call();
}
}
preLoadMetadata()
не сохраняет данные в кеше, но выполняет. После завершения развертывания, и я вызываю тот же метод preLoadMetadata()
снова, затем он сохраняет данные в кеш.
Почему @Cacheable
не работает во время развертывания?
Если я вручную использую put
метод Cache
заполнить кеш внутри метода с пометкой @PostConstruct
Я могу сделать это успешно во время развертывания.
Я использую Tomcat в качестве сервера.
Я использую кеш Couchbase за абстракцией Spring кеша.
2 ответа
Основная причина не работает Cacheable
аннотация:afterSingletonsInstantiated()
метод устанавливает initialized
признак истины только когда BeanFactory
создал все бобы. Если initialized
флаг равен false, операции кэширования не выполняются. Здесь, внутри пост-конструкции, когда мы начинаем предварительную загрузку кэшей, очень вероятно, что LoadCache
не последний компонент, который будет создан. Следовательно, операции кэширования не выполняются (при использовании аннотаций кэширования).
Следовательно, EventListener
аннотация в ответ на ContextRefreshEvent
Лучше всего использовать в этом случае, который гарантирует, что контекст запущен, а затем происходит только загрузка кэшей.
Если вы хотите предварительно загрузить кэш, я предлагаю вам использовать ApplicationListener
который будет выполняться после запуска вашего приложения:
@Component
public class CacheInitializer implements ApplicationListener<ContextRefreshedEvent>{
@Autowired
private List<Loader> allLoaders;
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
allLoaders.getCacheWrapper().getCallable().call();
}
}