내가 뭘하려고하면 @Cacheable 주석 봄처럼 많이 제공 보이는 주석을하는 것입니다.
그것은 다음과 같은 방법 위에 사용하는 :
@CleverCache(key = "'orders_'.concat(#id)")
public Order getOrder(int id) {
내가 캐시 가능을 사용하여 동일한을 사용하면 어떻게 든이 SpEL을 표현을 해석하고 가치있는 키 생성 할 수 있습니다 orders_1234
(= 1234 지정된 ID를)
내 일치하는 조언은 다음과 같습니다 :
@Around("CleverCachePointcut(cleverCache)")
public Object clevercache(ProceedingJoinPoint joinPoint, CleverCache cleverCache) throws Throwable {
String expression = cleverCache.key();
//FIXME: Please add working code here :D - extracting the key by interpreting the passed SpEL Expression in expression
나는 definitly가 식을 얻을 수 있지만, 아직 그것이 제대로 SpEL을-식 해석되어 작동하게하는 방법을 알아낼하지 않았다.
또 다른 지원 구문은해야 key = "T(com.example.Utils).createCacheKey(#paramOfMethodByName)"
키를 만들 수는 A의 정적 도우미가 호출된다.
이 작업을 수있는 방법을 어떤 생각? : 나는에서 조각을 가지고있는 코드에서 확인할 수있다 https://github.com/eiselems/spring-redis-two-layer-cache/blob/master/src/main/java/com/marcuseisele/example/twolayercache/ 의 CleverCache / ExampleAspect.java # L35
어떤 도움도 정말 감사합니다!
당신이 필요한 컨텍스트 정보가있는 경우, SpEL을 평가하기 위해 실제로 매우 간단합니다. 를 참조하십시오 이 문서 프로그램 SpEL을 구문 분석하는 방법을 찾기 위해.
그 컨텍스트 정보에 관해서는, 당신은 당신이 주석이 방법의 유형에 대해 잘 설명하지 않았다 @CleverCache
. 문제는 포인트 컷 도청 모든 방법을 주석하고 각각의 첫 번째 매개 변수는 경우 나도 몰라이다 int
ID. 이 질문에 대한 대답에 따라 그것은 쉽게 (하나의 간단한 경우) 또는 도청 방법에서 ID 인수 값을 얻기 위해 (단지 정수 ID와 방법을 찾을 경우 - 다른 사람을 위해 당신이 필요로하는) 더 어렵다. 아니면 여러 유형 및 방법 매개 변수, 인스턴스 변수 또는 무엇이든의 이름을 참조하는 식의 모든 종류가 있습니다. 이 솔루션의 복잡성 요구 사항 '복잡성에 연결되어 있습니다. 당신이 더 많은 정보를 제공하는 경우, 어쩌면 나 또한 더 많은 도움을 제공 할 수 있습니다.
업데이트 : 당신의 GitHub의의의 repo 보았다 데, 나는 간단한 경우에 대한 측면을 리팩토링 :
package com.marcuseisele.example.twolayercache.clevercache;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@Aspect
@Component
@Slf4j
public class ExampleAspect {
private static final ExpressionParser expressionParser = new SpelExpressionParser();
private Map<String, RedisTemplate> templates;
public ExampleAspect(Map<String, RedisTemplate> redisTemplateMap) {
this.templates = redisTemplateMap;
}
@Pointcut("@annotation(cleverCache)")
public void CleverCachePointcut(CleverCache cleverCache) {
}
@Around("CleverCachePointcut(cleverCache) && args(id)")
public Object clevercache(ProceedingJoinPoint joinPoint, CleverCache cleverCache, int id) throws Throwable {
long ttl = cleverCache.ttl();
long grace = cleverCache.graceTtl();
String key = cleverCache.key();
Expression expression = expressionParser.parseExpression(key);
EvaluationContext context = new StandardEvaluationContext();
context.setVariable("id", id);
String cacheKey = (String) expression.getValue(context);
System.out.println("### Cache key: " + cacheKey);
long start = System.currentTimeMillis();
RedisTemplate redisTemplate = templates.get(cleverCache.redisTemplate());
Object result;
if (redisTemplate.hasKey(cacheKey)) {
result = redisTemplate.opsForValue().get(cacheKey);
log.info("Reading from cache ..." + result.toString());
if (redisTemplate.getExpire(cacheKey, TimeUnit.MINUTES) < grace) {
log.info("Entry is in Grace period - trying to refresh it");
try {
result = joinPoint.proceed();
redisTemplate.opsForValue().set(cacheKey, result, grace+ttl, TimeUnit.MINUTES);
log.info("Fetch was successful - new value will be returned");
} catch (Exception e) {
log.warn("An error occured while trying to refresh the value - extending the old one", e);
//TODO: think about only adding 5 minutes on top of grace, or 50% of ttl on top of grace
//if protected by a circuit breaker we could go REALLY low here
redisTemplate.opsForValue().getOperations().expire(cacheKey, grace+ttl, TimeUnit.MINUTES);
}
}
} else {
result = joinPoint.proceed();
log.info("Giving from method ..." + result.toString());
redisTemplate.opsForValue().set(cacheKey, result, ttl + grace, TimeUnit.MINUTES);
}
long executionTime = System.currentTimeMillis() - start;
log.info("{} executed in {} ms", joinPoint.getSignature(), executionTime);
log.info("Result: {}", result);
return result;
}
}
은 diff는 다음과 같습니다 :