Based on decoration mode + aop + jvm-map + redis + annotation design level one + level two cache framework

Cache description

1. Basic concepts of multi-level caching

In actual development projects, in order to reduce the pressure of database access, we will cache data in memory,
such as Redis (distributed cache), EHCHE (JVM built-in cache).
For example, in the early morning, the project is relatively small and may not use Redis. For caching, the JVM built-in caching framework is used. When the
project is relatively large, the Redis distributed caching framework is adopted. At this time, the first and second level caches need to be designed.

2. The basic concept of decoration mode

Add additional functions without changing the original code
Insert picture description here

1. Code structure

Insert picture description here

Second, the specific code

1. Custom annotations

/**
 * 自定义缓存注解
 */
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ExtXjCache {
}

2. Custom annotated Aop proxy class

/**
 * 自定义注解Aop
 */
@Aspect
@Component
@Slf4j
public class XjCacheAop {

    // 二级缓存执行对象
    @Autowired
    private XjCache xjCache;

    /**
     * 使用Aop拦截我们的方法上是否使用缓存注解
     *
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around(value = "@annotation(com.xijia.config.aop.ExtXjCache)")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        // 获取目标方法
        Method targetMethod = methodSignature.getMethod();
        // 拼接缓存的key = 方法名 + 参数类型 + 查询参数值
        String key = targetMethod.getName() + Arrays.toString(targetMethod.getParameterTypes()) + Arrays.toString(joinPoint.getArgs());
        // 执行二级缓存,传入 joinPoint 对象; 当没有获取到缓存数据时,在执行目标对象 joinPoint.proceed(),如果存在缓存数据,则提前返回,不查询数据库
        Object result = xjCache.getCacheEntity(key, targetMethod.getReturnType(), joinPoint);
        return result;
    }
}

3. Level 1 cache

Container (jvm-Map)

/**
 * jvm 缓存容器类
 */
public class JvmMapCacheUtils {
    /**
     * 缓存容器
     */
    private static Map<String, String> caches = new ConcurrentHashMap<>();

    public static  <T> T getEntity(String key, Class<T> t) {
        // 缓存存放对象的情况
        String json = caches.get(key);
        return JSONObject.parseObject(json, t);
    }

    public static void putEntity(String key, Object o) {
        String json = JSONObject.toJSONString(o);
        caches.put(key, json);
    }

}

interface

public interface ComponentCache {

    /**
     * 根据key查询缓存数据
     *
     * @param
     * @return
     */
    <T> T getCacheEntity(String key,Class<T> t, ProceedingJoinPoint joinPoint);
}

achieve

/**
  * 一级缓存(jvm缓存)
  * @author wangsong
  * @mail  [email protected]
  * @date  2020/8/31 0031 23:00
  * @version 1.0.0
  */
@Component
public class JvmComponentCache implements ComponentCache {

    /**
     *
     * @param key 缓存key
     * @param t 返回数据类型
     * @param joinPoint aop传入的对象
     * @param <T>
     * @return
     */
    @Override
    public <T> T getCacheEntity(String key, Class<T> t, ProceedingJoinPoint joinPoint) {
        // 查询一级的Jvm缓存, 如果存在, 直接返回
        T jvmUser = JvmMapCacheUtils.getEntity(key,t);
        if (jvmUser != null) {
            return (T) jvmUser;
        }
        // 一级缓存不存在, 通过aop 传入的joinPoint 执行目标对象方法, 由目标对象去查询数据库获取数据
        try {
            Object resultDb = joinPoint.proceed();
            // 数据库DB有的情况 将该内容缓存到当前Jvm中
            JvmMapCacheUtils.putEntity(key, resultDb);
            return (T) resultDb;
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            return null;
        }
    }
}

4. Level 2 cache

Second-level cache, use decoration mode to enhance the first-level cache, inherit the first-level cache interface ComponentCache

Abstract class interface

public interface AbstractDecorate extends ComponentCache {
}

Second-level cache decoration

/**
 * 二级缓存装饰类
 * extends JvmComponentCache 可使用 super 来查询一级缓存数据
 */
@Component
public class RedisDecorate extends JvmComponentCache implements AbstractDecorate {
    @Autowired
    private RedisUtils redisUtils;

//    @Autowired
//    private JvmComponentCache jvmComponentCache;

    /**
     *
     * @param key 缓存对象key
     * @param t 返回数据类型
     * @param joinPoint aop的传入的执行对象
     * @param <T>
     * @return
     */
    @Override
    public <T> T getCacheEntity(String key, Class<T> t, ProceedingJoinPoint joinPoint) {
        // 查询二级缓存, 如果存在,直接返回
        T redisUser = redisUtils.getEntity(key, t);
        if (redisUser != null) {
            return (T) redisUser;
        }
        // 二级缓存不存在,查询一级缓存, 并把一级缓存返回的数据放入二级缓存中
        T jvmUser = super.getCacheEntity(key, t, joinPoint);
        if (jvmUser != null) {
            redisUtils.putEntity(key, jvmUser);
            return (T) jvmUser;
        }
        // 没有查询到数据
        return null;
    }
}

Exposure to the execution object

@Component
public class XjCache {

    @Autowired
    private RedisDecorate redisDecorate;

    public <T> T getCacheEntity(String key, Class<T> t, ProceedingJoinPoint joinPoint) {
        return redisDecorate.getCacheEntity(key, t, joinPoint);
    }
}

Three, use cache/description

Any method plus custom cache annotation

  • Execution method aop intercepted to annotated method
  • Get method name, method parameter type, method query parameter == spelled into the cached key
  • Call the second-level cache object in aop to determine whether it exists, and there is no call to the first-level cache object
  • The first-level cache object is judged whether it exists, there is no execution aop, the target method is called, the target method queries the database and the data is returned and saved in the first-level cache and the second-level cache

Insert picture description here

  • Some of the above content comes from the ant classroom

  • Personal open source project (universal background management system) –> https://gitee.com/wslxm/spring-boot-plus2 , you can check it out if you like

  • This is the end of this article. If you find it useful, please like or pay attention to it. We will continue to update more content from time to time... Thank you for watching!

Guess you like

Origin blog.csdn.net/qq_41463655/article/details/108332102