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 | 缓存接口,定义缓存操作。实现有:RedisCache、EhCacheCache、ConcurrentMapCache等 |
CacheManager | 缓存管理器,管理各种缓存(cache)组件 |
@Cacheable | 主要针对方法配置,能够根据方法的请求参数对其进行缓存 |
@CacheEvict | 清空缓存 |
@CachePut | 保证方法被调用,又希望结果被缓存。 与@Cacheable区别在于是否每次都调用方法,常用于更新 |
@EnableCaching | 开启基于注解的缓存 |
keyGenerator | 缓存数据时key生成策略 |
serialize | 缓存数据时value序列化策略 |
@CacheConfig | 统一配置本类的缓存注解的属性 |
@Cacheable/@CachePut/@CacheEvict 主要的参数
名称 | 解释 |
---|---|
value | 缓存的名称,在 spring 配置文件中定义,必须指定至少一个 例如: @Cacheable(value=”mycache”) 或者 @Cacheable(value={”cache1”,”cache2”} |
key | 缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写, 如果不指定,则缺省按照方法的所有参数进行组合 例如: @Cacheable(value=”testcache”,key=”#id”) |
condition | 缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false, 只有为 true 才进行缓存/清除缓存 例如:@Cacheable(value=”testcache”,condition=”#userName.length()>2”) |
unless | 否定缓存。当条件结果为TRUE时,就不会缓存。 @Cacheable(value=”testcache”,unless=”#userName.length()>2”) |
allEntries (@CacheEvict ) | 是否清空所有缓存内容,缺省为 false,如果指定为 true, 则方法调用后将立即清空所有缓存 例如: @CachEvict(value=”testcache”,allEntries=true) |
beforeInvocation (@CacheEvict) | 是否在方法执行前就清空,缺省为 false,如果指定为 true, 则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法 执行抛出异常,则不会清空缓存 例如: @CachEvict(value=”testcache”,beforeInvocation=true) |
SpEL上下文数据
Spring Cache提供了一些供我们使用的SpEL上下文数据,下表直接摘自Spring官方文档:
名称 | 位置 | 描述 | 示例 |
---|---|---|---|
methodName | root对象 | 当前被调用的方法名 | #root.methodname |
method | root对象 | 当前被调用的方法 | #root.method.name |
target | root对象 | 当前被调用的目标对象实例 | #root.target |
targetClass | root对象 | 当前被调用的目标对象的类 | #root.targetClass |
args | root对象 | 当前被调用的方法的参数列表 | #root.args[0] |
caches | root对象 | 当前方法调用使用的缓存列表 | #root.caches[0].name |
Argument Name | 执行上下文 | 当前被调用的方法的参数,如findArtisan(Artisan artisan),可以通过#artsian.id获得参数 | #artsian.id |
result | 执行上下文 | 方法执行后的返回值(仅当方法执行后的判断有效,如 unless cacheEvict的beforeInvocation=false) | #result |
注意:
1.当我们要使用root对象的属性作为key时我们也可以将“#root”省略,因为Spring默认使用的就是root对象的属性。 如
@Cacheable(key = "targetClass + methodName +#p0")
2.使用方法参数时我们可以直接使用“#参数名”或者“#p参数index”。 如:
@Cacheable(value="users", key="#id")
@Cacheable(value="users", key="#p0")
SpEL提供了多种运算符
类型 | 运算符 | ||
---|---|---|---|
关系 | <,>,<=,>=,==,!=,lt,gt,le,ge,eq,ne | ||
算术 | +,- ,* ,/,%,^ | ||
逻辑 | &&,\ | \ | ,!,and,or,not,between,instanceof |
条件 | ?: (ternary),?: (elvis) | ||
正则表达式 | matches | ||
其他类型 | ?.,?[…],![…],^[…],$[…] |
以上的知识点适合你遗忘的时候来查阅,下面正式进入学习!
实战
创建工程,添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
配置Redis及缓存名称
spring.redis.host=localhost
spring.redis.password=123456
spring.redis.database=0
spring.cache.cache-names=cacheName
启动类注解@EnableCaching
@SpringBootApplication
@EnableCaching
public class CacheredisApplication {
public static void main(String[] args) {
SpringApplication.run(CacheredisApplication.class, args);
}
}
添加实体
public class User implements Serializable {
public String name;
public int id;
public User(int id, String name) {
this.name = name;
this.id = id;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
注意
实体必须实现Serializable
接口
添加service
public interface UserService {
/**
* 根据Id查找用户
* @param id 用户Id
* @return 用户
*/
public User findUserById(int id);
/**
* 根据Id更新用户信息
* @param user 用户
* @return 用户
*/
public User updateUserById(User user);
/**
* 根据Id删除用户
* @param id 用户Id
*/
public void deleteUserById(int id);
}
添加serviceimpl
@Service
@CacheConfig(cacheNames = "cacheName")
public class UserServiceImpl implements UserService {
/**
* 根据Id查找用户
*
* @param id 用户Id
* @return 用户
*/
@Override
@Cacheable(key = "#id")
public User findUserById(int id) {
User user = new User(id,"张三");
return user;
}
/**
* 根据Id更新用户信息
*
* @param user 用户
* @return 用户
*/
@Override
@CachePut(key = "#user.id")
public User updateUserById(User user) {
return user;
}
/**
* 根据Id删除用户
*
* @param id 用户Id
*/
@Override
@CacheEvict(key = "#id")
public void deleteUserById(int id) {
}
}
@CacheConfig(cacheNames = "cacheName")
注解在类上使用,用来描述该类中所有方法使用的缓存名称,当然也可以不使用该注解,直接在具体的缓存注解上配置名称。
@Cacheable(key = "#id")
这个注解一般加在查询方法上,表示将一个方法的返回值缓存起来,默认情况下,缓存的key就是方法的参数,缓存的value就是方法的返回值。
@CachePut(key = "#user.id")
这个注解一般加在更新方法上,当数据库中的数据更新后,缓存中的数据也要跟着更新,使用该注解,可以将方法的返回值自动更新到已经存在的key上。
@CacheEvict(key = "#id")
这个注解一般加在删除方法上,当数据库中的数据删除后,相关的缓存数据也要自动清除,该注解在使用的时候也可以配置按照某种条件删除(condition属性)或者或者配置清除所有缓存(allEntries属性)。
增加controller
@RestController
public class UserController {
private final UserService userService;
public UserController(UserService userService){
this.userService=userService;
}
/**
* 根据Id查找用户
* @return 用户
*/
@RequestMapping("findUserById")
public User findUserById(){
return userService.findUserById(1);
}
/**
* 根据Id更新用户信息
* @return 用户
*/
@RequestMapping("updateUserById")
public User updateUserById(){
User user = userService.findUserById(1);
user.setName("李四");
return userService.updateUserById(user);
}
/**
* 根据Id删除用户
*/
@RequestMapping("deleteUserById")
public void deleteUserById(){
userService.deleteUserById(1);
}
}
这个是我根据插件改造的,所以不会变慢了
感谢分享