2015-10-01 1 views
1

Я использую spring-data-jpa 1.9.0.RELEASE и хочу использовать механизм пружинного кэширования внутри моих репозиториев, например.Отвлечение кэша Spring (AdviceMode.ASPECTJ) не работает внутри хранилищ данных spring-data-jpa

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. Кто-нибудь знает, что здесь происходит?

ответ

2

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

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

Таким образом, нельзя использовать аннотацию @Cacheable внутри интерфейсов репозитория вместе с aspectj. Мое решение теперь использовать custom implementations for Spring Data repositories:

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

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"); 
    } 
} 

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

+0

К сожалению, мое решение не работает, если вы хотите выселить кеш всякий раз, когда объект сохраняется, см. Сообщение [this] (http://stackoverflow.com/a/26283080/5396465) от @ oliver-gierke. Это связано с тем, что мы не можем комментировать метод S save (S-объект) интерфейса CrudRepository с аннотацией CacheEvict. Я думаю, эта проблема не может быть решена легко ... – smitzkus

Смежные вопросы