简单的demo
- 在想要加缓存的方法上加@Cacheable注解,在类上加@EnableCaching注解或者直接加载启动类上
package com.jsong.wiki.blog;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.stereotype.Component;
@EnableCaching
@Component
public class CacheService {
@Cacheable("cache")
public String getName(){
System.out.println("cache");
return "cache";
}
}
当调用getName方法是,第一次调用没有缓存,会执行方法体,第二次调用的时候不会执行方法,直接在缓存中获取数据。
约束应用中可用的缓存
- application.yml
只要名字叫cache的缓存,
spring:
cache:
cache-names:
- cache
当访问其他不存在的缓存时,会报错,启动的时候不会报错
java.lang.IllegalArgumentException: Cannot find cache named 'jsong' for Builder[public java.lang.String com.jsong.wiki.blog.CacheService.getName()] caches=[jsong] | key='' | keyGenerator='' | cacheManager='' | cacheResolver='' | condition='' | unless='' | sync='false'
关闭缓存
关闭应用缓存
spring.cache.type=none
spring:
cache:
cache-names:
- jsong
type: none
几个重要的注解
@Cacheable
这个注解可以设置和获取缓存
public @interface Cacheable {
@AliasFor("cacheNames")
String[] value() default {};
@AliasFor("value")
String[] cacheNames() default {};
String key() default "";
String keyGenerator() default "";
String cacheManager() default "";
String cacheResolver() default "";
String condition() default "";
String unless() default "";
boolean sync() default false;
}
支持主要参数
- cacheNames,value:作用相同,都是指定缓存的名字,当同时定义cacheNames和value的时候,cacheNames的值要和value的值相同。
demo
@Cacheable(value = "cache1")
public String getName(){
return "cache1";
}
@Cacheable(value = "cache1")
public String getName2(){
return "cache2";
}
单元测试
在访问getName()时,没有检测到有缓存,执行方法,把值放入到缓存cache1 并返回,getName2()和getName()标注的缓存value都是cache1,所以当执行getName2()时,发现缓存中有数据,并不执行方法,直接从缓存中取数据,所以,没有返回cache2,而是返回cahe1。
@Test
public void testCache(){
System.out.println(cacheService.getName()); // cache1
System.out.println(cacheService.getName2()); // cache1
}
- key:当前缓存的key,可以和value搭配使用,确定缓存。支持SpEL表达式(如:“#参数名”或者“#p参数index”)。
属性 | 描述 | 示例(#root可以省略) |
---|---|---|
methodName | 当前方法名 | #root.methodName |
method | 当前方法 | #root.method.name |
target | 当前被调用的对象 | #root.target |
targetClass | 当前被调用的对象的class | #root.targetClass |
args | 当前方法参数组成的数组 | #root.args[0] |
caches | 当前被调用的方法使用的Cache | #root.caches[0].name |
demo1
@Cacheable(value = "cache1", key = "#root.method")
public String getName() {
return "cache1";
}
@Cacheable(value = "cache1", key = "#root.method")
public String getName2() {
return "cache2";
}
单元测试
输出结果 cache1,cache2。因为两个缓存调用方法不是同一个方法,所以返回结果不同
@Test
public void testCache(){
System.out.println(cacheService.getName()); // cache1
System.out.println(cacheService.getName2()); // cache2
}
demo2
@Cacheable(value = "cache1", key = "#root.target")
public String getName() {
return "cache1";
}
@Cacheable(value = "cache1", key = "#root.target")
public String getName2() {
return "cache2";
}
单元测试
输出结果返回cache1,cache1。因为两个方法调用的对象都是同一个对象。
@Test
public void testCache(){
System.out.println(cacheService.getName()); // cache1
System.out.println(cacheService.getName2()); // cache1
}
- condition :只有当条件满足时才会去检查缓存,支持SpEL表达式
demo
@Cacheable(value = "cache1", key = "#root.target")
public String getName() {
return "cache1";
}
@Cacheable(value = "cache1", key = "#root.target", condition = "#p0>#p1")
public String getName2(int i, int j) {
return "cache2";
}
单元测试
第一次调用getName2方法时,缓存中的数据位cache1,并且condition条件满足,所以输出缓存数据cache1。
第二次调用getName2方法时,condition条件不满足,所以执行方法,输出数据cache2。
@Test
public void testCache(){
System.out.println(cacheService.getName()); // cache1
System.out.println(cacheService.getName2(2,1)); // cache1
System.out.println(cacheService.getName2(2,3)); // cache2
}
@CachePut
这个注解主要是设置缓存,不能获取缓存
它的属性和@Cacheable差不多,这里就不再赘述了。
demo
@Cacheable(value = "cache1", key = "#root.target")
public String getName() {
return "cache1";
}
@Cacheable(value = "cache1", key = "#root.target", condition = "#p0>#p1")
public String getName2(int i, int j) {
return "cache2";
}
@CachePut(value = "cache1", key = "#root.target", condition = "#p0>#p1")
public String setCache1(int i, int j) {
return "put-cache1";
}
单元测试
@Test
public void testCache(){
// System.out.println(cacheService.getName2(2,1));
// System.out.println(cacheService.getName2(2,3));
cacheService.setCache1(2,1);
System.out.println(cacheService.getName()); // put-cache1
}
@CacheEvict
清除缓存
当方法执行完成后,清除缓存,如果方法执行过程中报错,则不清除缓存。
新属性beforeInvocation当值为true时,在方法调用前就清除缓存,即使方法报错,也会清除缓存。
新属性allEntries当值为true时,清空所有缓存,忽略key。当值为false时,清空指定key的缓存,默认为false。
demo
@Cacheable(value = "cache1", key = "#root.target")
public String getName() {
return "cache1";
}
@Cacheable(value = "cache1", key = "#p0", condition = "#p0>#p1")
public String getName2(int i, int j) {
return "cache2";
}
// cache1 指定key赋值
@CachePut(value = "cache1", key = "#root.target", condition = "#p0>#p1")
public String setCache1(int i, int j) {
return "put-cache1";
}
// cache1 指定key赋值
@CachePut(value = "cache1", key = "#p0", condition = "#p0>#p1")
public String setCache2(int i, int j) {
return "put-cache2";
}
// 清除cache1 指定key的缓存
@CacheEvict(value = "cache1", key = "#root.target", condition = "#p0>#p1")
public void evictCache(int i, int j) {
}
// 清除cache1的所有缓存,忽略key
@CacheEvict(value = "cache1", allEntries = true, key = "#root.target", condition = "#p0>#p1")
public void evictAllCache(int i, int j) {
}
@Caching
可以同时定义多个注解属性
cacheable
put
evict
@Caching(cacheable = @Cacheable(value = "cache1"), put = @CachePut(value = "cache2", key = "#root.target"), evict = @CacheEvict(value = "cache3", allEntries = true))
public String caching() {
return "caching";
}
CacheManager
除了Spring自带的缓存,还可以用下面这些包管理缓存。
Generic
JCache (JSR-107) (EhCache 3, Hazelcast, Infinispan, and others)
EhCache 2.x
Hazelcast
Infinispan
Couchbase
Redis
Caffeine
Simple