Spring Memcached аннотации не кэшируются

Я пытаюсь заставить Memcache работать весной.

Я установил локальный сервер Memcached, используя Docker и Kitematic:

введите описание изображения здесь

Я могу получить доступ к серверу Memcached, используя telnet: telnet 192.168.99.100 32780 а потом беги stats или же stats items (который только распечатывает END если кеш пуст);

мой pom.xml:

    <dependency>
        <groupId>com.google.code.simple-spring-memcached</groupId>
        <artifactId>simple-spring-memcached</artifactId>
        <version>3.6.0</version>
    </dependency>
    <dependency>
        <groupId>com.google.code.simple-spring-memcached</groupId>
        <artifactId>spring-cache</artifactId>
        <version>3.6.0</version>
    </dependency>
    <dependency>
        <groupId>com.google.code.simple-spring-memcached</groupId>
        <artifactId>xmemcached-provider</artifactId>
        <version>3.6.0</version>
    </dependency>

В моем applicationContext.xml У меня есть следующее:

    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans 
    xmlns="http://www.springframework.org/schema/beans" 
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:rabbit="http://www.springframework.org/schema/rabbit"
    xmlns:task="http://www.springframework.org/schema/task"  
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd         
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
        http://www.springframework.org/schema/rabbit http://www.springframework.org/schema/rabbit/spring-rabbit.xsd
        http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.2.xsd">

    <context:property-placeholder location="classpath*:META-INF/spring/*.properties"/>
    ...
    <import resource="cacheContext.xml" />
    ...

В cacheContext.xml мой конфиг выглядит следующим образом:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:cache="http://www.springframework.org/schema/cache"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-3.2.xsd">

    <aop:aspectj-autoproxy/>
    <cache:annotation-driven/>

    <context:component-scan base-package="com.google.code.ssm"/>
    <context:component-scan base-package="com.mycee.application"/>

    <bean id="cacheBase" class="com.google.code.ssm.aop.CacheBase"/>

    <bean id="readThroughSingleCache" class="com.google.code.ssm.aop.ReadThroughSingleCacheAdvice">
        <property name="cacheBase" ref="cacheBase"/>
    </bean>
    <bean id="readThroughMultiCache" class="com.google.code.ssm.aop.ReadThroughMultiCacheAdvice">
        <property name="cacheBase" ref="cacheBase"/>
    </bean>
    <bean id="readThroughAssignCache" class="com.google.code.ssm.aop.ReadThroughAssignCacheAdvice">
        <property name="cacheBase" ref="cacheBase"/>
    </bean>
    <bean id="updateSingleCache" class="com.google.code.ssm.aop.UpdateSingleCacheAdvice">
        <property name="cacheBase" ref="cacheBase"/>
    </bean>
    <bean id="updateMultiCache" class="com.google.code.ssm.aop.UpdateMultiCacheAdvice">
        <property name="cacheBase" ref="cacheBase"/>
    </bean>
    <bean id="updateAssignCache" class="com.google.code.ssm.aop.UpdateAssignCacheAdvice">
        <property name="cacheBase" ref="cacheBase"/>
    </bean>
    <bean id="invalidateSingleCache" class="com.google.code.ssm.aop.InvalidateSingleCacheAdvice">
        <property name="cacheBase" ref="cacheBase"/>
    </bean>
    <bean id="invalidateMultiCache" class="com.google.code.ssm.aop.InvalidateMultiCacheAdvice">
        <property name="cacheBase" ref="cacheBase"/>
    </bean>
    <bean id="invalidateAssignCache" class="com.google.code.ssm.aop.InvalidateAssignCacheAdvice">
        <property name="cacheBase" ref="cacheBase"/>
    </bean>

    <bean id="incrementCounterInCache" class="com.google.code.ssm.aop.counter.IncrementCounterInCacheAdvice">
        <property name="cacheBase" ref="cacheBase"/>
    </bean>
    <bean id="decrementCounterInCache" class="com.google.code.ssm.aop.counter.DecrementCounterInCacheAdvice">
        <property name="cacheBase" ref="cacheBase"/>
    </bean>
    <bean id="readCounterFromCache" class="com.google.code.ssm.aop.counter.ReadCounterFromCacheAdvice">
        <property name="cacheBase" ref="cacheBase"/>
    </bean>
    <bean id="updateCounterInCache" class="com.google.code.ssm.aop.counter.UpdateCounterInCacheAdvice">
        <property name="cacheBase" ref="cacheBase"/>
    </bean>

    <bean name="cacheManager" class="com.google.code.ssm.spring.SSMCacheManager">
        <property name="caches">
            <set>
                <bean class="com.google.code.ssm.spring.SSMCache">
                    <constructor-arg name="cache" index="0" ref="defaultCache"/>
                    <constructor-arg name="expiration" index="1" value="300"/>
                    <constructor-arg name="allowClear" index="2" value="false"/>
                </bean>
            </set>
        </property>
    </bean>

    <bean name="defaultCache" class="com.google.code.ssm.CacheFactory" depends-on="cacheBase">
        <property name="cacheName" value="defaultCache"/>
        <property name="cacheClientFactory">
            <bean class="com.google.code.ssm.providers.xmemcached.MemcacheClientFactoryImpl"/>
        </property>
        <property name="addressProvider">
            <bean class="com.google.code.ssm.config.DefaultAddressProvider">
                <property name="address" value="localhost:11211"/>
            </bean>
        </property>
        <property name="configuration">
            <bean class="com.google.code.ssm.providers.CacheConfiguration">
                <property name="consistentHashing" value="true"/>
            </bean>
        </property>
    </bean>


</beans>

Я создал три разных метода, каждый из которых использует разные механизмы кэширования:

@Component("cacheEndpoint")
public class CacheClass {

    @Autowired
    SSMCacheManager cache;

    public String getDateTime1(String anything) {

        SSMCache c = cache.getCache("defaultCache");

        String s = c.get(anything, String.class);
        if (s != null) {
            return s;
        }

        Date d = new Date();
        String response = d.toString() + " - " + d.getTime();
        c.put(anything, response);

        return response;

    }

    @Cacheable("defaultCache")
    public String getDateTime2(String anything) {
        Date d = new Date();
        String response = d.toString() + " - " + d.getTime();
        return response;
    }

    @ReadThroughSingleCache(namespace = "defaultCache", expiration = 15000)
    public String getDateTime3(String anything) {
        Date d = new Date();
        String response = d.toString() + " - " + d.getTime();
        return response;
    }


}

Для доступа к нему я делаю:

@Autowired
CacheClass c;

...

// caches perfectly
c.getDateTime1("test");

// doesn't do any caching
c.getDateTime2("test");

// doesn't do any caching
c.getDateTime3("test");

После размещения исключений во время выполнения в getDateTime2 а также getDateTime3Было установлено, что перехватчики не вызываются.

Любая идея, что может быть причиной @Cachable а также @ReadThroughSingleCache не делает их перехват магии?

Обновление на основе ответа Матяжа Печана:

Интерфейс CacheClass:

public interface CacheClass {

    public String getDateTime1(String anything);

    public String getDateTime2(String anything);

    public String getDateTime3(String anything);

}

Реализация CacheClass:

@Component("cacheEndpoint")
public class CacheClassImpl implements CacheClass {

    @Autowired
    SSMCacheManager cache;

    public String getDateTime1(String anything) {

        SSMCache c = cache.getCache("defaultCache");

        String s = c.get(anything, String.class);
        if (s != null) {
            return s;
        }

        Date d = new Date();
        String response = d.toString() + " - " + d.getTime();
        c.put(anything, response);

        return response;

    }

    @Cacheable("defaultCache")
    public String getDateTime2(String anything) {

        Date d = new Date();
        String response = d.toString() + " - " + d.getTime();
        return response;

    }

    @ReadThroughSingleCache(namespace = "defaultCache", expiration = 15000)
    public String getDateTime3(String anything) {

        Date d = new Date();
        String response = d.toString() + " - " + d.getTime();
        return response;

    }


}

Конечная точка SOAP, где я тестирую кеш:

@Endpoint
public class PingEndpoint {

    @Autowired
    CacheClass c;

    @ResponsePayload
    @PayloadRoot(localPart = "PingRequest", namespace = "http://www.mycee.com/Application")
    public PingResponse doPing(@RequestPayload PingRequest request) {

        // caches perfectly
        System.out.println(c.getDateTime1("test"));

        // doesn't do any caching
        System.out.println(c.getDateTime2("test"));

        // doesn't do any caching
        System.out.println(c.getDateTime3("test"));

    }
}

cacheContext.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:cache="http://www.springframework.org/schema/cache"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
           http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-3.2.xsd">

    <aop:aspectj-autoproxy proxy-target-class="true"/>
    <cache:annotation-driven/>

    ...

2 ответа

Решение

В SSM 3.6.0 произошла ошибка, пожалуйста, вернитесь к версии 3.5.0, чтобы решить проблему, или попробуйте добавить

depends-on="cacheBase"

к определению bean-компонента defaultCache.

Обновление 1

Самостоятельные призывы не работают. Вызов не будет перехвачен, и результат не будет кэширован, если вызов выполняется через этот объект. Убедитесь, что метод, определенный в бине, вызывается из другого бина Spring.

Обновление 2

Для SSM метод должен быть аннотирован, как показано ниже:

@ReadThroughSingleCache(namespace = "defaultCache", expiration = 15000)
public String getDateTime3(@ParameterValueKeyProvider String anything) {
     ...
}

До сих пор перехватчики по некоторым причинам не срабатывают.

Механизмы проксирования пружин различаются в зависимости от используемой реализации.

По умолчанию используется AspectJ, для которого требуются интерфейсы (proxy-by-interface), и эти интерфейсы будут реализованы фактическим прокси, обернутым вокруг вашего компонента. Поскольку ваш бин является только классом и не имеет интерфейса, он не проксируется с AspectJ.

Есть два возможных решения:

  • Реализуйте интерфейс для CacheClass и используйте этот интерфейс при подключении к другим bean-компонентам
  • Используйте прокси CGLib (вам нужно будет добавить зависимость времени выполнения от CGLib) и добавить proxy-target-class в ваш элемент aspectj-proxy:

    <aop:aspectj-autoproxy proxy-target-class="true"/>

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