通用Redis查询工具类,结合函数编程和设计模式
文章目录
- 前言
- 一、技术沉淀
- 1.模板模式
- (1)介绍
- (2)场景模拟
- (2)场景解析
- 二、需求结合代码
- 1. 分析
- 2. 代码实现
- (1). 定义中间人
- (2). 定义仓库
- 三、最终实现效果
- 1. User服务配置中间人管理RedisKey:
- 2. 最终使用
- 总结
前言
现阶段公司后端架构中缓存模块代码大量冗余,各个服务都有各自的缓存模块,并且功能一致,由于之前没有合适的方案提取Client方法,因此一直没有进行优化
提示:以下是本篇文章正文内容,下面案例可供参考
一、技术沉淀
1.模板模式
(1)介绍
模板方法模式是一种行为设计模式, 它在父类中定义了一个算法的框架, 允许子类在不修改结构的情况下重写算法的特定步骤。主要要用来复用代码
(2)场景模拟
在我们的系统中把十三个重要服务比喻为一个商家,每个商家都会有一些营销活动,活动的时候赠送礼物,这十三个商家要用的赠礼都放在各自的仓库里。不过每个商家来拿货的时候,各家门口的保安都需要确定商家的身份。
(2)场景解析
在这个场景中,我们系统的每个服务就是商家,仓库就是对应的Redis缓存,而那个门口确定身份的保安就是请求Redis所需要的Key。在这个场景中每个微服务都需要去Redis缓存中拿数据,虽然不同的服务拿出来数据有可能不同,可是本质上来分析就是服务带着Key去请求Redis
二、需求结合代码
1. 分析
- 是否可以让所有的服务从
自己
去拿货改为定一个中间人
去拿货? - 如果拿货的那个角色可以让
中间人
去执行,那么仓库是否也可以统一管理
呢?因为不统一管理的话,中间人需要拿着拿着商家的钥匙跑遍不同的仓库,效率上会更加低下。 - 如何让
中间人拿到商家的身份卡
去通过保安的识别?
2. 代码实现
(1). 定义中间人
/*** 中间人VO类,继承了[AbstractRedisGet]仓库出入权* <T> 为泛型是因为为了适配各个服务数据* @author 路过人间的姜先生*/
@Getter
@Setter
public abstract class AbstractDefaultVo<T> extends AbstractRedisGet {private String id;private String createUserId;private String updateUserId;private String createTime;private String updateTime;
}
/*** @className: ObjectVo* @description: 自定义函数接口* @author: 路过人间的姜先生* @date: 2022/9/1*/
@FunctionalInterface
public interface ObjectVo<T> {T get();
}
(2). 定义仓库
/*** @className: AbstractRedisGet* @description: 统一管理获取缓存的方法(缓存仓库入口)* @author: 路过人间的姜先生* @date: 2022/8/26*/
@Slf4j
@Component
@Data
public abstract class AbstractRedisGet {@JSONField(serialize = false)private String redisKey;// 需要各个服务VO去实现的 build()方法,把对应的 redisKey 在接口里面进行赋值public abstract void build();/*** 获取Redis的方法** @param: Supplier<T> supplier java8中自带的生产型接口* @author: 路过人间的姜先生* @date: 2022/8/26*/public <T> T getObjectVo(Supplier<T> supplier) {initializeBuild();Class aClass = parametBuilder();if (aClass != null) {// 获取缓中的对象return getT(redisKey, aClass, null, supplier);}return null;}/*** 获取Redis的方法,重载上面的获取Redis方法,在上面方法的基础上,* 可以重新设置缓存失效时间* * @author: 路过人间的姜先生* @date: 2022/8/26*/public <T> T getObjectVo(Integer seconds, Supplier<T> supplier) {initializeBuild();Class aClass = parametBuilder();if (aClass != null) {// 获取缓中的对象return getT(redisKey, aClass, seconds, supplier);}return null;}/*** 获取Redis的方法,其中只需要把需要执行的查询方法传入,就可以执行缓存查询的方法,如果缓存中没有的情况下会去执行您传入的方法** <p>和之前方法不同在于,可以使用支持任意类对象** <p>author: 路过人间的姜先生** <p>2022/8/26*/public <T> T getObject(ObjectVo<T> supplier) {initializeBuild();// 获取缓中的对象return getT(this.redisKey, Object.class, null, supplier);}/*** 获取Redis的方法,其中只需要把需要执行的查询方法传入,就可以执行缓存查询的方法,如果缓存中没有的情况下会去执行您传入的方法** <p>和之前方法不同在于,可以使用支持任意类对象 , 并且不需要实现改抽象类,可以用作扩展** <p>author: 路过人间的姜先生** <p>2022/8/26*/public <T> T getObject(Class clazz, Integer seconds, ObjectVo<T> supplier) {initializeBuild();// 获取缓中的对象return getT(this.redisKey, clazz, seconds, supplier);}/*** 通过key删除缓存** @author: 路过人间的姜先生* @date: 2022/8/26*/public void deleteCache() {initializeBuild();if (StringUtils.isNotBlank(redisKey) && RedisUtils.isCached(redisKey)) {RedisUtils.expire(redisKey, 1);}}/*** 构建处理Build方法,并且获取泛型实例** @return: void* @author: 路过人间的姜先生* @date: 2022/8/31*/private Class parametBuilder() {if (StringUtils.isNotBlank(redisKey)) {// 获取泛型实列ParameterizedType ptype = (ParameterizedType) this.getClass().getGenericSuperclass();Class clazz = (Class<T>) ptype.getActualTypeArguments()[0];return clazz;}return null;}/*** 构建处理Build方法** @date: 2022/9/1*/private void initializeBuild() {// 处理build方法,获取到 redisKeytry {Method build = this.getClass().getMethod("build");build.invoke(this);} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {log.error("Vo对象中的build方法不存在");}}/*** 返回缓存中的对象** @author: 路过人间的姜先生* @date: 2022/8/30*/private <T> T getT(String key, Class c, Integer seconds, Supplier<T> supplier) {try {return (T)Optional.ofNullable(RedisUtils.getBean(key, c)).map(e -> {RedisUtils.expire(key, seconds != null ? seconds : 86400);return e;}).orElseGet(() ->Optional.ofNullable(get(supplier)).map(e -> {RedisUtils.saveBean(key, e, seconds != null ? seconds : 86400);return e;}).orElseGet(() -> null));} catch (Exception e) {log.error("查询缓存失败={}", e.getMessage());return null;}}/*** 返回缓存中的对象 == 支持java基本对象类型** @author: 路过人间的姜先生* @date: 2022/8/30*/public <T> T getT(String key, Class c, Integer seconds, ObjectVo<T> supplier) {try {return (T)Optional.ofNullable(RedisUtils.getBean(key, c)).map(e -> {RedisUtils.expire(key, seconds != null ? seconds : 86400);return e;}).orElseGet(() ->Optional.ofNullable(supplier.get()).map(e -> {RedisUtils.saveBean(key, e, seconds != null ? seconds : 86400);return e;}).orElseGet(() -> null));} catch (Exception e) {log.error("查询缓存失败={}", e.getMessage());return null;}}/*** 单独处理查询服务的逻辑,并且进行异常处理** @author: 路过人间的姜先生* @date: 2022/8/26*/private <T> T get(Supplier<T> supplier) {try {return supplier.get();} catch (Exception e) {log.error("查询服务失败={}", e.getMessage());}return null;}
}
三、最终实现效果
1. User服务配置中间人管理RedisKey:
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class UserVo extends AbstractDefaultVo<UserVo>{public UserVo(String id) {super.setId(id);}@Overridepublic void build() {// 定义Rediskey , 在对对象进行初始化并且传入ID的时候,会直接给XcbRedisUtils的redisKey字段赋值super.setRedisKey(UserRedisKey.USER_USERVO.getName() + super.getId());}
}
2. 最终使用
// 查询缓存UserVo userVo =new UserVo(userId).getObjectVo(() -> {查询方法});
// 删除缓存
new UserVo(userId).deleteCache();// 自定义查询缓存方法AbstractRedisGet redisGet =new AbstractRedisGet() {@Overridepublic void build() {}};List<任意对象> list =redisGet.getT(key,List.class,15,() -> {查询方法});
总结
代码架构优化是一个剥丝抽茧的过程,希望我的帖子对各位有帮助。
通用Redis查询工具类,结合函数编程和设计模式相关推荐
- java redis remove_最全的Java操作Redis的工具类
RedisUtil 当前版本:1.1 增加更全的方法,对以前的部分方法进行了规范命名,请放心替换成新版本. 介绍 最全的Java操作Redis的工具类,使用StringRedisTemplate实现, ...
- 免费天气查询工具类源码,开箱即用,根据中国气象局API编写。高效稳定
文章目录 引言 相关依赖 WeatherUtil工具类代码 http工具类 测试 引言 使用Java语言,根据中国气象局API编写的查询天气工具类,代码引入就能用,代码中对异常做了处理,无论是否查询成 ...
- SpringBoot中操作spring redis的工具类
场景 SpringBoot+Vue+Redis实现前后端分离的字典缓存机制: https://blog.csdn.net/badao_liumang_qizhi/article/details/108 ...
- 分享一个nodejs中koa操作redis的工具类 基于 ioredis
分享一个node 操作redis的工具类 基于ioredis redis.js const config = require(':config/server.base.config'); const ...
- NC6 查询工具类 QueryUtil.java
NC6 查询工具类 package nc.impl.am.db;import java.util.ArrayList; import java.util.Collections; import jav ...
- java redis缓存工具类_redis工具类-JedisUtil
redis连接的工具类 1.java中的redis java中,使用redis不会将其当作数据库来使用,更多的是作为缓存或者是消息中间件来使用.在用作缓存时,我们需要使用第三方提供的jar包来进行开发 ...
- java rowmapper 通用实现_springmvc工具类封装RowMapper详解
springmvc通常是先写实体,在数据库查询,最后增删改差,最感觉代码很冗余,自己在封装了一下. 常见的结构是: entity:如 package com.liuxinquan.entiry; /* ...
- hbase 按时刻查询_Hbase查询工具类,根据时间查询数据
1,需求:已知空气监测数据在hbase中存储,要求按照时间,查询citycode为110000(北京)一个月的数据,数据为每日的监测数据 ID ,CITYCODE,SO2 ,CO,NO2 ,O3, P ...
- Flutter - 一个fultter练习项目(仿写微信UI、实现一些常用效果、封装通用组件和工具类)
demo 地址: https://github.com/iotjin/jh_flutter_demo 代码不定时更新,请前往github查看最新代码 pwd:123456 代码不定期更新 注:Flut ...
最新文章
- 函数声明末尾的“ const”是什么意思? [重复]
- 孕妇可以使用计算机,【电脑对孕妇有影响吗】电脑对孕妇的危害,孕妇能玩电脑吗 - 妈妈网百科...
- @RequestParam 注解的使用——Spring系列知识学习笔记
- .NET中生成动态验证码
- .NET应用迁移到.NET Core(三)从商业角度看移植过程
- 获取两个数据的交集_MySQL交集和差集的实现方法
- 使用WildFly 8在Java EE7中自举Apache Camel
- Python-100 练习题 02
- python开发框架 代码生成_我的第一个python web开发框架(31)——定制ORM(七)...
- beyond compare类似软件_你用过最好用的截图软件是哪一款
- C#+ArcEngine中com对象的释放问题
- 球形天空盒php,unity3d天空盒
- mysql千万测试表生成,随机id、username、age、sex、create_time
- mysql error1682_mysql5.7报错 1546、1577和1682问题分析
- (Android+Qt最小系统设计方案)RK3288核心板设计之软件开发环境搭建(4.0)
- 学生DW静态网页设计—西安旅游-高质量(9页) HTML+CSS+JavaScript 学生DW网页设计
- MySQL实现分数排名问题
- 微信接口返回的状态码
- 视频教程-Android Material Design 新控件-Android
- 使用 FFmpeg 转换视频/音频格式 | 开源 免费 | 不用套壳软件