@Cacheable в Spring
@Cacheable — одна аннотация, которая превращает обычный метод в кэшируемый, без единой строчки кода вручную проверяющей кэш.
@Service
class UserService {
@Cacheable("users") // результат метода кэшируется под именем "users"
User getUser(Long id) {
return userRepository.findById(id).orElseThrow(); // выполнится только при первом вызове с этим id
}
}
Первый вызов getUser(1) реально выполняет метод и сохраняет результат в кэш. Все следующие вызовы с тем же id возвращают значение из кэша, не выполняя тело метода вообще.
Копнуть глубже
Это пример паттерна Proxy (см. тему «Структурные (Adapter, Proxy)») — Spring оборачивает бин в прокси, который перехватывает вызов метода, проверяет кэш до реального вызова, и решает: вернуть из кэша или выполнить метод по-настоящему.
@CachePut — всегда выполняет метод и обновляет кэш (в отличие от @Cacheable, который пропускает выполнение при наличии значения в кэше):
@CachePut("users")
User updateUser(User user) {
return userRepository.save(user); // выполнится всегда, кэш обновится новым значением
}
@CacheEvict — удаляет значение из кэша:
@CacheEvict("users")
void deleteUser(Long id) {
userRepository.deleteById(id);
}
Ключевая ловушка @Cacheable — оно не работает при вызове метода изнутри того же класса. Spring AOP создаёт прокси вокруг бина, и перехват срабатывает только через вызов снаружи, через сам прокси-объект — this.getUser(1) внутри того же класса обойдёт кэш стороной (та же причина, что у @Transactional — см. тему «Как работают прокси»).
• почему `@Cacheable` не работает при вызове метода изнутри того же класса (если дошёл до 2-го слоя).