基於Redis的Service緩存實現

項目中有使用到緩存,每次須要將緩存代碼和業務代碼雜糅在一塊兒,以及分散各處的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

相關文章
相關標籤/搜索