本篇文章涉及的源码下载地址:https://gitee.com/daifyutils/springboot-samples
下一篇:Spring Cache使用Redis缓存、自定义注解参数值
抽象缓存
Spring Cache是Spring提供的一套缓存的抽象实现,通过配置Cache的数据源可以轻松的将缓存的存放地址进行修改。
引入依赖
Spring默认提供了对Spring Cache的支持,所以如果使用的是spring-boot-starter-parent则无需引入
参数配置
启动注释
要开启Spring Cache需要在启动类中添加注释
@EnableCaching
@SpringBootApplication
@EnableCaching
public class CacheApplication {
public static void main(String[] args) {
SpringApplication.run(CacheApplication.class,args);
}
}
创建缓存配置
除了启动类中添加注释,假如需要使用其他数据库作为缓存数据源需要实现CacheManager接口,但是对于测试时使用内存作为缓存管理器,则默认已经会实现,所以不需要实现任何接口
使用cache进行数据操作
/**
* @author daify
* @date 2020-10-13
*/
@Repository
public class CacheDao {
/**
* 获取数据
* @param key
* @return
*/
@Cacheable(value = "string" ,key = "#key")
public String find(String key) {
return "";
}
/**
* 设置数据
* @param data
* @param key
* @return
*/
@CachePut(value = "string" ,key = "#key")
public String putStr(String data,String key) {
return "";
}
/**
* 清空缓存
* @param key
*/
@CacheEvict(value = "string" ,key = "#key")
public void clear(String key) {
}
}
测试用例
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = CacheApplication.class)
@EnableAutoConfiguration
@Slf4j
public class CacheDaoTest extends CacheApplication {
@Autowired
private CacheDao cacheDao;
private static String KEY ="test";
/**
* 获取数据
* @return
*/
@Test
public void find() {
cacheDao.clear(KEY);
String cacheData = cacheDao.find(KEY);
Assert.assertTrue(StringUtils.isEmpty(cacheData));
cacheDao.putStr("123",KEY);
String cacheData2 = cacheDao.find(KEY);
Assert.assertTrue("123".equals(cacheData2));
log.info("测试执行完毕");
}
}
输出结果
2020-10-17 12:22:09.059 INFO 28620 --- [ main] dai.samples.cache.dao.CacheDaoTest : Started CacheDaoTest in 1.865 seconds (JVM running for 2.679)
2020-10-17 12:22:09.175 INFO 28620 --- [ main] dai.samples.cache.dao.CacheDaoTest : 测试执行完毕
2020-10-17 12:22:09.179 INFO 28620 --- [ Thread-4] o.s.w.c.s.GenericWebApplicationContext : Closing org.springframework.web.context.support.GenericWebApplicationContext@640f11a1: startup date [Sat Oct 17 12:22:07 CST 2020]; root of context hierarchy
使用cache注意事项
cache的原理
其实就是将需要缓存的方法进行代理,在执行具体逻辑之前会通过代理进行一些操作。
- 在同一个类中调用被缓存注解的方法会导致缓存失效
Spring cache 本质是动态生成proxy代理来对调用方法进行切面。但是当对象方法使用内部调用而不是外部引用的时候则会导致proxy失效。
- 静态方法无法使用cache注解
同样因为静态方法直接通过类名.方法名进行调用,绕过了spring proxy的代理类,无法使用切面拦截。
注释介绍
注解 | 作用 |
---|---|
CacheAnnotationParser | 指定缓存定义解析 |
CacheConfig | 用来为当前类的缓存操作指定独特的配置 |
Cacheable | 尝试获取缓存如果缓存不存在则不使用缓存进行查询并缓存返回值 |
CacheEvict | 清空缓存 |
CachePut | 更新缓存 |
Caching | 集合了Cacheable、CacheEvict、CachePut 可是通过配置实现三者效果 |
CachingConfigurer | 指定缓存配置 |
EnableCaching | 开启缓存 |
CacheAnnotationParser
参数
参数 | 作用 | 参考值 |
---|---|---|
parseCacheAnnotations | 提供类缓存定义的解析 | |
parseCacheAnnotations | 提供方法缓存定义的解析 |
CacheConfig
此注解是一个类级注释,用来为当前类的缓存操作指定独特的配置
参数
参数 | 作用 | 参考值 |
---|---|---|
cacheNames | 设置此配置的缓存名称 | |
keyGenerator | 键生成器,定义了该方法之后可以根据业务自定义key | 此参数为注入的bean名称,对应Bean需要实现org.springframework.cache.interceptor.KeyGenerator |
cacheManager | 自定义cacheManager 缓存管理器 | 注入的bean名称,实现org.springframework.cache.CacheManager接口 |
cacheResolver | 自定义的缓存解析器 | 注入的bean名称,实现org.springframework.cache.interceptor.CacheResolver接口 |
Cacheable
参数
参数 | 作用 | 参考值 |
---|---|---|
value | 缓存的名称,至少指定一个 | |
cacheNames | 指定缓存名称 | |
key | 缓存的key,可以为空也可以使用SpEL表达式,默认按照方法的所有参数进行组合 | |
keyGenerator | 键生成器,定义了该方法之后可以根据业务自定义key | 此参数为注入的bean名称,对应Bean需要实现org.springframework.cache.interceptor.KeyGenerator |
cacheManager | 自定义cacheManager 缓存管理器 | 注入的bean名称,实现org.springframework.cache.CacheManager接口 |
cacheResolver | 自定义的缓存解析器 | 注入的bean名称,实现org.springframework.cache.interceptor.CacheResolver接口 |
condition | 执行缓存的条件,使用SpEL表达式需要返回true或者false | #age>2 |
unless | 使用SpEL表达式,标识无需缓存的条件 | |
sync | 设置缓存的操作为同步进行 |
CacheEvict
参数
参数 | 作用 | 参考值 |
---|---|---|
value | 缓存的名称,至少指定一个 | |
cacheNames | 指定缓存名称 | |
key | 缓存的key,可以为空也可以使用SpEL表达式,默认按照方法的所有参数进行组合 | |
keyGenerator | 键生成器,定义了该方法之后可以根据业务自定义key | 此参数为注入的bean名称,对应Bean需要实现org.springframework.cache.interceptor.KeyGenerator |
cacheManager | 自定义cacheManager 缓存管理器 | 注入的bean名称,实现org.springframework.cache.CacheManager接口 |
cacheResolver | 自定义的缓存解析器 | 注入的bean名称,实现org.springframework.cache.interceptor.CacheResolver接口 |
condition | 执行缓存的条件,使用SpEL表达式需要返回true或者false | #age>2 |
allEntries | 是否清空此value缓存下所有key缓存,而不是注解中对应的缓存 | false |
beforeInvocation | 在执行方法之前就清空缓存 | false |
CachePut
参数
参数 | 作用 | 参考值 |
---|---|---|
value | 缓存的名称,至少指定一个 | |
cacheNames | 指定缓存名称 | |
key | 缓存的key,可以为空也可以使用SpEL表达式,默认按照方法的所有参数进行组合 | |
keyGenerator | 键生成器,定义了该方法之后可以根据业务自定义key | 此参数为注入的bean名称,对应Bean需要实现org.springframework.cache.interceptor.KeyGenerator |
cacheManager | 自定义cacheManager 缓存管理器 | 注入的bean名称,实现org.springframework.cache.CacheManager接口 |
cacheResolver | 自定义的缓存解析器 | 注入的bean名称,实现org.springframework.cache.interceptor.CacheResolver接口 |
condition | 执行缓存的条件,使用SpEL表达式需要返回true或者false | #age>2 |
unless | 使用SpEL表达式,标识无需缓存的条件 |
Caching
此注解为某一方法提供了多个操作
参数
参数 | 作用 | 参考值 |
---|---|---|
cacheable | 查询缓存(设置)缓存的注解 | |
put | 设置缓存的注解 | |
evict | 清空缓存的注解 |
下面操作可以提供id->user 和 name->user的缓存
@Caching(
put = {
@CachePut(value = "animalById", key = "#user.id"),
@CachePut(value = "animalById", key = "#user.name")
}
)
public User saveUser(final User user){
return user;
}
CachingConfigurer
参数
参数 | 作用 | 参考值 |
---|---|---|
cacheManager | 自定义cacheManager 缓存管理器 | 注入的bean名称,实现org.springframework.cache.CacheManager接口 |
cacheResolver | 自定义的缓存解析器 | 注入的bean名称,实现org.springframework.cache.interceptor.CacheResolver接口 |
keyGenerator | 键生成器,定义了该方法之后可以根据业务自定义key | 此参数为注入的bean名称,对应Bean需要实现org.springframework.cache.interceptor.KeyGenerator |
errorHandler | 异常处理操作 | 需要实现org.springframework.cache.interceptor.CacheErrorHandler |
EnableCaching
参数
参数 | 作用 | 参考值 |
---|---|---|
proxyTargetClass | 设置代理方式,false为JDK动态代理;true为基于cglib动态代理 | 默认为false |
mode | 切面方式,false为JDK动态代理;true为基于aspectj动态代理 | 默认为false |
order | 一个切点存在多个操作的时候的执行顺序,默认为最低优先级 | 数字越大优先级越低 |
SpEL介绍
描述 | 语句 |
---|---|
被调用方法名 | root.method.name |
被调用对象 | root.target |
被调用的类 | root.targetClass |
方法参数列表 | root.args[0] |
方法缓存列表 | root.caches[0].name |
被调用的参数的方法 | {参数对象}.{属性字段} |
方法执行后的返回值 | result |
示例
@CachePut(value = "string" ,
key = "#root.method.name + '---' + #root.target + '---' + " +
"#root.targetClass + '---' + #root.args[0] + '---' + #root.caches[0].name")
public String putStr2(String data,String key) {
return data;
}
下面内容Key会输出
putStr2---dai.samples.cache.dao.CacheDao@91f565d---class dai.samples.cache.dao.CacheDao---123---string123
个人水平有限,上面的内容可能存在没有描述清楚或者错误的地方,假如开发同学发现了,请及时告知,我会第一时间修改相关内容。假如我的这篇内容对你有任何帮助的话,麻烦给我点一个赞。你的点赞就是我前进的动力。