【问题标题】:Spring Memcached annotations not CachingSpring Memcached 注解不缓存
【发布时间】:2015-08-19 06:18:36
【问题描述】:

我正在尝试让 Memcache 在 Spring 中工作。

我已经使用 Docker 和 Kitematic 设置了本地 Memcached 服务器:

我可以使用 telnet 访问 Memcached 服务器:telnet 192.168.99.100 32780,然后运行 ​​statsstats 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");

getDateTime2getDateTime3 中放置运行时异常后,确定没有调用拦截器。

知道@Cachable@ReadThroughSingleCache 没有发挥拦截魔法的原因是什么吗?

根据 Matjaž Pečan 的回复更新:

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/>

    ...

【问题讨论】:

    标签: java spring caching memcached simple-spring-memcached


    【解决方案1】:

    SSM 3.6.0有错误,请降级到3.5.0解决问题或尝试添加

    depends-on="cacheBase"
    

    到 defaultCache bean 定义。

    更新 1

    自调用不起作用。如果调用是通过 this 对象进行的,则不会拦截调用并且不会缓存结果。确保 bean 中定义的方法是从另一个 Spring bean 调用的。

    更新 2

    对于 SSM 方法必须注释如下:

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

    由于某些原因,仍然没有触发拦截器。

    【讨论】:

    • 添加 depends-on="cacheBase" 至少可以使手动缓存工作,所以朝着正确的方向迈出了一步,谢谢!注释由于某种原因不起作用。
    • 如何调用 getDateTime?确保通过使用另一个 bean 而不是同一个 bean 所以不像 this.getDateTime(..) 因为自我调用不会被 Spring 拦截。
    • 我已将 getDateTime 移到它自己的类中,请参阅 Update2。手动缓存工作完美,注释不做任何缓存。
    • 不知道是否调用了拦截器,请在getDataTime1和getDataTime2中添加: throw new RuntimeException() and past stacktraces
    • PingEndpoint 和 CacheClass 之间应该有 Spring 和 SSM 拦截器类。
    【解决方案2】:

    Spring 代理机制因使用的实现而异。

    默认是 AspectJ,它需要接口(按接口代理),然后这些接口将由包裹在 bean 周围的实际代理实现。由于您的 bean 只是一个类并且没有接口,因此它没有被 AspectJ 代理。

    有两种可能的解决方案:

    • 为 CacheClass 实现一个接口并使用该接口连接到其他 bean
    • 使用 CGLib 代理(您需要添加对 CGLib 的运行时依赖项)并在您的 aspectj-proxy 元素中添加 proxy-target-class:

      &lt;aop:aspectj-autoproxy proxy-target-class="true"/&gt;

    【讨论】:

    • 我已经用你的建议更新了我的问题,注释没有做任何缓存。
    • 您在 XML 中哪里定义了“testCache”缓存?我找不到它了。您是否在实际文件中定义了它?我看到你定义了一个“defaultCache”。
    • 应该testCachedefaultCache 吗?已经改了,但没什么区别。
    猜你喜欢
    • 1970-01-01
    • 2017-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-23
    • 1970-01-01
    • 2021-08-22
    相关资源
    最近更新 更多