Spring Cache с Couchbase с использованием LoadTimeWeaving - странно не работает

Я добавляю Spring Cache в существующий весенний проект, используя аннотации. Я использую Couchbase в качестве провайдера кеша. Я хочу использовать переплетение времени загрузки с использованием AspectJ, чтобы разрешить кеширование вызовов частных методов и вызовов методов класса case.

Уже три дня я застрял над этой проблемой, и я прочитал десятки статей, документации и примеров, но эта штука просто не работает.

Это то, что я сделал -

@Configuration
@EnableSpringConfigured
@EnableAspectJAutoProxy
@EnableLoadTimeWeaving(aspectjWeaving = EnableLoadTimeWeaving.AspectJWeaving.ENABLED)
@EnableTransactionManagement
@EnableRetry
@PropertySource(
        value = {"classpath:application.properties", "classpath:${spring.profiles.active}.properties"},
        ignoreResourceNotFound = true)
public class BeanConfig implements LoadTimeWeavingConfigurer {

    ... various beans here ...

    @Override
    public LoadTimeWeaver getLoadTimeWeaver() {
        return new TomcatLoadTimeWeaver();// because I'm using Tomcat 7
    }

    @Bean
    public InstrumentationLoadTimeWeaver loadTimeWeaver()  throws Throwable {
        return new InstrumentationLoadTimeWeaver();
    }
}

@Configuration
@EnableSpringConfigured
@EnableCaching(mode = AdviceMode.ASPECTJ)
@ComponentScan(basePackages = "com.foo.bar.dao.cache.couchbase")
public class CacheConfigurer extends CachingConfigurerSupport {
    @Bean
    @Override
    public CacheManager cacheManager() {
        ... cachemanager configuration here ...
    }
}

Затем у меня есть @Chacheable в методе DAO в классе, а не в интерфейсе.

Наконец, в $CATALINA_HOME/conf/context.xml моего Tomcat 7 у меня есть -

<Context>
    <Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"/>    
</Context>

Я добавил следующие зависимости в pom.xml (это проект maven) -

  • кушетка-пружина-кэш
  • весенние аспекты
  • аспектжвивер
  • аспект
  • пружинный инструмент
  • весна-инструмент-кот

Если я не использую кэширование LTW, оно отлично работает для вызовов методов, поступающих через интерфейсы (как и должно быть). Но после того, как я включаю LTW-кэширование, оно вообще не работает - ни кеширования ни для вызова метода, ни ошибок.

Кто-нибудь пробовал использовать LTW для кеша Spring с кушеткой? Что я здесь упускаю или делаю неправильно?

Я использую Spring 4.3.5.Release.

Обновить –

Вот мой минимальный код, воспроизводящий ситуацию - https://github.com/harshilsharma63/spring-boilerplate-with-cache


person Harshil Sharma    schedule 29.12.2016    source источник
comment
на самом деле ничего общего с диванной базой, провайдер не имеет значения. Вы должны иметь возможность воспроизвести это в хранилище памяти. Нет ничего явно плохого, что бросается мне в глаза. Кстати, вы можете использовать @Cacheable при реализации без LTW, только не приватные методы.   -  person Stephane Nicoll    schedule 29.12.2016
comment
Разве вы не можете использовать -javaagent:/path/to/aspectjweaver.jar в качестве аргумента JVM вместо необходимой магии загрузчика классов, если вы этого не сделаете?   -  person Nándor Előd Fekete    schedule 29.12.2016
comment
Или, что еще лучше, используйте переплетение во время компиляции. Поскольку вы уже полагаетесь на AspectJ для управления транзакциями, что не является дополнительной функцией вашего приложения, вы можете упростить свое приложение, перенеся часть плетения из времени выполнения вашего приложения в свою сборку.   -  person Nándor Előd Fekete    schedule 29.12.2016
comment
@StephaneNicoll Я попробую использовать другого поставщика кеша, просто чтобы проверить.   -  person Harshil Sharma    schedule 30.12.2016
comment
@NándorElődFekete Я уже пытался указать собственный загрузчик классов в tomcat context.xml, как указано в вопросе. Плетение времени компиляции - возможное решение для запуска вещей. Я буду изучать его.   -  person Harshil Sharma    schedule 30.12.2016
comment
Вам не нужна магия загрузчика классов, если вы используете java-агент для переплетения во время загрузки или вы используете переплетение во время компиляции. Включить агент LTW так же просто, как указать аргумент командной строки для запуска вашей JVM. Во всех случаях плетение во время компиляции лучше, за исключением, может быть, случая, когда вы хотите плести динамически загружаемый код, который недоступен во время компиляции (например, плагины).   -  person Nándor Előd Fekete    schedule 30.12.2016
comment
@StephaneNicoll Я загрузил минимальный код, который воспроизводит эту проблему. Как вы думаете, вы можете взглянуть на это?   -  person Harshil Sharma    schedule 02.01.2017


Ответы (1)


Забудьте о переплетении времени загрузки на основе загрузчика классов, особенно с Tomcat ‹ 8.0. У вас будет много проблем, связанных с порядком загрузки классов: некоторые классы будут загружены до того, как Spring установит свой загрузчик классов, и вы столкнетесь с трудными для отладки проблемами, некоторые из ваших классов не будут сплетены и т. д. Вместо этого используйте агент Java.

Вот как исправить вашу конфигурацию с помощью Tomcat 7, переключившись на переплетение на основе агента Java:

  1. Удалите @EnableLoadTimeWeaving аннотации.
  2. Удалите <Loader loaderClass... из context.xml.
  3. Добавьте -javaagent:/path/to/aspectjweaver.jar к параметрам запуска JVM.

Если вы хотите перейти на Tomcat 8, выполните следующие действия:

  1. Вынесем @EnableLoadTimeWeaving(aspectjWeaving=ENABLED) в отдельный класс конфигурации, назовем его WeavingConfig.
  2. Измените свой класс WebInitializer так, чтобы для getRootConfigClasses() вы возвращали только WeavingConfig.class.
  3. Переместите другие необходимые классы конфигурации в getServletConfigClasses().
  4. Удалите ненужные конфигурации, такие как <Loader loaderClass..., из context.xml, @EnableAspectJAutoProxy.
  5. Выгода.

Конечно, лучше всего было бы просто использовать переплетение времени компиляции.

person Nándor Előd Fekete    schedule 03.01.2017
comment
лучше всего было бы просто использовать переплетение времени компиляции. - какая-то конкретная причина, по которой плетение во время компиляции по-прежнему будет лучшим? - person Harshil Sharma; 04.01.2017
comment
Кроме того, есть идеи, почему документация Spring сильно отличается от того, что вы предложили (что действительно сработало)? - person Harshil Sharma; 04.01.2017
comment
С переплетением во время компиляции вы переносите снижение производительности за счет переплетения со времени загрузки на время сборки, поэтому время запуска будет быстрее. Вам не нужно изменять свойства среды выполнения целевой системы, например добавлять агент Java или изменять поведение загрузчика классов. Это также безопаснее, потому что, если по какой-то причине LTW не работает, вы обнаружите это — совершенно очевидно — только во время выполнения, в то время как это не проблема, если вы включите плетение в свою сборку. В целом, это более безопасная и стабильная альтернатива LTW. - person Nándor Előd Fekete; 04.01.2017
comment
Что касается того, почему документация Spring не говорит о проблемах с загрузкой классов, я не хочу строить догадки. Но я также считаю это упущением, потому что вижу повторяющиеся вопросы на SO относительно @EnableLoadTimeWeaving. - person Nándor Előd Fekete; 04.01.2017