Использование Spring bean-компонентов в качестве ключа с аннотацией @Cacheable

Как заставить работать следующее: - Spring bean, у которого есть метод, который должен кэшироваться с аннотацией @Cacheable - другой spring bean, который создает ключи для кэша (KeyCreatorBean).

Итак, код выглядит примерно так.

@Inject
private KeyCreatorBean keyCreatorBean;

@Cacheable(value = "cacheName", key = "{@keyCreatorBean.createKey, #p0}")
@Override
public List<Examples> getExamples(ExampleId exampleId) {
  ...

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

Caused by: org.springframework.expression.spel.SpelEvaluationException: 
    EL1057E:(pos 2): No bean resolver registered in the context to resolve access to bean 'keyCreatorBean'

person Juha Syrjälä    schedule 09.07.2012    source источник
comment
Попробуйте что-то вроде #{keyCreatorBean.method} вместо @keyCreatorBean.method. Просто случайное предположение.   -  person Ajinkya    schedule 09.07.2012
comment
Вы можете попробовать это: stackoverflow.com/a/8142249/799562 <cache:annotation-driven key-generator="myKeyGenerator"/>, но вам нужно реализовать org.springframework.cache.interceptor.KeyGenerator.   -  person micfra    schedule 10.07.2012
comment
Я написал об этой проблеме в SpringSource: jira.springsource.org/browse/SPR-9578< /а>   -  person Juha Syrjälä    schedule 10.07.2012
comment
Другой связанный вопрос: stackoverflow.com/q/5743565/1431 здесь проблема с аннотациями Spring Security, но данный обходной путь не работает в моем случае.   -  person Juha Syrjälä    schedule 10.07.2012
comment
Как записал @biju-kunjummen, преобразователь bean-компонентов не задается EvaluationContext, используемым в базовых классах. Это было бы возможно, но только путем изменения реализации org.springframework.cache.interceptor.CacheAspectSupport$CacheOperationContext, где создается EvaluationContext. Это может быть хорошей подсказкой для вашего тикета JIRA, потому что это основная причина.   -  person micfra    schedule 10.07.2012


Ответы (2)


Я проверил базовую реализацию разрешения кеша, похоже, нет простого способа внедрить BeanResolver, который требуется для разрешения bean-компонентов и оценки выражений, таких как @beanname.method.

Поэтому я бы также порекомендовал несколько хакерский способ, подобный тому, который рекомендовал @micfra.

В соответствии с тем, что он сказал, создайте KeyCreatorBean в соответствии с этими строками, но внутренне делегируйте его keycreatorBean, который вы зарегистрировали в своем приложении:

package pkg.beans;

import org.springframework.stereotype.Repository;

public class KeyCreatorBean  implements ApplicationContextAware{
    private static ApplicationContext aCtx;
    public void setApplicationContext(ApplicationContext aCtx){
        KeyCreatorBean.aCtx = aCtx;
    }


    public static Object createKey(Object target, Method method, Object... params) {
        //store the bean somewhere..showing it like this purely to demonstrate..
        return aCtx.getBean("keyCreatorBean").createKey(target, method, params);
    }

}
person Biju Kunjummen    schedule 10.07.2012

Если у вас есть статическая функция класса, она будет работать так:

@Cacheable(value = "cacheName", key = "T(pkg.beans.KeyCreatorBean).createKey(#p0)")
@Override
public List<Examples> getExamples(ExampleId exampleId) {
  ...
}

с участием

package pkg.beans;

import org.springframework.stereotype.Repository;

public class KeyCreatorBean  {

    public static Object createKey(Object o) {
        return Integer.valueOf((o != null) ? o.hashCode() : 53);
    }

}
person micfra    schedule 09.07.2012
comment
Мне нужно использовать spring bean, а не статический фабричный метод. - person Juha Syrjälä; 10.07.2012
comment
Работа с @keyCreatorBean.createKey(#p0) не удалась, как и в вашем случае. Может быть, контекст не знает об экземпляре компонента во время обработки аннотации кеша? Какой-то весенний гуру вокруг? - person micfra; 10.07.2012