阿里开源 JetCache 缓存框架介绍使用
一、JetCache
JetCache是一个基于Java的缓存系统封装,提供统一的API和注解来简化缓存的使用。 JetCache提供了比SpringCache更加强大的注解,可以原生的支持TTL、两级缓存、分布式自动刷新,还提供了Cache接口用于手工缓存操作。 当前有四个实现,RedisCache、TairCache(此部分未在github开源)、CaffeineCache(in memory)和一个简易的LinkedHashMapCache(in memory),要添加新的实现也是非常简单的。
全部特性:
- 通过统一的API访问Cache系统
- 通过注解实现声明式的方法缓存,支持TTL和两级缓存
- 通过注解创建并配置Cache实例
- 针对所有Cache实例和方法缓存的自动统计
- Key的生成策略和Value的序列化策略是可以配置的
- 分布式缓存自动刷新,分布式锁 (2.2+)
- 异步Cache API (2.2+,使用Redis的lettuce客户端时)
- Spring Boot支持
github地址: https://github.com/alibaba/jetcache
注意:
JetCache需要JDK1.8、Spring Framework4.0.8以上版本。Spring Boot为可选,需要1.1.9以上版本。如果不使用注解(仅使用jetcache-core),Spring Framework也是可选的,此时使用方式与Guava/Caffeine cache类似。
二、SpringBoot 引入
- pom
<!-- https://mvnrepository.com/artifact/com.alicp.jetcache/jetcache-starter-redis-lettuce --><dependency><groupId>com.alicp.jetcache</groupId><artifactId>jetcache-starter-redis-lettuce</artifactId><version>2.6.0.M1</version></dependency><dependency><groupId>com.github.ben-manes.caffeine</groupId><artifactId>caffeine</artifactId></dependency><!-- 添加对redis的支持 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><!-- 添加对连接池的支持 --><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId></dependency>
- application.yml
jetcache:statIntervalMinutes: 1 #统计间隔areaInCacheName: falselocal:default: #默认areatype: caffeinekeyConvertor: fastjsonremote:default:type: redis.lettuce #使用lettucekeyConvertor: fastjsonvalueEncoder: javavalueDecoder: javapoolConfig:minIdle: 1maxIdle: 50maxTotal: 1000maxWait: 1000
# uri: ['redis://password@192.168.0.1:6379/0','redis://password@192.168.0.2:6379/0','redis://password@192.168.0.3:6379/0']uri:- redis://password@192.168.0.1:6379/0 #redis://密码@IP:端口/库- redis://password@192.168.0.2:6379/0- redis://password@192.168.0.3:6379/0readFrom: masterPreferred #master优先
- 启动类开启缓存
@SpringBootApplication
@EnableCreateCacheAnnotation
@EnableMethodCache(basePackages = { "com.bxc.jetcache.jetcachedemo.service" })
public class JetcacheDemoApplication {public static void main(String[] args) {SpringApplication.run(JetcacheDemoApplication.class, args);}}
三、方法缓存
1. @Cached
使用@Cached方法可以为一个方法添加上缓存。JetCache通过Spring AOP生成代理,来支持缓存功能。注解可以加在接口方法上也可以加在类方法上,但需要保证是个Spring bean。
@Cached(name = "bxcCache:", cacheType = CacheType.BOTH, key = "#id", expire = 30, timeUnit = TimeUnit.MINUTES)
public String getCache(String id) {System.out.println("哈哈哈哈");return "abc";
}@CacheUpdate(name = "bxcCache:", key = "#id", value = "#result")
public String updateCache(String id) {return "update";
}@CacheInvalidate(name = "bxcCache:", key = "#id")
public String deleteCache(String id){return "delete";
}
上面代码中可以看出,我们可以使用SpEL(Spring Expression Language)来设置key和Value。name属性不是必须的,但是起个名字是个好习惯,展示统计数据的使用,会使用这个名字。如果同一个area两个@CreateCache的name配置一样,它们生成的Cache将指向同一个实例。这里面需要注意的是,java代码的编辑级别必须是1.8。
其中CacheType
CacheType.REMOTE 远程缓存,如:redis
CacheType.LOCAL本地缓存,如:linkedhashmap、caffeine
CacheType.BOTH 本地+远程缓存,二级缓存
@CacheUpdate和@CacheInvalidate的name和area属性必须和@Cached相同,name属性还会用做cache的key前缀。
@Cached注解和@CreateCache的属性非常类似,但是多几个:
属性 | 默认值 | 说明 |
---|---|---|
area | “default” | 如果在配置中配置了多个缓存area,在这里指定使用哪个area |
name | 未定义 | 指定缓存的唯一名称,不是必须的,如果没有指定,会使用类名+方法名。name会被用于远程缓存的key前缀。另外在统计中,一个简短有意义的名字会提高可读性。 |
key | 未定义 | 使用SpEL指定key,如果没有指定会根据所有参数自动生成。 |
expire | 未定义 | 超时时间。如果注解上没有定义,会使用全局配置,如果此时全局配置也没有定义,则为无穷大 |
timeUnit | TimeUnit.SECONDS | 指定expire的单位 |
cacheType | CacheType.REMOTE | 缓存的类型,包括CacheType.REMOTE、CacheType.LOCAL、CacheType.BOTH。如果定义为BOTH,会使用LOCAL和REMOTE组合成两级缓存 |
localLimit | 未定义 | 如果cacheType为LOCAL或BOTH,这个参数指定本地缓存的最大元素数量,以控制内存占用。如果注解上没有定义,会使用全局配置,如果此时全局配置也没有定义,则为100 |
localExpire | 未定义 | 仅当cacheType为BOTH时适用,为内存中的Cache指定一个不一样的超时时间,通常应该小于expire |
serialPolicy | 未定义 | 指定远程缓存的序列化方式。可选值为SerialPolicy.JAVA和SerialPolicy.KRYO。如果注解上没有定义,会使用全局配置,如果此时全局配置也没有定义,则为SerialPolicy.JAVA |
keyConvertor | 未定义 | 指定KEY的转换方式,用于将复杂的KEY类型转换为缓存实现可以接受的类型,当前支持KeyConvertor.FASTJSON和KeyConvertor.NONE。NONE表示不转换,FASTJSON可以将复杂对象KEY转换成String。如果注解上没有定义,会使用全局配置。 |
enabled | true | 是否激活缓存。例如某个dao方法上加缓存注解,由于某些调用场景下不能有缓存,所以可以设置enabled为false,正常调用不会使用缓存,在需要的地方可使用CacheContext.enableCache在回调中激活缓存,缓存激活的标记在ThreadLocal上,该标记被设置后,所有enable=false的缓存都被激活 |
cacheNullValue | false | 当方法返回值为null的时候是否要缓存 |
condition | 未定义 | 使用SpEL指定条件,如果表达式返回true的时候才去缓存中查询 |
postCondition | 未定义 | 使用SpEL指定条件,如果表达式返回true的时候才更新缓存,该评估在方法执行后进行,因此可以访问到#result |
2. @CacheRefresh 自动刷新
@CacheRefresh 相当于开始一个定时任务,定时刷新值到缓存中。
@Cached(name = "bxcCache:", cacheType = CacheType.BOTH, key = "#id", expire = 30, timeUnit = TimeUnit.MINUTES)
@CacheRefresh(refresh = 2, stopRefreshAfterLastAccess = 10, timeUnit = TimeUnit.SECONDS)
public String getCache(String id) {System.out.println("哈哈哈哈");return "abc";
}
refresh 刷新时间周期
stopRefreshAfterLastAccess 停止刷新周期
timeUnit 时间单位
运行效果:
@CacheRefresh注解说明:
属性 | 默认值 | 说明 |
---|---|---|
refresh | 未定义 | 刷新间隔 |
timeUnit | TimeUnit.SECONDS | 时间单位 |
stopRefreshAfterLastAccess | 未定义 | 指定该key多长时间没有访问就停止刷新,如果不指定会一直刷新 |
refreshLockTimeout | 60秒 | 类型为BOTH/REMOTE的缓存刷新时,同时只会有一台服务器在刷新,这台服务器会在远程缓存放置一个分布式锁,此配置指定该锁的超时时间 |
3. @CachePenetrationProtect 同步加载数据
当缓存访问未命中的情况下,对并发进行的加载行为进行保护。 当前版本实现的是单JVM内的保护,即同一个JVM中同一个key只有一个线程去加载,其它线程等待结果。
@Cached(name = "bxcCache:", cacheType = CacheType.BOTH, key = "#id", expire = 30, timeUnit = TimeUnit.MINUTES)
@CachePenetrationProtect
public String getCache(String id) {System.out.println("哈哈哈哈");return "abc";
}
参数解析:
四、缓存API
使用@CreateCache注解去创建一个Cache实例
@CreateCache(expire = 100, cacheType = CacheType.BOTH, localLimit = 50)
private Cache<Long, UserDO> userCache;
expire 超时时间
cacheType 缓存类型
localLimit 限制缓存数量
//写入缓存
cache.put("abc", "aaa");
//读取缓存
System.out.println("1 > " + cache.get("abc"));System.out.println("2 > "+ cache.computeIfAbsent("abc1", res -> {return "111";
}));System.out.println("3 > " + cache.computeIfAbsent("abc2", res -> {return "222";
}, false, 10, TimeUnit.SECONDS));
五、异步API
从JetCache2.2版本开始,所有的大写API返回的CacheResult都支持异步。当底层的缓存实现支持异步的时候,大写API返回的结果都是异步的。当前支持异步的实现只有jetcache的redis-luttece实现,其他的缓存实现(内存中的、Tair、Jedis等),所有的异步接口都会同步堵塞,这样API仍然是兼容的。
CacheGetResult<UserDO> r = cache.GET(userId);
这一行代码执行完以后,缓存操作可能还没有完成,如果此时调用r.isSuccess()或者r.getValue()或者r.getMessage()将会堵塞直到缓存操作完成。如果不想被堵塞,并且需要在缓存操作完成以后执行后续操作,可以这样做:
CompletionStage<ResultData> future = r.future();
future.thenRun(() -> {if(r.isSuccess()){System.out.println(r.getValue());}
});
以上代码将会在缓存操作异步完成后,在完成异步操作的线程中调用thenRun中指定的回调。CompletionStage是Java8新增的功能,如果对此不太熟悉可以先查阅相关的文档。需要注意的是,既然已经选择了异步的开发方式,在回调中不能调用堵塞方法,以免堵塞其他的线程(回调方法很可能是在event loop线程中执行的)。
部分小写的api不需要任何修改,就可以直接享受到异步开发的好处。比如put和removeAll方法,由于它们没有返回值,所以此时就直接优化成异步调用,能够减少RT;而get方法由于需要取返回值,所以仍然会堵塞。
六、分布式锁
boolean hasRun = cache.tryLockAndRun("liuxw3", 100, TimeUnit.SECONDS, () -> {System.out.println("我获取到锁了");
});
阿里开源 JetCache 缓存框架介绍使用相关推荐
- 阿里开源的缓存框架JetCache,实现spring二级缓存
之前一直在用Spring Cache进行接口数据的缓存,主要是Spring Cache在对具体key缓存失效时间的设置不是很方法,还要自己去扩展,无意中发现了阿里的JetCache.大部分的需求都能满 ...
- Java 开源分布式缓存框架Ehcache
Ehcache 是一个Java实现的开源分布式缓存框架,EhCache 可以有效地减轻数据库的负载,可以让数据保存在不同服务器的内存中,在需要数据的时候可以快速存取.同时EhCache 扩展非常简单, ...
- 阿里开源深度学习框架XDL,面向高维稀疏数据,支持千亿参数训练规模
安妮 发自 阿里中心 量子位 出品 | 公众号 QbitAI 近日,阿里巴巴首次开源了面向高维稀疏数据的深度学习框架,叫作X-Deep Learning,简称XDL. 阿里表示,XDL基于大数据营销平 ...
- 阿里巴巴开源的缓存框架JetCache创建缓存
官网:https://github.com/alibaba/jetcache/wiki/CacheAPI_CN ======================= 多层嵌套缓存无效的问题: https:/ ...
- jcs开源缓存框架介绍
这篇文章写的通俗易懂,转自http://blog.csdn.net/zyujie/article/details/7369463,以作学习. JCS是Jakarta的项目Turbine的子项目.它是一 ...
- 第二代NumPy?阿里开源超大规模矩阵计算框架Mars
机器之心 2018-12-26 13:41:47 选自 GitHub,机器之心编译,参与:刘晓坤. Mars 是由阿里云高级软件工程师秦续业等人开发的一个基于张量的大规模数据计算的统一框架,目前它已在 ...
- github开源企业级应用框架介绍CIIP
简介 CIIP是基于XAF开发的开源信息系统框架,经历了4个月的开发终于可以拉出来见人了.CIIP最常见的应用场景是基于数据库的企业级应用程序,例如供应链系统,ERP系统,MRP系统,CRM系统等. ...
- 详解阿里开源分布式事务框架Seata
Seata发展历史 笔者于2014年开始着手解决阿里巴巴集团内部业务的分布式事务问题,从0到1研发一个支持非侵入模式(内部称之为AT模式,即自动模式)和TCC模式(内部称之为MT模式,即手动模式)的分 ...
- dva开源项目_dva 框架介绍
dva 是基于 redux 最佳实践 实现的 framework,简化使用 redux 和 redux-saga 时很多繁杂的操作 数据流向 数据的改变发生通常是通过用户交互行为或者浏览器行为(如路由 ...
最新文章
- Linux环境HBase安装与使用
- numpy.concatenate详解
- hdu 1054 Strategic Game 二分图最小点覆盖
- Flask的forms类
- 计算结构体、数组、指针的sizeof
- nginx php access denied,LNMP 解决Access Denied错误详细介绍
- 《Django实战系列》
- Windows 10中安装.net framework提示已经安装
- 算法导论——lec 12 平摊分析与优先队列
- centos7修改命令行或图形界面启动模式
- Java进阶之路,技术要点
- 公司法人没社保零申报,原来可以这样?
- HTML5+CSS大作业——清新春暖花开个人博客网站(6页)
- C++中如何创建一个类?
- thymeleaf模板引擎即时生效的问题
- iOS崩溃日志符号化及NLP聚类实现
- 群晖NAS 7.X版搭建博客网站,并内网穿透发布公网可访问 8-8
- pyqt5做一个工具箱
- python 类 实例_Python类的实例详解
- 吃鸡ios和android灵敏度,和平精英灵敏度怎么调最稳2020二指攻略:安卓苹果灵敏度调节方法大全[多图]...