gpt4 book ai didi

java - @Cacheable 通过 Spring aop - 如何生成唯一的缓存键

转载 作者:塔克拉玛干 更新时间:2023-11-02 19:25:40 28 4
gpt4 key购买 nike

我想在为 findById(Long id) 方法扩展相同的 AbstractService 的几个服务上启用缓存。

所以在我的 applicationContext 中我写道:

<!-- cache definitions -->
<cache:advice id="cacheAdvice" cache-manager="cacheManager">
<cache:caching cache="refs">
<cache:cacheable method="findById" key="#root.targetClass + #id"/>
</cache:caching>
</cache:advice>

<aop:config>
<aop:advisor advice-ref="cacheAdvice" pointcut="execution(* x.y.*.service.reference.*.*(..))"/>
</aop:config>

问题是我想为方法 findById 上的每个服务调用生成一个唯一的键,因为 ID 可以相同(因此有一个类转换异常):

java.lang.ClassCastException: x.y.model.RefSituation  cannot be cast to x.y.model.RefCivility

单元测试:

public class AbstractReferenceServiceTest extends AbstractBiTest {

@Inject
@Named("refSituationServiceClient")
private RefSituationService refSituationService;

@Inject
@Named("refCivilityServiceClient")
private RefCivilityService refCivilityService;

@Test
public void findById() {
RefSituation situation = refSituationService.findById(1L);
situation = refSituationService.findById(2L);
situation = refSituationService.findById(1L);

RefCivility refCivility = refCivilityService.findById(1L);
refCivility = refCivilityService.findById(2L);
refCivility = refCivilityService.findById(1L);
}
}

这两个服务都扩展了一个 AbstractReferenceService :

public interface RefSituationService extends AbstractReferenceService<RefSituation> {}
public interface RefCivilityService extends AbstractReferenceService<RefCivility> {}

并且 AbstractReferenceService 扩展了一个名为 RestHub (https://github.com/resthub/resthub-spring-stack/blob/master/resthub-common/src/main/java/org/resthub/common/service/CrudService.java) 的框架提供的 crudService

但是使用上面的配置我有一个错误:

org.springframework.expression.spel.SpelEvaluationException: EL1030E:(pos 0): The operator 'ADD' is not supported between objects of type 'java.lang.Class' and 'null'
at org.springframework.expression.spel.ExpressionState.operate(ExpressionState.java:198)
at org.springframework.expression.spel.ast.OpPlus.getValueInternal(OpPlus.java:97)
at org.springframework.expression.spel.ast.SpelNodeImpl.getValue(SpelNodeImpl.java:93)
at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:89)
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.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:91)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
at com.sun.proxy.$Proxy175.findById(Unknown Source)

预先感谢您的帮助。

最佳答案

问题是#root.targetClass.name 总是“CrudService”,要解决这个问题你必须:

1- 实现您自己的 CacheKeyGenerator :

应用上下文.xml:

    <bean id="refCacheKeyGenerator" class="x.y.cache.RefCacheKeyGenerator" />

<!-- cache definitions -->
<cache:advice id="cacheAdvice" key-generator="refCacheKeyGenerator" cache-manager="cacheManager">
<cache:caching cache="refs">
<cache:cacheable method="findById"/>
</cache:caching>
</cache:advice>

<aop:config>
<aop:advisor advice-ref="cacheAdvice" pointcut="execution(* x.y.*.service.reference.*.*(..))"/>
</aop:config>

Java:

public class RefCacheKeyGenerator implements org.springframework.cache.interceptor.KeyGenerator {

@Override
public Object generate(Object target, Method method, Object... params) {
final List<Object> key = new ArrayList<>();

key.add(method.getDeclaringClass().getName());
key.add(method.getName());

List<Class<?>> clazz = ClassUtils.getAllInterfaces(target.getClass());
if(CollectionUtils.isNotEmpty(clazz)){
for(Class<?> sClass : clazz){
if(AbstractReferenceService.class.isAssignableFrom(sClass)){
if(!AbstractReferenceService.class.equals(sClass)){
key.add(sClass.getName());
}
}
}
}
for (final Object o : params) {
key.add(o);
}

return key;
}

}

测试:

public class RefCacheTest extends AbstractTest {

@Autowired
private RefSituationService refSituationService;

@Autowired
private RefCivilityService refCivilityService;

@Autowired
private CacheManager cacheManager;


@Test
public void findById() {

Cache refCache = cacheManager.getCache(MyCache.REFS);
refCache.setStatisticsEnabled(true);

assertThat(refSituationService.findById(1L)).isInstanceOf(RefSituation.class);
assertThat(refSituationService.findById(1L)).isInstanceOf(RefSituation.class);
assertThat(refSituationService.findById(2L)).isInstanceOf(RefSituation.class);

assertThat(refCivilityService.findById(1L)).isInstanceOf(RefCivility.class);
assertThat(refCivilityService.findById(1L)).isInstanceOf(RefCivility.class);
assertThat(refCivilityService.findById(2L)).isInstanceOf(RefCivility.class);

System.out.println(refCache.getName() +" - "+ refCache.getStatistics().toString());

assertThat(refCache.getStatistics().getCacheHits()).isEqualTo(2);
assertThat(refCache.getSize()).isEqualTo(4);
}

关于java - @Cacheable 通过 Spring aop - 如何生成唯一的缓存键,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21832243/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com