阅读spring cache文档,学习有关@Cacheable注解的相关使用
This commit is contained in:
@@ -7,3 +7,71 @@ Cache针对java方法进行缓存,当想要获取的信息在cache中可获取
|
|||||||
|
|
||||||
在spring中,cache abstraction的caching service是一个抽象接口而不是实现,需要使用实际的storage来对缓存数据进行存储。
|
在spring中,cache abstraction的caching service是一个抽象接口而不是实现,需要使用实际的storage来对缓存数据进行存储。
|
||||||
spring提供了cache abstraction的一系列实现,例如基于JDK java.util.concurrent.ConcurrentMap的缓存、Caffeine等
|
spring提供了cache abstraction的一系列实现,例如基于JDK java.util.concurrent.ConcurrentMap的缓存、Caffeine等
|
||||||
|
### 使用cache abstraction的要点
|
||||||
|
1. cache声明:表示需要使用cache的方法,并且指明cache策略
|
||||||
|
2. cache配置:将cache数据存储到何处,并从何处读取
|
||||||
|
## 缓存可能会存在的问题
|
||||||
|
在使用缓存时,可能会面临如下问题:
|
||||||
|
- 多进程环境问题:在多进程环境之下(如微服务在多个server上部署服务)使用缓存时,如果想要缓存在多个节点之间进行共享,需要解决缓存的共享问题
|
||||||
|
- 并发安全问题:使用缓存实际上是get-if-not-found-then-proceed-and-put-eventually的过程,在这个过程中并不会加锁,故而会存在并发安全的问题。如果多个线程都同时发生缓存miss的问题,那么同一个方法会背调用多次并且返回结果会背load多次;淘汰时同样会面临竞争问题,并发环境下如果有一个线程想要淘汰过时key,但另一个线程load了最新的value并更新ttl,那么更新后的key仍有可能被淘汰。
|
||||||
|
## 基于声明式注解的缓存
|
||||||
|
### @Cacheable
|
||||||
|
可以使用@Cacheable将方法声明为可缓存的,在将方法声明为@Cacheable之后,方法的返回结果会被存储到缓存中。在一系列具有相同参数的调用中,cache中缓存的值将会被返回,而无需真的调用方法。
|
||||||
|
在@Cacheable注解最简单的使用场景中,需要指明和方法关联的cache name:
|
||||||
|
```java
|
||||||
|
// 如下示例中,findBook方法将会和名为books的缓存相关联
|
||||||
|
@Cacheable("books")
|
||||||
|
public Book findBook(ISBN isbn) {...}
|
||||||
|
```
|
||||||
|
> 虽然大多数场景下@Cacheable注解只会指定一个cache name,但是**也能为@Cacheable注解指定多个cache**。当任一缓存命中时,关联的值都会被返回。
|
||||||
|
> 即使其他缓存没有命中,该命中值也会添加到所有其他缓存中(方法并未被实际调用)
|
||||||
|
|
||||||
|
如下实例为@Cacheable方法指定了多个cache:
|
||||||
|
```java
|
||||||
|
@Cacheable({"books", "isbns"})
|
||||||
|
public Book findBook(ISBN isbn) {...}
|
||||||
|
```
|
||||||
|
#### 默认的key生成
|
||||||
|
缓存实际上是通过key-value的形式存储的,每次对cached method的调用都需要被转化为一个合适的key。cache abstraction通过使用SimpleKeyGenerator来生成key,该generator生成算法如下:
|
||||||
|
- 如果没有给定参数,那么返回SimpleKey.EMPTY
|
||||||
|
- 如果给定了一个参数,返回该参数
|
||||||
|
- 如果指定了多于一个参数,那么返回一个包含所有参数的SimpleKey
|
||||||
|
|
||||||
|
该算法在大多数用例之下运行正常,只要参数含有正常key并且具有有效的hashCode和equals实现。
|
||||||
|
#### 自定义key生成的方式
|
||||||
|
当在cached method的参数中,仅仅只有一部分参数应参与key的生成,另一部分不参与时,可以通过指定@Cacheable注解的key属性来指定如何生成key。可以在key属性中使用spel表达式:
|
||||||
|
```java
|
||||||
|
@Cacheable(cacheNames="books", key="#isbn")
|
||||||
|
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)
|
||||||
|
|
||||||
|
@Cacheable(cacheNames="books", key="#isbn.rawNumber")
|
||||||
|
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)
|
||||||
|
|
||||||
|
@Cacheable(cacheNames="books", key="T(someType).hash(#isbn)")
|
||||||
|
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)
|
||||||
|
```
|
||||||
|
#### sync caching
|
||||||
|
在使用@Cacheable时,默认情况下cached method并没有使用任何lock。可以使用@Cacheable注解的sync属性来指示底层的缓存provider在value被计算时锁定指定条目(防止在竞争场景下同一个值被重复计算)。
|
||||||
|
```java
|
||||||
|
@Cacheable(cacheNames="foos", sync=true)
|
||||||
|
public Foo executeExpensiveOperation(String id) {...}
|
||||||
|
```
|
||||||
|
#### condition cache
|
||||||
|
可以通过指定@Cacheable注解的condition属性来指定该方法调用是否被缓存。condition可以为其指定一个spel表达式,如果表达式结果为true,该方法调用被缓存,否则不被缓存。
|
||||||
|
```java
|
||||||
|
// 仅当name参数的长度小于32时被缓存
|
||||||
|
@Cacheable(cacheNames="book", condition="#name.length() < 32")
|
||||||
|
public Book findBook(String name)
|
||||||
|
```
|
||||||
|
还可以使用unless属性来阻止方法被缓存,unless同样可以为其指定一个spel表达式。unless在方法调用完成之后被计算,可以通过#result来根据方法返回结果决定是否缓存该方法:
|
||||||
|
```java
|
||||||
|
@Cacheable(cacheNames="book", condition="#name.length() < 32", unless="#result.hardback")
|
||||||
|
public Book findBook(String name)
|
||||||
|
```
|
||||||
|
#### @Cacheable和Optional
|
||||||
|
cache abstraction支持Optional类型,如果Optional对象的value不为空,那么value将会被存储到cache中,如果Optional为空,那么null将会被存储到管来奶的cache中。
|
||||||
|
在@Cacheable的spel表达式中,#result获取的是Optional对象的value而不是wrapper。
|
||||||
|
```java
|
||||||
|
@Cacheable(cacheNames="book", condition="#name.length() < 32", unless="#result?.hardback")
|
||||||
|
public Optional<Book> findBook(String name)
|
||||||
|
```
|
||||||
|
|||||||
Reference in New Issue
Block a user