Абстракция кеша Spring (AdviceMode.ASPECTJ) не работает внутри репозиториев spring-data-jpa

Я использую spring-data-jpa 1.9.0.RELEASE и хочу использовать механизм пружинного кэширования внутри моих репозиториев, например

public interface LandDao extends CrudRepository<Land, Long> {

    @Cacheable("laender")
    Land findByName(String land)
}

Вот моя конфигурация кеша:

@Configuration
@EnableCaching(mode=AdviceMode.ASPECTJ)
public class EhCacheConfiguration extends CachingConfigurerSupport {
...

Обратите внимание, что я использую AdviceMode.ASPECTJ (время компиляции). К сожалению, кэширование не работает при вызове метода репо findByName. Изменение режима кэширования на AdviceMode.PROXY все работает нормально.

Чтобы гарантировать, что кэширование в принципе работает с aspectJ, я написал следующую службу:

@Service
public class LandService {

  @Autowired
  LandDao landDao;

  @Cacheable("landCache")
  public Land getLand(String bez) {
    return landDao.findByName(bez);
  }
}

В этом случае кеш работает как брелок. Поэтому я думаю, что все части моего приложения настроены правильно, и проблема заключается в сочетании режима кэширования spring-data-jpa и AspectJ. У кого-нибудь есть идея, что здесь происходит не так?

1 ответ

Хорошо, нашел ответ на мой вопрос самостоятельно. Javadoc ответственного аспекта org.springframework.cache.aspectj.AnnotationCacheAspect гласит:

При использовании этого аспекта необходимо аннотировать класс реализации (и / или методы в этом классе), а не интерфейс (если есть), который реализует этот класс. AspectJ следует правилу Java, согласно которому аннотации на интерфейсах не наследуются.

Поэтому невозможно использовать аннотацию @Cacheable внутри интерфейсов репозитория вместе с aspectj. Мое решение сейчас заключается в использовании пользовательских реализаций для репозиториев Spring Data:

Интерфейс для пользовательских функций хранилища:

public interface LandRepositoryCustom {

    Land findByNameCached(String land);
}

Реализация пользовательских функций хранилища с использованием запроса dsl:

@Repository
public class LandRepositoryImpl extends QueryDslRepositorySupport 
       implements LandRepositoryCustom {

  @Override
  @Cacheable("landCache")
  public Land findByNameCached(String land) {
    return from(QLand.land).where(QLand.land.name.eq(land)).singleResult(QLand.land);
  }
}

Обратите внимание на аннотацию @Cacheable для метода findByNameCached.

Базовый интерфейс репозитория:

public interface LandRepository extends CrudRepository<Land, Long>, LandRepositoryCustom {
}

Используя репозиторий:

public class SomeService {

  @Autowired
  LandRepository landDao;

  public void foo() {
    // Cache is working here:-)
    Land land = landDao.findByNameCached("Germany");
  }
}

Было бы полезно добавить примечание, касающееся этого ограничения, в ссылку на данные пружины.

Другие вопросы по тегам