java - 如何实现CacheLoader以便读取@Cacheable key

标签 java spring caching ehcache spring-cache

尝试使用内联刷新来实现我自己的缓存加载器。此缓存加载使用 RefreshAheadCacheFactory

如描述

http://terracotta.org/documentation/4.1/bigmemorymax/api/refresh-ahead#scheduled-refresh-ahead

&

http://www.ehcache.org/generated/2.9.0/html/ehc-all/#page/Ehcache_Documentation_Set%2Fco-dec_creating_a_decorator_2.html

我在尝试添加自己的 key 时收到错误:

@Cacheable(key="myKey" , value = "myCache")

错误是:

org.springframework.expression.spel.SpelEvaluationException: EL1008E:(pos 0): Field or property 'myKey' cannot be found on object of type 'org.springframework.cache.interceptor.CacheExpressionRootObject'
    at org.springframework.expression.spel.ast.PropertyOrFieldReference.readProperty(PropertyOrFieldReference.java:208)
    at org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:72)
    at org.springframework.expression.spel.ast.SpelNodeImpl.getValue(SpelNodeImpl.java:93)
    at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:88)
    at org.springframework.cache.interceptor.ExpressionEvaluator.key(ExpressionEvaluator.java:80)
    at org.springframework.cache.interceptor.CacheAspectSupport$CacheOperationContext.generateKey(CacheAspectSupport.java:464)
    at org.springframework.cache.interceptor.CacheAspectSupport.inspectCacheables(CacheAspectSupport.java:291)
    at org.springframework.cache.interceptor.CacheAspectSupport.execute(CacheAspectSupport.java:198)
    at org.springframework.cache.interceptor.CacheInterceptor.invoke(CacheInterceptor.java:66)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:622)
    at ehcache.MyCache$$EnhancerByCGLIB$$4aeb3b9c.tester(<generated>)
    at ehcache.TestEhcache.testCache(TestEhcache.java:21)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:47)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

如何将 key “myKey”添加到缓存中?

我认为我错误地设置了自定义缓存加载器。 loadAll方法应该如何实现。这是我的实现:

public Map loadAll(Collection keys, Object argument) {
    // TODO Auto-generated method stub

    return new HashMap<String , String>();
}

这个 HashMap 应该包含键“myKey”吗?

当我自定义此方法时:

public Map loadAll(Collection keys, Object argument) {
// TODO Auto-generated method stub
 Map map = new HashMap<String , String>();
 map.put("myKey", "test");

return map;

}

我收到同样的错误。

所有代码和配置:

spring-ehcache.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:util="http://www.springframework.org/schema/util"
    xmlns:cache="http://www.springframework.org/schema/cache"
     xmlns:p="http://www.springframework.org/schema/p"
     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
     http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd
     http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
    <cache:annotation-driven />
    <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager"
        p:cache-manager-ref="ehcache" />
    <bean id="ehcache"
        class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"
        p:config-location="my-ehcache.xml" />

    <bean id="myCache" class="ehcache.MyCache"></bean>
</beans>

my-ehcache.xml:

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">
    <defaultCache eternal="true" maxElementsInMemory="100"
        overflowToDisk="false" />
    <cache name="myCache" maxElementsInMemory="10" eternal="true"
        overflowToDisk="false">

  <cacheLoaderFactory class="MyCacheLoaderFactory" properties="myKey" 
    />

        <cacheDecoratorFactory 
            class="net.sf.ehcache.constructs.refreshahead.RefreshAheadCacheFactory"
            properties="timeToRefreshSeconds=10,
      batchSize=5,
      numberOfThreads=4,
      maximumBacklogItems=5,
      evictOnLoadMiss=true" />

    </cache>
</ehcache>
<小时/>
package ehcache;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring-ehcache.xml")
public class TestEhcache {

    @Test
    public void testCache(){

        while(true){


            long t1 = System.currentTimeMillis();

            System.out.println(myCache.tester());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            long t2 = System.currentTimeMillis();

            System.out.println("Exc time : "+(t2-t1));
        }
    }


    @Autowired
    private MyCache myCache;

}



package ehcache;

import org.springframework.cache.annotation.Cacheable;

public class MyCache {

    @Cacheable(key="myKey" , value = "myCache")
    public String tester() {

        System.out.println("in cache");
        ExpensiveOperation expensiveOperation = new ExpensiveOperation();
        String ret = expensiveOperation.doThis();

        return ret;
    }

}

package ehcache;

public class ExpensiveOperation {

    public String doThis() {

        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        return "test";
    }

}

import java.util.Properties;
import net.sf.ehcache.Ehcache;
import net.sf.ehcache.loader.CacheLoader;

public class MyCacheLoaderFactory extends
        net.sf.ehcache.loader.CacheLoaderFactory {

        @Override
        public CacheLoader createCacheLoader(Ehcache cache, Properties properties) {

            return new MyCacheLoader();

        }

    }

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import net.sf.ehcache.CacheException;
import net.sf.ehcache.Ehcache;
import net.sf.ehcache.Status;
import net.sf.ehcache.loader.CacheLoader;


public class MyCacheLoader implements CacheLoader {

    public Object load(Object key) throws CacheException {
        // TODO Auto-generated method stub
        return load(key, null);
    }

    public Map loadAll(Collection keys) {
        // TODO Auto-generated method stub

        System.out.println("in loadall");

        return loadAll(keys , null);
    }

    public Object load(Object key, Object argument) {

        System.out.println("in load");
        // TODO Auto-generated method stub
        return "my object";
    }

    public Map loadAll(Collection keys, Object argument) {
        // TODO Auto-generated method stub
         Map map = new HashMap<String , String>();
         map.put("myKey", "test");

        return map;
    }

    public String getName() {
        // TODO Auto-generated method stub
        return null;
    }

    public CacheLoader clone(Ehcache cache) throws CloneNotSupportedException {
        // TODO Auto-generated method stub
        return null;
    }

    public void init() {
        // TODO Auto-generated method stub

    }

    public void dispose() throws CacheException {
        // TODO Auto-generated method stub

    }

    public Status getStatus() {
        // TODO Auto-generated method stub
        return null;
    }

}

最佳答案

首先,您需要查看 Spring Cache 文档,特别是 this section 。您对注释的使用无效,这就是您看到 Spring 异常的原因。

其次,您需要真正实现CacheLoader。该类将通过访问数据库、Web 服务以及任何可以查询记录系统以根据该键获取数据的方式将键转换为键值对。这纯粹是特定于应用程序的,取决于您的用例。

第三,您需要更好地了解您在 Ehcache XML 中指定的属性,因为其中包含 myKey 没有什么意义。

还有一些其他问题需要解决,但理解上面的前两个问题至关重要。

关于java - 如何实现CacheLoader以便读取@Cacheable key,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26993833/

相关文章:

java - 从 Spring Boot 应用程序连接到 Oracle 数据库时如何修复 "Driver does not support get/set network timeout for connections"?

objective-c - iOS UIImageView 流畅的图像呈现

java - 如何在没有冗余计算的情况下过滤和映射 Java 8 流中的值?

java - 需要 Apache commons-lang3 作为使用 Tycho 构建的 Eclipse 插件的依赖项

java - 使用 Spring 的通知机制

c# - 缓存对象集合的最佳方法。一起还是作为单独的元素?

caching - 如何使 favicon.ico 小且可缓存?

java - 创建一个包含隐藏二进制数据的 wav 并读取它(Java)

java - 我可以使用 MySQL Connector/J 执行以分号分隔的多个查询吗?

java - 从 Tapestry 组件监听 spring 事件