項目中有使用到緩存,每次須要將緩存代碼和業務代碼雜糅在一塊兒,以及分散各處的key,嚴重影響代碼的可讀性。如下是使用AOP對其簡單嘗試。直接上代碼:redis
一、定義緩存註解:json
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Cache { long timeOut() default 0; TimeUnit timeUnit() default TimeUnit.HOURS; }
二、定義參數惟一鍵註解,使用此註解標記此輸入參數參與構成惟一鍵:緩存
@Target({ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) public @interface CacheUniqueKey { }
三、CacheAspectide
@Component @Slf4j @Aspect @Data public class CacheAspect { private final CacheCenter<String> cacheCenter; // 緩存開關配置 @Value("${service.cache}") private boolean cacheEnable = false; @Around(value = "@annotation(com.yingying.survey.component.cache.Cache)&&@annotation(cache)") public Object around(ProceedingJoinPoint joinPoint, Cache cache) throws Throwable { if (!cacheEnable) { return joinPoint.proceed(); } long timeOut = cache.timeOut(); TimeUnit timeUnit = cache.timeUnit(); if (timeOut == 0) { return joinPoint.proceed(); } Class<?> clazz = joinPoint.getTarget().getClass(); String clazzSimpleName = clazz.getSimpleName(); String methodName = joinPoint.getSignature().getName(); Signature signature = joinPoint.getSignature(); Class declaringType = ((MethodSignature) signature).getReturnType(); String uniqueParam = methodParamsResolve(joinPoint); String cacheKey = clazzSimpleName + ":" + methodName + ":" + uniqueParam; if (cacheCenter.isExistCache(cacheKey)) { String loadCache = cacheCenter.loadCache(cacheKey); log.info("data from cache:{}", loadCache); if (declaringType.isArray()) { return JSONArray.parseArray(loadCache, declaringType); } else { return JSON.parse(loadCache, declaringType); } } Object proceedResult = joinPoint.proceed(); // 爲了從緩存中取值時不出現空指針的狀況,現不對返回值爲空的結果緩存。 if (proceedResult != null) { String cacheData = JSON.json(proceedResult); CacheUnit cacheUnit = new CacheUnit().setTimeUnit(timeUnit).setCacheOutTime(timeOut).setCacheKey(cacheKey); cacheCenter.insertCache(cacheUnit, cacheData); } return proceedResult; } private String methodParamsResolve(ProceedingJoinPoint joinPoint) { Signature signature = joinPoint.getSignature(); Method method = ((MethodSignature) signature).getMethod(); Annotation[][] parameterAnnotations = method.getParameterAnnotations(); String uniqueParam = ""; int idx = 0; for (Annotation[] annotations : parameterAnnotations) { for (Annotation annotation : annotations) { if (annotation instanceof CacheUniqueKey) { Object[] args = joinPoint.getArgs(); uniqueParam = (String) args[idx]; return uniqueParam; } } idx++; } return uniqueParam; } }
四、緩存配置單元:spa
@Data @Accessors(chain = true) public class CacheUnit { @NotBlank @NotNull private String cacheKey; private long cacheOutTime = 0; @NotNull private TimeUnit timeUnit; }
五、緩存中心實現接口:3d
public interface CacheCenter<T> { boolean isExistCache(@NotNull @NotBlank String cacheKey); T loadCache(@NotNull @NotBlank String cacheKey); boolean insertCache(@NotNull CacheUnit cacheUnit, @NotNull T cacheData); }
六、基於Redis的緩存中心實現:指針
@Service("cacheCenter") @Data public class RedisCacheCenter implements CacheCenter<String> { private final RedisService redisService; @Override public boolean isExistCache(@NotNull @NotBlank String cacheKey) { return redisService.exists(cacheKey); } @Override public String loadCache(@NotNull @NotBlank String cacheKey) { return redisService.get(cacheKey); } @Override public boolean insertCache(@NotNull CacheUnit cacheUnit, @NotNull String cacheData) { long cacheOutTime = TimeUnit.SECONDS.convert(cacheUnit.getCacheOutTime(), cacheUnit.getTimeUnit()); redisService.set(cacheUnit.getCacheKey().getBytes(), cacheData.getBytes(), cacheOutTime); return true; } }
七、應用案例:code