Подтвердить что ты не робот

Spring cache @Cacheable метод игнорируется при вызове из одного класса

Я пытаюсь вызвать метод @Cacheable из одного класса:

@Cacheable(value = "defaultCache", key = "#id")
public Person findPerson(int id) {
   return getSession().getPerson(id);
} 

public List<Person> findPersons(int[] ids) {
   List<Person> list = new ArrayList<Person>();
   for (int id : ids) {
      list.add(findPerson(id));
   }
   return list;
}

и надеемся, что результаты из findPersons также кэшируются, но аннотация @Cacheable игнорируется, а метод findPerson выполняется каждый раз.

Я делаю что-то неправильно здесь, или это предназначено?

4b9b3361

Ответ 1

Это связано с тем, как создаются прокси-серверы для обработки кэширования, связанные с транзакциями функции в Spring. Это очень хорошая ссылка на то, как Spring обрабатывает его - Транзакции, кеширование и АОП: понимание использования прокси в Spring

Короче говоря, самозапуск обходит динамический прокси-сервер, и любая перекрестная проблема, такая как кеширование, транзакция и т.д., которая является частью динамической логики прокси, также обойдена.

Исправление заключается в использовании времени компиляции AspectJ или времени загрузки.

Ответ 2

Вот что я делаю для небольших проектов с ограниченным использованием вызовов методов внутри одного класса. Внутрикодовая документация настоятельно рекомендуется, так как это может показаться неудачным для коллег. Но его легко проверить, просто, быстро достичь и избавит меня от полномасштабного инструментария AspectJ. Однако для более интенсивного использования я бы посоветовал решение AspectJ.

@Service
@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
class PersonDao {

    private final PersonDao _personDao;

    @Autowired
    public PersonDao(PersonDao personDao) {
        _personDao = personDao;
    }

    @Cacheable(value = "defaultCache", key = "#id")
    public Person findPerson(int id) {
        return getSession().getPerson(id);
    }

    public List<Person> findPersons(int[] ids) {
        List<Person> list = new ArrayList<Person>();
        for (int id : ids) {
            list.add(_personDao.findPerson(id));
        }
        return list;
    }
}

Ответ 3

Для тех, кто использует плагин Grails Spring Cache, обходной путь описан в документации. У меня была эта проблема в приложении grails, но, к сожалению, принятый ответ кажется непригодным для Grails. Решение является уродливым, IMHO, но оно работает.

Пример кода демонстрирует это хорошо:

class ExampleService {
    def grailsApplication

    def nonCachedMethod() {
        grailsApplication.mainContext.exampleService.cachedMethod()
    }

    @Cacheable('cachedMethodCache')
    def cachedMethod() {
        // do some expensive stuff
    }
}

Просто замените exampleService.cachedMethod() своим собственным сервисом и методом.

Ответ 4

Внутренняя конфигурация кэша может использоваться для "проксификации" вызовов метода, см. пример в этом ответе: stackoverflow.com/a/48168762/907576

Ответ 5

Можете ли вы помочь мне определить Java-бин PersonDAO в конфигурации Java?