SSM项目中使用Redis缓存

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Yubu_/article/details/75099098

适合使用缓存的数据:

1 很少更新的数据

2 经常被用到的数据

3 数据量不大的数据


缓存控制

声明3个注解,对类或者方法是否支持缓存进行控制


@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyCacheable {

    int expire() default 600;//缓存过期时间,单位秒,默认60
}

@Target(ElementType.METHOD)
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface MyUseCache {

}

@Target(ElementType.METHOD)
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface MyClearCache {

}

MyCacheable注解标注在类上,控制这个类的方法时候可以使用MyUseCache和MyClearCache注解

MyUseCache注解标注在方法上,在执行方法之前,先从缓存尝试获取数据,如果获取了,直接返回数据,如果没有获取到,执行方法进行查询,并且把查询到的数据放入缓存

MyClearCache注解标注在方法上,清空缓存


使用原则

会更新数据的操作都清理缓存

对于有关联关系的表,当相关联的表进行了更新操作时,会出现缓存数据和数据库数据不一致,通过设置缓存过期时间来解决。缓存过期时间根据数据不一致可接受时间决定

由于需要支持过期时间,需要每条缓存使用一个独立的key,为了对一个表的缓存进行全部删除,需要保证同一个类的缓存的key的前缀一致

value是json格式的字符串数据,如果查询方法的返回值不符合json格式,则不能使用缓存


实现缓存的AOP代码


@Aspect
public class CacheAspect {

    @Pointcut("@target(com.my.annotation.MyCacheable)")
    private void cacheable() {

    }

    @Pointcut("@annotation(com.my.annotation.MyUseCache)")
    private void useCache() {

    }

    @Pointcut("@annotation(com.my.annotation.MyClearCache)")
    private void clearCache() {

    }

    @SuppressWarnings("all")
    @Around("cacheable() && useCache()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {

        //目标类Class对象
        Class targetClass = joinPoint.getTarget().getClass();
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();

        String key = createKey(joinPoint);
        String value = JedisUtils.get(key);//从缓存中取数据

        //如果缓存数据不为空,则直接使用缓存数据
        if (!CommonUtils.isEmpty(value)) {

            //方法返回值类型
            Class returnType = ReflectUtils.getActualReturnType(targetClass, method);
            //方法返回值类型的泛型类型
            Class[] parametricTypes = ReflectUtils.getActualParametricTypeOfReturnType(targetClass, method);

            return JsonUtils.toBean(value, returnType, parametricTypes);

        } else {
            //如果执行到这里就说明缓存里面没有数据,则执行正常逻辑(从数据库中查询数据)
            Object returnObject = joinPoint.proceed();
            MyCacheable cacheable = (MyCacheable) targetClass.getAnnotation(MyCacheable.class);
            //把数据存入缓存
            JedisUtils.setex(key, cacheable.expire(), JsonUtils.toJson(returnObject));
            return returnObject;
        }
    }

    @After("cacheable() && clearCache()")
    public void after(JoinPoint joinPoint) {
        //清空和此key前缀匹配的所有缓存
        JedisUtils.del(createKeyPatternForDelete(joinPoint));
    }

    //生成要删除的redis key的正则表达式
    private String createKeyPatternForDelete(JoinPoint joinPoint) {
        StringBuilder keyPattern = new StringBuilder();
        keyPattern.append("cache_").append(joinPoint.getTarget().getClass().getName()).append("_*");
        return keyPattern.toString();
    }

    private String createKey(JoinPoint joinPoint) {
        StringBuilder key = new StringBuilder();//redis缓存key的前缀

        key.append("cache_").append(joinPoint.getTarget().getClass().getName()).append("_");

        String signature = joinPoint.getSignature().toString();
        signature = signature.substring(signature.lastIndexOf('.') + 1);

        key.append(signature).append("_");

        Object[] args = joinPoint.getArgs();
        if (args != null && args.length > 0) {

            String argsStr = JsonUtils.toJson(args);

            //把:替换为_,避免生成命名空间
            argsStr = argsStr.replaceAll(":", "_");
            key.append(argsStr);
        }
        return key.toString();
    }

}







猜你喜欢

转载自blog.csdn.net/Yubu_/article/details/75099098