JSR107规范简述
- Java Caching定义了5个核心接口,分别是CachingProvider, CacheManager, Cache, Entry 和 Expiry
-
- Caching Provider定义了创建、配置、获取、管理和控制多个CacheManager。一个应用可以在运行期访问多个CachingProvider。
- CacheManager定义了创建、配置、获取、管理和控制多个唯一命名的Cache,这些Cache存在于CacheManager的上下文中。一个CacheManager仅被一个CachingProvider所拥有。
- Cache是一个类似Map的数据结构并临时存储以Key为索引的值。一个Cache仅被一个CacheManager所拥有。
- Entry是一个存储在Cache中的key-value对。
- Expiry 每一个存储在Cache中的条目有一个定义的有效期。一旦超过这个时间,条目为过期的状态。一旦过期,条目将不可访问、更新和删除。缓存有效期可以通过ExpiryPolicy设置
Spring缓存抽象
- Spring从3.1开始定义了org.springframework.cache.Cache
和org.springframework.cache.CacheManager接口来统一不同的缓存技术、
并支持使用JCache(JSR-107)注解简化我们开发。 - Cache接口为缓存的组件规范定义,包含缓存的各种操作集合;
- Cache接口下Spring提供了各种xxxCache的实现;如RedisCache,EhCacheCache , ConcurrentMapCache等;
- 每次调用需要缓存功能的方法时,Spring会检查检查指定参数的指定的目标方法是否已经被调用过;如果有就直接从缓存中获取方法调用后的结果,如果没有就调用方法并缓存结果后返回给用户。下次调用直接从缓存中获取。
- 使用Spring缓存抽象时我们需要关注点
-
- ①确定方法需要被缓存以及他们的缓存策略
- ②从缓存中读取之前缓存存储的数据
Cache相关重要概念&缓存注解
注解 | 描述 |
---|---|
Cache | 缓存接口,定义缓存操作。实现有:RedisCache、EhCacheCache、ConcurrentMapCache等 |
CacheManager | 缓存管理器,管理各种缓存(Cache)组件 |
@Cacheable | 主要针对方法配置,能够根据方法的请求参数对其结果进行缓存 |
@CacheEvict | 清空缓存 |
@CachePut | 保证方法被调用,又希望结果被缓存。 |
@EnableCaching | 开启基于注解的缓存 |
keyGenerator | 缓存数据时key生成策略 |
serialize | 缓存数据时value序列化策略 |
@Cacheable/@CachePut/@CacheEvict 主要的参数
参数 | 描述 | 例子 |
---|---|---|
value | 缓存的名称,在 spring 配置文件中定义,必须指定至少一个 | @Cacheable(value={”cache1”,”cache2”} |
key | 缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合 | @Cacheable(value=”testcache”,key=”#userName”) |
condition | 缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存/清除缓存,在调用方法之前之后都能判断 | @Cacheable(value=”testcache”,condition=”#userName.length()>2”) |
allEntries(@CacheEvict ) | 是否清空所有缓存内容,缺省为 false,如果指定为 true,则方法调用后将立即清空所有缓存 | @CachEvict(value=”testcache”,allEntries=true) |
beforeInvocation(@CacheEvict) | 是否在方法执行前就清空,缺省为 false,如果指定为 true,则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法执行抛出异常,则不会清空缓存 | @CachEvict(value=”testcache”,beforeInvocation=true) |
unless(@CachePut/@Cacheable) | 用于否决缓存的,不像condition,该表达式只在方法执行之后判断,此时可以拿到返回值result进行判断。条件为true不会缓存,fasle才缓存 | @Cacheable(value=”testcache”,unless=”#result == null”) |
Spring Cache代码相关
- pom.xml
<dependencies>
<!-- Spring Cache缓存模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
-
主启动类标注@EnableCaching
-
User.java
package com.hf.cache.entity;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.experimental.Accessors;
import java.io.Serializable;
/**
* @Copyright (C), 2016-2019 hf
* @FileName: User
* @Author: hf
* @Date: 2019/9/29 0:53
* @Description: User 实体
*/
@Getter
@Setter
@Accessors(chain = true)
@AllArgsConstructor
@ToString
public class User implements Serializable {
//id
private String id;
//用户名
private String name;
//手机号
private String phone;
//邮箱
private String email;
//状态
private boolean status;
}
- UserService.java
package com.hf.cache.service;
import com.hf.cache.entity.User;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* @Copyright (C), 2016-2019 hf
* @FileName: UserService
* @Author: hf
* @Date: 2019/9/29 0:57
* @Description: 用户服务实现层
*/
@Service
public class UserService {
static Map<String, User> map = new HashMap<>(12);
static {
map.put("liuyi", new User(UUID.randomUUID().toString().substring(0,7), "liuyi", "155********", "liuyi@163.com", true));
map.put("chenger", new User(UUID.randomUUID().toString().substring(0,7), "chenger", "166********", "chenger@163.com", true));
map.put("zhangsan", new User(UUID.randomUUID().toString().substring(0,7), "zhangsan", "165********", "zhangsan@163.com", true));
map.put("lisi", new User(UUID.randomUUID().toString().substring(0,7), "lisi", "178********", "lisi@163.com", true));
map.put("wangwu", new User(UUID.randomUUID().toString().substring(0,7), "wangwu", "182********", "wangwu@163.com", true));
}
/**
* 功能描述:
* 查询用户实体并缓存
* 〈
* 相关参数说明:
* cacheNames/value:指定缓存组件的名字;将方法的返回结果放在哪个缓存中,是数组的方式,可以指定多个缓存;
*
* key:缓存数据使用的key;可以用它来指定。默认是使用方法参数的值 1-方法的返回值
* 编写SpEL; #i d;参数id的值 #a0 #p0 #root.args[0]
* getEmp[2]
*
* keyGenerator:key的生成器;可以自己指定key的生成器的组件id
* key/keyGenerator:二选一使用;
*
*
* cacheManager:指定缓存管理器;或者cacheResolver指定获取解析器
*
* condition:指定符合条件的情况下才缓存;
* ,condition = "#id>0"
* condition = "#a0>1":第一个参数的值》1的时候才进行缓存
*
* unless:否定缓存;当unless指定的条件为true,方法的返回值就不会被缓存;可以获取到结果进行判断
* unless = "#result == null"
* unless = "#a0==2":如果第一个参数的值是2,结果不缓存;
* sync:是否使用异步模式
*
* 〉
*
* @className: UserService
* @author: hf
* @version: 1.0.0
* @date: 2019/9/29 1:10
* @param: [key]
* @return: com.hf.cache.entity.User
*
*/
@Cacheable(value = {"user"},key = "#key",unless = "#result==null")
public User getUser(String key) {
System.out.println("查询key=【" + key + "】的用户");
return map.get(key);
}
/**
* 功能描述:
* 〈
* 更新用户信息
* @CachePut:既调用方法,又更新缓存数据;同步更新缓存
* 〉
*
* @className: UserService
* @author: hf
* @version: 1.0.0
* @date: 2019/9/29 1:15
* @param: [user]
* @return: com.hf.cache.entity.User
*
*/
@CachePut(value = {"user"},key = "#result.name")
public User updateUser(User user) {
map.put(user.getName(), user);
return user;
}
/**
* 功能描述:
* 〈
* 删除用户
* @CacheEvict:缓存清除
*
* key:指定要清除的数据
* allEntries = true:指定清除这个缓存中所有的数据
* beforeInvocation = false:缓存的清除是否在方法之前执行
* 默认代表缓存清除操作是在方法执行之后执行;如果出现异常缓存就不会清除
* beforeInvocation = true:
* 代表清除缓存操作是在方法运行之前执行,无论方法是否出现异常,缓存都清除
*
* 〉
*
* @className: UserService
* @author: hf
* @version: 1.0.0
* @date: 2019/9/29 1:20
* @param: [key]
* @return: void
*
*/
@CacheEvict(value = {"user"},beforeInvocation = true)
public void deleteUser(String key) {
map.remove(key);
}
/**
* 功能描述:
* 〈
* @Caching 定义复杂的缓存规则
* 〉
*
* @className: UserService
* @author: hf
* @version: 1.0.0
* @date: 2019/9/29 1:25
* @param: [key]
* @return: com.hf.cache.entity.User
*
*/
@Caching(
cacheable = {
@Cacheable(value = "user",key="#key+1")
},
put = {
@CachePut(value = "user",key = "#result.id")
}
)
public User getUserByKey(String key) {
return map.get(key);
}
}
- UserController.java
package com.hf.cache.controller;
import com.hf.cache.entity.User;
import com.hf.cache.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import java.util.UUID;
/**
* @Copyright (C), 2016-2019 hf
* @FileName: UserController
* @Author: hf
* @Date: 2019/9/29 1:32
* @Description:
*/
@RestController
public class UserController {
@Autowired
UserService userService;
@GetMapping("/get/{key}")
public User get(@PathVariable String key) {
return userService.getUser(key);
}
@GetMapping("/del/{key}")
public String del(@PathVariable String key) {
userService.deleteUser(key);
return "Success";
}
@GetMapping("/upd/{key}")
public User upd(@PathVariable String key) {
User user = new User(UUID.randomUUID().toString(), key, "120000", "12000@qq.com", true);
return userService.updateUser(user);
}
}