Spring Cache

Spring 3.1 引入了激动人心的基于注解(annotation)的缓存(cache)技术,它本质上不是一个具体的缓存实现方案(例如 EHCache 或者 OSCache),而是一个对缓存使用的抽象,通过在既有代码中添加少量它定义的各种 annotation,即能够达到缓存方法的返回对象的效果。Spring 的缓存技术还具备相当的灵活性,不仅能够使用 SpEL(Spring Expression Language)来定义缓存的 key 和各种 condition,还提供开箱即用的缓存临时存储方案,也支持和主流的专业缓存例如 EHCache、Redis 集成。


基本原理

和 spring 的事务管理类似,spring cache 的关键原理就是 spring AOP,通过 spring AOP,其实现了在方法调用前、调用后获取方法的入参和返回值,进而实现了缓存的逻辑。

  1. 原始方法调用

    如下图所示,当客户端“Calling code”调用一个普通类 Plain Object 的 foo() 方法的时候,是直接作用在 pojo 类自身对象上的,客户端拥有的是被调用者的直接的引用。
    这里写图片描述

  2. 动态代理调用

    Spring cache 利用了 Spring AOP 的动态代理技术,即当客户端尝试调用 pojo 的 foo()方法的时候,给他的不是 pojo 自身的引用,而是一个动态生成的代理类。这个时候,实际客户端拥有的是一个代理的引用,那么在调用 foo() 方法的时候,会首先调用 proxy 的 foo() 方法,这个时候 proxy 可以整体控制实际的 pojo.foo() 方法的入参和返回值,比如缓存结果,比如直接略过执行实际的 foo() 方法等,都是可以轻松做到的。
    这里写图片描述

SpringBoot pom依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

使用缓存-@Cacheable

getAccountByName 方法上有一个@Cacheable(value=”accountCache”)注解,这个注解的意思是,当调用这个方法的时候,会从一个名叫 accountCache 的缓存中查询,如果没有,则执行实际的方法(即查询数据库),并将执行的结果存入缓存中,否则返回缓存中的对象。这里的缓存中的 key 就是参数 userName,value 就是 Account 对象。

@Cacheable(value = "accountCache")// 使用了一个名叫 accountCache 的缓存
public Account getAccountByName(String userName) {
    // 方法内部实现不考虑缓存逻辑,直接实现业务
    return getFromDB(userName);
}

清空缓存-@CacheEvict

当账号数据发生变更,那么必须要清空某个缓存,另外还需要定期的清空所有缓存,以保证缓存数据的可靠性。spring cache 通过 @CacheEvict 注解来标记要清空缓存的方法,当这个方法被调用后,即会清空缓存。其中的 Key 是指定了缓存的 key ,# 号标示是一个 SpEL 表达式,此表达式可以遍历方法的参数对象,具体语法可以参考 Spring 的相关文档手册。

@CacheEvict(value = "accountCache", key = "#account.getName()")// 清空某个缓存
public void updateAccount(Account account) {
    updateDB(account);
}

@CacheEvict(value = "accountCache", allEntries = true)// 清空所有缓存
public void reload() {
}

条件操作-condition

如果要求只有账号名称的长度小于等于 4 的情况下,才做缓存,大于 4 的不使用缓存,那怎么实现呢?@Cacheable 提供了一个基于 SpEL 表达式的 condition 属性,可以用该属性定义条件表达式:condition=”#userName.length() <=4”,这里使用了 SpEL 表达式访问了参数 userName 对象的 length() 方法,条件表达式返回一个布尔值,true/false,当条件为 true,则进行缓存操作,否则直接调用方法执行的返回结果。

@Cacheable(value = "accountCache", condition = "#userName.length() <= 4")
public Account getAccountByName(String userName) {
    return getFromDB(userName);
}

多参数key组合-SpEL表达式

可以可以利用 SpEL 表达式对缓存 key 进行设计,如使用 concat 组合userName 和 password作为缓存的key

@Cacheable(value = "accountCache", key = "#userName.concat(#password)")
public Account getAccount(String userName, String password, boolean sendLog) {
    return getFromDB(userName, password);
}

强方法调用-@CachePut

使用@Cacheable 注解时,当重复使用相同参数调用方法的时候,方法本身不会被调用执行,而是直接从缓存中查找并返回结果。有些情况下我们希望方法一定会被调用,因为其除了返回一个结果,还做了其他事情,例如记录日志,调用接口等,这个时候,我们可以用 @CachePut 注解,这个注解可以确保方法被执行,同时方法的返回值也被记录到缓存中。

@Cacheable(value="accountCache")
public Account getAccountByName(String userName) {
    return getFromDB(userName);
}

扩展性-与Redis整合

详见:http://blog.csdn.net/ifwinds/article/details/78937511

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值