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分布式缓存框架,这时候需要设计一级与二级缓存。
装饰模式应用场景
**多级缓存设计、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 <T>
* @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.数据库
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.测试结果 测试一级二级都没有数据
1、调用接口,首先进入aop – 查询二级缓存 RedisDecorateService,
2、 如果有二级缓存没有 则取查询一级缓存 L1CacheService,
3、如果一级缓存没有则目标方法查询数据库 gatewayHandlerDbService.getHandlerId(apiHandler)
4、查询完数据库并set返回到一级缓存,set完后返回到 RedisDecorateService
5、把从数据库查回来的结果 set到二级缓存,最后直接return
总结
Link design-decoration-pattern