Java设计模式 Java设计模式 修饰模式 Java设计模式之修饰模式 APO实现 多级缓存

Java设计模式之修饰模式 基于APO实现

  • 基于装饰模式实现多级缓存策略
  • 装饰模式应用场景
  • 二、代码实现 (+AOP 实现多级缓存)
    • 1 Redis 工具类 RedisUtils
    • 2基于jvm缓存 JvmMapCacheUtils
    • 3.抽象组件:定义一个抽象接口,来规范准备附加功能的类 ComponentCache
    • 4.将要被附加功能的类,实现抽象构件角色接口 AbstractDecorate
    • 5.持有对具体构件角色的引用并定义与抽象构件角色一致的接口 L1CacheService
    • 6.持有对具体构件角色的引用并定义与抽象构件角色一致的接口 RedisDecorateService
    • 6.基于aop拦截目标方法
    • 7.数据库
    • 8.接口测试
    • 8.测试结果 测试一级二级都没有数据
  • 总结
  • Link [design-decoration-pattern](https://gitee.com/wu_xiaoxi/springboot-family.git)

基于装饰模式实现多级缓存策略

重点:不改变原有代码的基础之上,新增附加功能

在实际开发项目,为了减少数据库的访问压力,我们都会将数据缓存到内存中
比如:Redis(分布式缓存)、EHCHE(JVM内置缓存).
例如在早起中,项目比较小可能不会使用Redis做为缓存,使用JVM内置的缓存框架,
项目比较大的时候开始采用Redis分布式缓存框架,这时候需要设计一级与二级缓存。

Java设计模式 Java设计模式 修饰模式 Java设计模式之修饰模式 APO实现 多级缓存_第1张图片

装饰模式应用场景

**多级缓存设计、mybatis中一级与二级缓存、IO流**

二、代码实现 (+AOP 实现多级缓存)

1 Redis 工具类 RedisUtils


@Component
public class RedisUtils {
     

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    // 如果key存在的话返回fasle 不存在的话返回true
    public Boolean setNx(String key, String value, Long timeout) {
     
        Boolean setIfAbsent = stringRedisTemplate.opsForValue().setIfAbsent(key, value);
        if (timeout != null) {
     
            stringRedisTemplate.expire(key, timeout, TimeUnit.SECONDS);
        }
        return setIfAbsent;
    }

    /**
     * 存放string类型
     *
     * @param key     key
     * @param data    数据
     * @param timeout 超时间
     */
    public void setString(String key, String data, Long timeout) {
     
        stringRedisTemplate.opsForValue().set(key, data);
        if (timeout != null) {
     
            stringRedisTemplate.expire(key, timeout, TimeUnit.SECONDS);
        }
    }

    /**
     * 存放string类型
     *
     * @param key  key
     * @param data 数据
     */
    public void setString(String key, String data) {
     
        setString(key, data, null);
    }

    /**
     * 根据key查询string类型
     *
     * @param key
     * @return
     */
    public String getString(String key) {
     
        String value = stringRedisTemplate.opsForValue().get(key);
        return value;
    }

    public <T> T getEntity(String key, Class<T> t) {
     
        String json = getString(key);
        return JSONObject.parseObject(json, t);
    }

    public void putEntity(String key, Object object) {
     
        String json = JSONObject.toJSONString(object);
        setString(key, json);
    }

    /**
     * 根据对应的key删除key
     *
     * @param key
     */
    public boolean delKey(String key) {
     
        return stringRedisTemplate.delete(key);
    }


    public void setList(String key, List<String> listToken) {
     
        stringRedisTemplate.opsForList().leftPushAll(key, listToken);
    }

    public StringRedisTemplate getStringRedisTemplate() {
     
        return stringRedisTemplate;
    }
}

2基于jvm缓存 JvmMapCacheUtils


/**
 * @Author : sean
 * @DateTime : 2021/8/3、22:27
 * @Description : 缓存基础缓存
 **/
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);
    }
}

3.抽象组件:定义一个抽象接口,来规范准备附加功能的类 ComponentCache


/**
 * @author: Sean
 * @time: 2021/8/4
 * @description: 定义共同规范,最初开始定义好
 */
public abstract class ComponentCache {
     

    /**
     * 共同方法
     * @param 
     * @return
     */
    public abstract  <T> T getCacheEntity(String key,Class<T> t, ProceedingJoinPoint joinPoint);
}

4.将要被附加功能的类,实现抽象构件角色接口 AbstractDecorate


/**
 * @author: Sean
 * @time: 2021/8/4
 * @description: 抽象装饰类,针对一级缓存增强
 */
public abstract class AbstractDecorate extends ComponentCache {
     

}

5.持有对具体构件角色的引用并定义与抽象构件角色一致的接口 L1CacheService

/**
 * @author: Sean
 * @time: 2021/8/4
 * @description: 一级缓存 装饰类
 */
@Component
public class L1CacheService extends ComponentCache {
     

    @Override
    public <T> T getCacheEntity(String key,Class<T> t, ProceedingJoinPoint joinPoint) {
     

        //从以一级缓存jvm(new Map)中找,是否有,
        T gatewayHandlerEntity = JvmMapCacheUtils.getEntity(key, t);

        if (gatewayHandlerEntity != null) {
     
            return gatewayHandlerEntity;
        }

        try {
     
              //一级缓存没有直接执行目标方法 查数据库 方法: gatewayHandlerDbService.getHandlerId(apiHandler

            Object result = joinPoint.proceed();

            JvmMapCacheUtils.putEntity(key, result);

            return (T) result;

        } catch (Throwable throwable) {
     

            throwable.printStackTrace();
            return null;
        }
    }
}

6.持有对具体构件角色的引用并定义与抽象构件角色一致的接口 RedisDecorateService

/**
 * @author: Sean
 * @time: 2021/8/4
 * @description: 二级缓存拓展 ,对最开始基本功能实现增强,二级缓存装饰类
 */
@Component
public class RedisDecorateService extends AbstractDecorate {
     

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private L1CacheService l1CacheService;

    @Override
    public <T> T getCacheEntity(String key, Class<T> t, ProceedingJoinPoint joinPoint) {
     

        //查询耳机缓存
        T gatewayHandlerEntity = redisUtils.getEntity(key, t);

        if (gatewayHandlerEntity != null) {
     
            return gatewayHandlerEntity;
        }

        T handlerEntity = l1CacheService.getCacheEntity(key, t, joinPoint);
        
		//如果一级缓存查回来为空,执行aop目标方法,并把查回来的值保存到二级缓存中
        if (handlerEntity != null) {
     

            redisUtils.putEntity(key, handlerEntity);

            return handlerEntity;
        }

        return null;
    }
}

6.基于aop拦截目标方法

/**
 * 定义注解接口 缓存注解
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ExitCache {
     
}
/**
 * @Author : sean
 * @DateTime : 2021/8/4、21:37
 * @Description : AOP 拦截注解
 **/
@Component
@Aspect
public class ExitAsyncAop {
     

    @Autowired
    private RedisDecorateService redisDecorateService;

    /**
     * 拦截方法上是否有缓存注解
     *
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around(value = "@annotation(com.sean.springboot.aop.ExitCache)")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
     

        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();

        //获取目标方法
        Method method = methodSignature.getMethod();

        String key = method.getName() + Arrays.toString(method.getParameterTypes()) + Arrays.toString(joinPoint.getArgs());

        //泛型:api 返回结果 method.getReturnType()
        return redisDecorateService.getCacheEntity(key, method.getReturnType(), joinPoint);
    }
}

7.数据库

Java设计模式 Java设计模式 修饰模式 Java设计模式之修饰模式 APO实现 多级缓存_第2张图片

8.接口测试

@RestController
@RequestMapping("/")
public class ModificationController {
     


    @Autowired
    private GatewayHandlerDbService gatewayHandlerDbService;

    @ExitCache
    @GetMapping("mod/{apiHandler}")
    public GatewayHandlerEntity modification(@PathVariable("apiHandler") String apiHandler) {
     

        return gatewayHandlerDbService.getHandlerId(apiHandler);
    }
}

8.测试结果 测试一级二级都没有数据

Java设计模式 Java设计模式 修饰模式 Java设计模式之修饰模式 APO实现 多级缓存_第3张图片

1、调用接口,首先进入aop – 查询二级缓存 RedisDecorateService,
2、 如果有二级缓存没有 则取查询一级缓存 L1CacheService,
3、如果一级缓存没有则目标方法查询数据库 gatewayHandlerDbService.getHandlerId(apiHandler)
4、查询完数据库并set返回到一级缓存,set完后返回到 RedisDecorateService
5、把从数据库查回来的结果 set到二级缓存,最后直接return

总结

Link design-decoration-pattern

你可能感兴趣的:(java设计模式,java,redis,设计模式,aop,缓存)