多租缓存实现方案 (Java)

   缓存在系统中是不可少的,缓存的实现是一个从无到有的过程,最开始,单应用的,缓存都是应用内部的,Map基本就能满足,实现简单。但是当上了微服务之后,应用是多部署的,应用之间的缓存在用Map就无法共享了,如果在调用一次其它服务,此时开销就会增大。

  Redis 目前可能是主流的,但是后续可能不用Redis ,可能用其它的内存缓存,如何让程序实现尽可能少的变化,同时支持通用的处理(如多租的缓存切换、增删、刷新等通用的实现),因此封装了通用缓存功能,缓存整体设计如下:

MuliTenantCache 顶层为缓存的基础对外接口(查询、刷新等)

public interface MuliTenantCache<KEY, OBJ> {

    boolean repeatedLoadding();

    boolean isReadonly();

    OBJ getObj(KEY key);

    List<OBJ> getObjs();

    List<OBJ> getObjs(List<KEY> keys);

    void refresh();

    void refresh(List<KEY> keys);

    void flush();

    void flushKeys(List<KEY> keys);

    void add(List<OBJ> values);

    void add(KEY key, OBJ value);
}

AbstractMuliTenantCache 主要是个模板实现,实现MuliTenantCache对外的方法,根据存储或用户自己的配置组合缓存。

public abstract class AbstractMuliTenantCache<T, M> implements MuliTenantCache<T, M> {

    protected MuliTenantCacheConfig<T, M> config;

    protected MuliTenantCacheStorage<T, M> storage;

    protected Class<M> clazzValue;

    @Override
public final void add(List<M> values) {
readonly();
storage.doAdd(values);
} @Override
public final void add(T key, M value) {
readonly();
storage.doAdd(key, value);
} @Override
public boolean isReadonly() {
return false;
} @Override
public boolean repeatedLoadding() {
return true;
} @Override
public M getObj(T key) {
M m = storage.getCacheObj(key);
if (m == null && repeatedLoadding()) {
m = config.query(key);
add(key, m);
m = storage.getCacheObj(key);
} return m;
} @Override
public List<M> getObjs() {
return new ArrayList<>(storage.getCachesObjs());
} @Override
public List<M> getObjs(List<T> keys) {
if (SbzObjectUtils.isNullOrEmpty(keys)) {
return Collections.EMPTY_LIST;
}
return storage.getCachesObjs(keys);
} @Override
public final void refresh() {
flush();
add(config.query());
} @Override
public final void refresh(List<T> keys) {
flushKeys(keys);
add(config.query(keys));
} @Override
public final void flushKeys(List<T> keys) {
readonly();
storage.doFlushKeys(keys);
} @Override
public final void flush() {
readonly();
storage.doFlush();
} private void readonly() {
if (isReadonly()) {
throw new SystemException("springbreeze cache is readonly ,can't set or refresh");
}
} protected T getKey(T key, M m) {
if (key != null) {
return key;
}
T result = config.getKey(m);
return result;
} protected Class<M> getClazzValue() {
return this.clazzValue;
} protected void setConfig(MuliTenantCacheConfig<T, M> config) {
this.config = config;
}
}
MuliTenantCacheConfig主要是缓存维护的逻辑,如数据源、配置是否只读、缓存分类等。
public interface MuliTenantCacheConfig<KEY, OBJ> {

    boolean repeatedLoadding();

    boolean isReadonly();

    String cacheType();

    KEY getKey(OBJ m);

    List<OBJ> query();

    OBJ query(KEY t);

    List<OBJ> query(List<KEY> ts);

}
MuliTenantCacheStorage 主要给缓存应用做的扩展,如Redis缓存和Map缓存需要分别实现对应点逻辑。
public interface MuliTenantCacheStorage<KEY, OBJ> {

    OBJ getCacheObj(KEY key);

    List<OBJ> getCachesObjs(List<KEY> key);

    List<OBJ> getCachesObjs();

    OBJ doAdd(KEY key, OBJ m);

    List<OBJ> doAdd(List<OBJ> values);

    void doFlushKeys(List<KEY> keys);

    void doFlush();
}
AbstractMuliTenantCacheBase 实现和组合 AbstractMuliTenantCache 逻辑,创建工作在 builder 中进行。
public abstract class AbstractMuliTenantCacheBase<KEY, OBJ> extends AbstractMuliTenantCache<KEY, OBJ>
implements MuliTenantCacheConfig<KEY, OBJ> { @Autowired
private SbzMuliTenantCacheBuilder<KEY, OBJ> builder; @PostConstruct
public void init() {
this.config = this;
this.storage = (MuliTenantCacheStorage<KEY, OBJ>) builder.build(this, getGenericClass());
} @SuppressWarnings("unchecked")
private Class<OBJ> getGenericClass() {
return (Class<OBJ>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[1];
}
}
SbzMuliTenantCacheBuilder 复制对象的创建,后续增加配置创建Map 或 其他的缓存存储。
@Component
public class SbzMuliTenantCacheBuilder<KEY, OBJ> { @Autowired
protected RedisService redisService; public AbstractMuliTenantCache<KEY, OBJ> build(MuliTenantCacheConfig<KEY, OBJ> config, Class<OBJ> clazz) {
RedisAbstractMuliTentantCache<KEY,
OBJ> cache = new RedisAbstractMuliTentantCache<>(config, redisService, clazz); return cache;
}
}
RedisMuliTentantCache 为Redis 的实现方式。
public class RedisMuliTentantCache<T, M> extends AbstractMuliTenantCache<T, M>
implements MuliTenantCacheStorage<T, M> { protected RedisService redisService; public RedisAbstractMuliTentantCache(MuliTenantCacheConfig<T, M> config, RedisService redisService,
Class<M> clazzM) {
this.redisService = redisService;
this.storage = this;
this.clazzValue = clazzM;
this.config = config;
} protected String getRedisKey(T key) {
return MessageFormat.format("{0}:{1}:{2}", UserInfo.getCurrentOrgCode(), config.cacheType(), key);
} protected String getRedisStrKey(String key) {
return MessageFormat.format("{0}:{1}:{2}", UserInfo.getCurrentOrgCode(), config.cacheType(), key);
} @Override
public M doAdd(T key, M m) {
redisService.set(getRedisKey(getKey(key, m)), JSON.toJSONString(m));
return m;
} @Override
public List<M> doAdd(List<M> values) {
if (!SbzObjectUtils.isNullOrEmpty(values)) {
values.forEach(s -> {
doAdd(config.getKey(s), s);
});
}
return values;
} @Override
public void doFlushKeys(List<T> keys) {
if (!SbzObjectUtils.isNullOrEmpty(keys)) {
String[] redisKeys = keys.stream().map(t -> getRedisKey(t)).toArray(String[]::new);
redisService.remove(redisKeys);
}
} @Override
public void doFlush() {
redisService.removePattern(getRedisStrKey("*"));
} @Override
public M getCacheObj(T key) {
String redisValue = redisService.getByKeyGenerial(getRedisKey(key));
if (!SbzStringUtils.isNullOrEmpty(redisValue)) {
M result = toObj(redisValue, getClazzValue());
return result;
} return null;
} @Override
public List<M> getCachesObjs() {
List<String> redisValues = redisService.getByPatternGenerial(getRedisStrKey("*"));
if (!SbzObjectUtils.isNullOrEmpty(redisValues)) {
List<M> result = new ArrayList<>(redisValues.size());
redisValues.forEach(s -> result.add(toObj(s, getClazzValue())));
return result;
} return Collections.EMPTY_LIST;
} @Override
public List<M> getCachesObjs(List<T> keys) {
Set<Serializable> redisKeys = new HashSet<>();
keys.forEach(s -> {
redisKeys.add(getRedisKey(s));
});
List<String> redisValues = redisService.getByKeysGenerial(redisKeys);
if (!SbzObjectUtils.isNullOrEmpty(redisValues)) {
List<M> result = new ArrayList<>(redisValues.size());
redisValues.forEach(s -> result.add(toObj(s, getClazzValue())));
return result;
} return Collections.EMPTY_LIST;
} public static <T> T toObj(String json, Class<T> t) {
return JSON.parseObject(json, t);
}

调用过程很简单。

@Component
public class DemoCache extends SbzAbstractMuliTenantCacheBase<String, DemoCacheInfo> { @Override
public String cacheType() {
return "DEMO_CACHE";
} @Override
public String getKey(DemoCacheInfo m) {
return m.getKey();
} @Override
public List<DemoCacheInfo> query() {
return DemoCacheInfo.get(Arrays.asList("C1", "C2", "C3"));
} @Override
public DemoCacheInfo query(String t) {
return LambdaUtils.firstOrDefault(DemoCacheInfo.get(Arrays.asList("C1")));
} @Override
public List<DemoCacheInfo> query(List<String> ts) {
return DemoCacheInfo.get(ts);
} }

多租缓存实现方案 (Java)的更多相关文章

  1. atitit.跨架构 bs cs解决方案. 自定义web服务器的实现方案 java .net jetty  HttpListener

    atitit.跨架构 bs cs解决方案. 自定义web服务器的实现方案 java .net jetty  HttpListener 1. 自定义web服务器的实现方案,基于原始socket vs   ...

  2. Web缓存(Varnish方案)

    Web缓存(Varnish方案) 转载 http://www.s135.com/post/313/ arnish是一款高性能的开源HTTP加速器,挪威最大的在线报纸 Verdens Gang (htt ...

  3. shiro使用redis作为缓存,出现要清除缓存时报错 java.lang.Exception: Failed to deserialize at org.crazycake.shiro.SerializeUtils.deserialize(SerializeUtils.java:41) ~[shiro-redis-2.4.2.1-RELEASE.jar:na]

    shiro使用redis作为缓存,出现要清除缓存时报错 java.lang.Exception: Failed to deserialize at org.crazycake.shiro.Serial ...

  4. Atitit.软件命名空间  包的命名统计 及命名表(2000个名称) 方案java package

    Atitit.软件命名空间  包的命名统计 及命名表(2000个名称) 方案java package 1. 统计的lib jar 列表1 2. Code3 3. 常用包名按找字母排序(2000个)4 ...

  5. iOS 本地缓存实现 方案借鉴

    在手机应用程序开发中,为了减少与服务端的交互次数,加快用户的响应速度,一般都会在iOS设备中加一个缓存的机制,前面一篇文章介绍了iOS设备的内存缓存,这篇文章将设计一个本地缓存的机制. 功能需求 这个 ...

  6. Redis获取缓存异常:java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to XXX

    Redis获取缓存异常:java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to XXX. 出现这种异常,我需要自 ...

  7. Window Redis分布式部署方案 java

    Redis分布式部署方案 Window 1.    基本介绍 首先redis官方是没有提供window下的版本, 是window配合发布的.因现阶段项目需求,所以研究部署的是window版本的,其实都 ...

  8. 如何利用缓存机制实现JAVA类反射性能提升30倍

    一次性能提高30倍的JAVA类反射性能优化实践 文章来源:宜信技术学院 & 宜信支付结算团队技术分享第4期-支付结算部支付研发团队高级工程师陶红<JAVA类反射技术&优化> ...

  9. 第三章 - CPU缓存结构和java内存模型

    CPU 缓存结构原理 CPU 缓存结构 查看 cpu 缓存 速度比较 查看 cpu 缓存行 cpu 拿到的内存地址格式是这样的 CPU 缓存读 根据低位,计算在缓存中的索引 判断是否有效 0 去内存读 ...

随机推荐

  1. hive+postgres安装部署过程

    master节点安装元数据库,采用postgres:#useradd postgres#password postgressu - postgreswget https://ftp.postgresq ...

  2. 数字千万别用puts!

    为了图省事我好几次都习惯的用puts输出一些确定答案,比如直接puts("-1"); 每次都wa到心态崩溃才想起来数字不能用puts...

  3. dp的小理解

    这段时间刷dp,总结出了一个不算套路的套路. 1.根据题意确定是否有重叠子问题,也就是前面的状态对后面的有影响,基本满足这个条件的就可以考虑用dp了. 2.确定是dp后,就是最难的部分--如何根据题意 ...

  4. pyspark Py4JJavaError: Unsupported class file major version 56

    在jupyter notebook跑上面的代码的时候报错Py4JJavaError: An error occurred while calling z:org.apache.spark.mllib. ...

  5. Linux POSIX共享内存方法&ipcs &struct shmid_ds

    内容是主进程创建子进程计算斐波那契数列. 其中计算到第几项是有主进程命令行输入. 共享内存段,并且查看了一些信息. 参考操作系统概念第七版 3.10,3.11 关于LINUX C库函数 中的 fpri ...

  6. printf,sprintf,fprintf的区别与联系

    在写代码过程中总会遇到printf和sprintf,既然这两个都遇到了,那么不妨再加一个fprintf吧. 他们三个都是将格式化字符串输出,区别就是他们输出的目标不一样. (1).printf,是把格 ...

  7. C++ part4

    红黑树 references: 红黑树详细分析,看了都说好 关于红黑树(R-B tree)原理,看这篇如何 性质: 1.节点是红色或黑色 2.根节点是黑色 3.叶子节点(叶子节点均为NULL)都是黑色 ...

  8. 51nod 1073约瑟夫环 递归公式法

    约瑟夫环问题的原来描述为,设有编号为1,2,--,n的n(n>0)个人围成一个圈,从第1个人开始报数,报到m时停止报数,报m的人出圈,再从他的下一个人起重新报数,报到m时停止报数,报m的出圈,- ...

  9. 北京网络赛G BOXES 大模拟+BFS

    题目描述 Description There is a strange storehouse in PKU. In this storehouse there are n slots for boxe ...

  10. Hexo-域名设置+收录

    Hexo-域名设置+Github域名加速+网址收录 Github.Gitee绑定域名,然后进行网址收录. 不想购买域名也完全可以进行网址收录. 购买阿里云域名 1.进入阿里云域名网站 2.进入价格详情 ...