Как реализовать CacheLoader, чтобы читался ключ @Cacheable

При попытке реализовать собственный загрузчик кеша с помощью встроенного обновления. Этот загруженный кеш использует 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

Я получаю сообщение об ошибке при попытке добавить свой собственный ключ:

@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)

Как я могу добавить ключ «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;

}

Я получаю ту же ошибку.

Весь код и конфигурация:

весна-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>

мой-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;
    }

}

person blue-sky    schedule 18.11.2014    source источник


Ответы (1)


Прежде всего, вам нужно взглянуть на документацию по Spring Cache и, в частности, этого раздела. Ваше использование аннотации недопустимо, поэтому вы видите исключение из Spring.

Во-вторых, вам нужно действительно реализовать CacheLoader. Это класс, который преобразует ключ в пару ключ-значение, обращаясь к вашей базе данных, веб-сервису, ко всему, что может запросить систему записи, чтобы получить данные на основе этого ключа. Это чисто специфическое приложение и зависит от вашего варианта использования.

В-третьих, вам нужно лучше посмотреть, какие свойства вы указываете в XML-файле Ehcache, потому что наличие myKey там не имеет особого смысла.

И есть некоторые другие проблемы, которые нужно исправить, но понимание первых двух из вышеперечисленных имеет решающее значение.

person Louis Jacomet    schedule 19.11.2014
comment
Не могли бы вы предоставить пример рабочего кода для реализации CacheLoader? Я в той же лодке, и я изо всех сил пытаюсь заставить это работать. Метод, аннотированный @cacheable, похоже, не вызывается по истечении timeToRefreshSeconds. Спасибо! - person Jason King; 06.12.2016
comment
Пожалуйста, откройте для этого отдельный вопрос, пометив его Ehcache, я обязательно доберусь до него в какой-то момент. - person Louis Jacomet; 06.12.2016