[英]@Cacheable via Spring aop - how generate unique cache key
我想在幾個服務上啟用緩存,這些服務擴展了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的框架提供的crudService( https://github.com/resthub/resthub-spring-stack/blob/master/resthub-common/src/main/java/org/resthub/common/service/ CrudService.java )
但是上面的配置我有一個錯誤:
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:
ApplicationContext.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);
}
很可能這里發生的是+
運算符和類型可能是也可能不是Strings
。 假設你想字符串連接(長算法將導致沖突,我認為你想避免的),強迫你的關鍵參數Strings
可能會解決問題。 翼:
<!-- cache definitions -->
<cache:advice id="cacheAdvice" cache-manager="cacheManager">
<cache:caching cache="refs">
<cache:cacheable method="findById" key="#root.targetClass.name + #id.toString()"/>
</cache:caching>
</cache:advice>
我現在正在嘗試,只需使用下一個配置,它就可以工作,而無需額外的密鑰生成器自定義實現:
@Cacheable(value = "lookups", key="T(org.springframework.cache.interceptor.SimpleKeyGenerator).generateKey(#root.target.class, #root.args)")
這里的主要思想包括具體的對象類作為關鍵部分之一。
這是創建唯一鍵的更簡單方法:
@Cacheable(value = "all-coupons", cacheManager="cacheManagerCompany" , key="#root.method + #this.toString()")
@Override
public List<Coupon> getAllCoupons() {
return compDBDAO.getCoupons();
}
這個問題的解決方案是使用key="#root.method + #this.toString()
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.