优雅的缓存开发,看这一篇文章就可以了「干货」

用Java打酱油 2017-10-01 00:08

优雅的缓存开发,看这一篇文章就可以了「干货」

缓存重要性及缓存开发的几个阶段,见这篇文章,本文主要关注如何优雅的做缓存开发:

  • 基于注解的缓存开发,对应用代码无侵入性;

  • 可以方的切换第三方缓存框架,无需修改代码;

  • 服务调用方(缓存使用者)无需识别是缓存调用还是一般服务调用,举例说明:调用方在调用UserService.getUser(String userId)服务时,无需关心服务具体实现是基于缓存还是直接查询数据库,由服务提供者根据系统实现吞吐量来决定,系统初期压力不大,可以不使用缓存,待到有性能瓶颈了,修改服务实现支持缓存。

Spring cahe可以很好的满足以上需求,还能带来意外的小惊喜。

Spring cache简介

Spring cache基于注释(annotation)的缓存(cache)技术,它本质上不是一个具体的缓存实现方案(例如 EHCache 或者 Redis),而是一个对缓存使用的抽象,通过在既有代码中添加少量它定义的各种 annotation,即能够达到缓存方法的返回对象的效果。

Spring cache的缓存技术还具备相当的灵活性,不仅能够使用 SpEL(Spring Expression Language)来定义缓存的 key 和各种 condition,还提供开箱即用的缓存临时存储方案,也支持和主流的专业缓存例如 Redis集成。

其特点总结如下:

  • 通过少量的配置 annotation 注释即可使得既有代码支持缓存

  • 支持开箱即用 Out-Of-The-Box,即不用安装和部署额外第三方组件即可使用缓存

  • 支持 Spring Express Language,能使用对象的任何属性或者方法来定义缓存的 key 和 condition

  • 支持 AspectJ,并通过其实现任何方法的缓存支持

  • 支持自定义 key 和自定义缓存管理者,具有相当的灵活性和扩展性

干货就要先看示例

1.配置一个基于内存的缓存

优雅的缓存开发,看这一篇文章就可以了「干货」

配置缓存管理器

2.定义一个用户User实体类

优雅的缓存开发,看这一篇文章就可以了「干货」

pojo

3.定义UserService接口和UserServiceImpl,这个实现类是重点。在getUser方法上添加了@Cacheable注解,意思即是如果调用该方法,则先到名为userCache的缓存中根据id找User是否存在,如果不存在才会到数据库查询,并且将查询结果放到缓存中。

  • 名为userCache的缓存实现是org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean,在第1步中已经注册;

  • 在调用getUser方法时会先到缓存中查找;

  • getUser方法执行完成后会将结果缓存起来,以便下次从缓存中查询;

优雅的缓存开发,看这一篇文章就可以了「干货」

服务类

4.测试

当第一次执行时,因为缓存中没有数据,会查询数据库。第二次再次执行时,因为缓存中已经有数据了,则直接从缓存中获取结果。

优雅的缓存开发,看这一篇文章就可以了「干货」

运行结果

Spring cache开发

缓存实现

Spring cache是对缓存的抽象,并不负责具体缓存的实现。所以开发第一步即是配置缓存管理器和具体的缓存实现

  • 缓存管理器使用缺省的org.springframework.cache.support.SimpleCacheManager即可,无需改变;

  • 缓存实现,在实现的应用中可能会用到多种缓存实现,如基于内存(map)、Redis的,不同的项目使用的缓存实现也可能不同,如下配置了一种名为userCache的内存缓存实现。

优雅的缓存开发,看这一篇文章就可以了「干货」

缓存配置

@Cacheable

在方法调用之前执行,即先查询缓存,如果缓存中没有数据再执行方法并将结果缓存起来。常用于查询类服务

优雅的缓存开发,看这一篇文章就可以了「干货」

cacheable

属性说明示例
value缓存的名称,在 spring 配置文件中定义,必须指定至少一个,如果是多个,则将结果写入多个缓存@Cacheable(value={”cache1”,”cache2”}
key缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合@CacheCacheable(value="userCache", key="#user.id" )
condition满足缓存条件的数据才会放入缓存,condition在调用方法之前和之后都会判断@CacheCacheable(value="userCache",condition="#user.id.length()>4" )
unless满足条件不更新缓存,不像condition,该表达只在方法执行之后判断,此时可以拿到返回值result进行判断了@CacheCacheable(value="userCache",condition="#user.id.length()>4" )//满足条件不更新缓存

@CachePut

在方法调用之后执行,即先执行方法,再缓存结果。常用于更新类服务。

优雅的缓存开发,看这一篇文章就可以了「干货」

cacheput

注:缓存key是user对象的id, 缓存结果是方法的返回值,无论是CachePut还是Cacheable缓存的结果都是方法的返回值

属性说明示例
value缓存的名称,在 spring 配置文件中定义,必须指定至少一个,如果是多个,则将结果写入多个缓存@Cacheable(value={”cache1”,”cache2”}
key缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合@CacheCacheable(value="userCache", key="#user.id" )
condition满足缓存条件的数据才会放入缓存,condition在调用方法之前和之后都会判断@CacheCacheable(value="userCache",condition="#user.id.length()>4" )
unless满足条件不更新缓存,不像condition,该表达只在方法执行之后判断,此时可以拿到返回值result进行判断了@CacheCacheable(value="userCache",condition="#user.id.length()>4" )//满足条件不更新缓存

@CacheEvict

清理缓存。根据根据key清理缓存;清理所有缓存;根据条件清理缓存

优雅的缓存开发,看这一篇文章就可以了「干货」

cacheevict

属性说明示例
value同CachePut 
key同CachePut 
condition同CachePut 
allEntries是否清理所有缓存数据@CacheEvict(value="userCache",allEntries=true)
beforeInvocation是否在方法执行之前清理@CacheEvict(value="userCache",beforeInvocation=false)

三种方式的对比

  • @Cacheable 根据请求参数缓存结果(方法返回值),在方法执行前调用;

  • @CachePut 根据请求参数缓存结果(方法返回值),在方法执行后调用;

  • @CachEvict 清理缓存,可以根据请求参数清理,也可以全部清理;可在方法执行前或后清理缓存;

注意

基于动态代理的实现,所以在对象内部调用时缓存不生效

优雅的缓存开发,看这一篇文章就可以了「干货」

内部调用不生效

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值