Spring Cache缓存


缓存介绍

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

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

Spring Cache位于spring-content中,如下图

Spring Cache涉及主要类

Spring定义了Cache和CacheManager两个基础接口类。

Cache

Cache接口提供了其他缓存技术实现的规范,包括缓存的各种操作,增加、删除、获取缓存等。Cache默认实现缓存如下,其中EhcacheRedisCache都为流行的Cache实现方法。

CacheManager

CacheManager是Spring提供的各种缓存技术抽象接口,通过它管理Spring框架内部默认实现的CacheManager,Spring框架内部默认实现的CacheManager如下

CacheResolver

CacheResolver解析器,用于根据实际情况来动态解析使用哪个Cache。

KeyGenerator

KeyGenerator当使用注解时,默认key的生成规则。

Spring Cache主要的注解

@Cacheable

用于读取缓存的方法上,先从缓存中读取数据,如果没有再调用具体方法获取数据,然后将数据添加到缓存中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Cacheable {
//cacheNames的别名
@AliasFor("cacheNames")
String[] value() default {};
//方法调用的结果存储时的cache名字
@AliasFor("value")
String[] cacheNames() default {};
//缓存的键值名称,支持SpEL
String key() default "";
//key的生成策略
String keyGenerator() default "";
//cache管理器,不指定使用默认
String cacheManager() default "";
//cache解析器,不指定使用默认
String cacheResolver() default "";
//满足何种条件才能被缓存,支持SpEL
String condition() default "";
//满足哪些结果不加入缓存
String unless() default "";
//是否同步读取缓存,更新缓存
boolean sync() default false;
}

例子:

1
2
3
4
5
@Cacheable(value = "user", key = "#id",condition = "#id.length()>0",unless = "#id==null")
public User findById(String id) {
return userDao.findById(id).orElseGet(User::new);
}

@CachePut

用于保存或者更新方法上,调用方法时将相应数据存入缓存中。

例子:

1
2
3
4
5
@CachePut(value = "user", key = "#user.id")
@Transactional
public User update(User user) {
return userDao.save(user);
}

@CacheEvict

用于删除方法上,删除对应缓存。

1
2
3
4
5
6
7
8
9
10
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface CacheEvict {
...
//是否删除所有实体对象
boolean allEntries() default false;
//是否在方法调用之前执行,默认在调用方法执行成功后删除缓存。
boolean beforeInvocation() default false;

例子:

1
2
3
4
@CacheEvict(value = "user")
public void delete() {
...
}

@Caching

组合使用Cache注解

1
2
3
4
5
6
7
8
9
10
11
12
13
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Caching {

Cacheable[] cacheable() default {};

CachePut[] put() default {};

CacheEvict[] evict() default {};

}

@CacheConfig

全局Cache配置,自定义cache时需在方法上指定此注解。

@EnableCaching

开启Spring Cache的默认配置,启动缓存需要在项目中添加此注解。

Spring Boot集成

redis

支持分布式缓存,默认使用Luttuce客户端,也可采用Jedis。

引入依赖

pom.xml

1
2
3
4
5
6
7
8
9
10
<!--缓存-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!--redis实现-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

配置文件

application.yml

单机模式配置

1
2
3
4
5
6
7
8
9
10
11
12
spring:
application:
name: coding-cache-redis
# redis配置
redis:
host: localhost
port: 6379
password: 1111
database: 0
# 启动缓存类型
cache:
type: redis

哨兵模式配置

1
2
3
4
5
6
7
8
9
10
11
12
spring:
application:
name: coding-cache-redis
redis:
sentinel:
master: mymaster
nodes: 192.168.81.10:26375,192.168.81.11:26376,192.168.81.12:26377
database: 3
password: 1111
# 启动缓存类型
cache:
type: redis

集群模式配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
spring:
application:
name: coding-cache-redis
redis:
database: 3
password: 1111
cluster:
#代表redis多个节点的ip与端口号,多个节点需要使用“,”隔开。
nodes: 192.168.81.10:26375,192.168.81.11:26376,192.168.81.12:26377
#最大重定向次数
max-redirects: 2
# 启动缓存类型
cache:
type: redis

启动缓存

在Application启动类中使用@EnableCaching注解启用缓存

1
2
3
4
5
6
7
8
9
@EnableCaching
@SpringBootApplication
public class CodingCacheRedisApplication {

public static void main(String[] args) {
SpringApplication.run(CodingCacheRedisApplication.class, args);
}

}

具体操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
@Service
@CacheConfig(cacheNames = "user")
public class UserService {
@Autowired
private UserDao userDao;

@Cacheable
@Transactional
public User save(User user) {
return userDao.save(user);
}

// 缓存更新
@CachePut(key = "#user.id")
@Transactional
public User update(User user) {
return userDao.save(user);
}

// 缓存保存
@Cacheable(key = "#id", condition = "#id.length()>0", unless = "#id==null")
public User findById(String id) {
return userDao.findById(id).orElseGet(User::new);
}

//缓存删除
@CacheEvict
@Transactional
public void delete(String id) {
userDao.deleteById(id);
}
}

Ehcache

EhCache 是一个纯 Java 的进程内缓存框架,具有快速、精干等特点,是 Hibernate 中默认的 CacheProvider 。

引入依赖

1
2
3
4
5
6
7
8
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>

配置文件

application.yml

1
2
3
4
5
6
7
8
9
10
11
12
spring:
application:
name: coding-cache-redis
# redis配置
redis:
host: localhost
port: 6379
password: 1111
database: 0
# 启动缓存类型
cache:
type: ehcache

在resources下添加ehcache.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?xml version="1.0" encoding="UTF-8"?>  
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ehcache.xsd">
<diskStore path="java.io.tmpdir"/>
<!--硬盘上缓存存储位置 -->
<!--user.home 用户home目录 -->
<!--user.dir 用户当前工作目录-->
<!--java.io.tmpdir默认临时目录-->
<defaultCache
eternal="false"
maxEntriesLocalHeap="2000"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="false" />
<!-- user 缓存 -->
<!-- name:缓存名 -->
<!-- maxElementsInMemory:最大缓存 key 数量 -->
<!-- timeToLiveSeconds:缓存过期时长,单位:秒 -->
<!-- memoryStoreEvictionPolicy:缓存淘汰策略 -->
<cache name="user"
maxElementsInMemory="1000"
timeToLiveSeconds="60"
memoryStoreEvictionPolicy="LRU"/>
</cache>

</ehcache>

启动缓存

在Application启动类中使用@EnableCaching注解启用缓存

1
2
3
4
5
6
7
8
9
@EnableCaching
@SpringBootApplication
public class CodingCacheRedisApplication {

public static void main(String[] args) {
SpringApplication.run(CodingCacheRedisApplication.class, args);
}

}

具体操作

同redis


文章作者: 苏叶新城
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 苏叶新城 !
  目录