文章目录
1.引入依赖
<!--开启 cache 缓存-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
</dependency>
2.在application.yml文件中配置redis
spring:
redis:
host: 127.0.0.1
port: 6379
# 连接池配置,2.0中直接使用jedis或者lettuce配置连接池
jedis:
pool:
# 最大空闲连接数
max-idle: 500
# 最小空闲连接数
min-idle: 50
# 等待可用连接的最大时间,负数为不限制
max-wait: -1s
# 最大活跃连接数,负数为不限制
max-active: -1
3.定义一个Redis配置类
@Configuration
@EnableCaching
public class RedisConfig {
@Bean //在没有指定缓存Key的情况下,key生成策略
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuffer sb = new StringBuffer();
sb.append(target.getClass().getName());
sb.append(method.getName());
for (Object obj : params) {
sb.append(obj.toString());
}
return sb.toString();
}
};
}
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
//RedisCacheManager cacheManager = RedisCacheManager.create(factory);//通过RedisCacheManager的静态方法create 产生的cacheManager只是使用Spring提供的默认配置
//通过自定义的方式构建cacheManager
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
config.entryTtl(Duration.ofMinutes(60 * 72)).//设置缓存过期时间
disableCachingNullValues();//不缓存空值
RedisCacheManager cacheManager = RedisCacheManager.builder(factory) //使用自定义的缓存配置初始化
.build();
return cacheManager;
}
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
@EnableCaching作用
@EnableCaching注解是spring framework中的注解驱动的缓存管理功能。
很多时候系统的瓶颈都在一些比较复杂的IO操作,例如读取数据库,如果一些比较稳定的数据,一般的解决方案就是用缓存。spring boot提供了比较简单的缓存方案。只要使用 @EnableCaching即可完成简单的缓存功能。
作用:开启缓存注解支持(必须作用在缓存配置类上才有效)
4 缓存注解
@Cacheable
作用:主要针对方法配置,能够根据方法的请求参数对其结果进行缓存
Spring 在执行 @Cacheable 标注的方法前先查看缓存中是否有数据,如果有数据,则直接返回缓存数据;若没有数据,执行该方法并将方法返回值放进缓存。
@Cacheable可以指定三个属性value、key和condition:
value:缓存的名称,在spring配置文件中定义,必须指定至少一个
key:缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合
condition:缓存的条件,可以为空,使用SpEL编写,返回true或者false只有为true才进行缓存
例如:
@Cacheable(value = "cache",key = "#key")
public String setCache(String key,String value){
return value;
}
调用方法传入key:aa value:bbbb,可以看见redis中存入的值,key的名字的话由value+key组成,存储数据类型为String,当我再次调用这个方法传入key:aa value:cccc,获取出来的值是bbbb,所以标注了@Cacheable的方法会先去查询缓存中有没有数据,如果有数据,直接返回数据,不会执行方法体的内容;若没有数据,就会执行方法并将返回值放入缓存。
@CachePut
和 @Cacheable 类似,不管缓存中是否存在数据,都会执行方法并将返回值存入到缓存, 主要用于数据新增和修改方法
@CacheEvict
作用:主要针对方法配置,能够根据一定的条件对缓存进行清空
@CacheEvict可以指定五个属性value、key、condition、allEntries和beforeInvocation:
value:缓存的名称,在spring配置文件中定义,必须指定至少一个
key:缓存的key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合
condition:缓存的条件,可以为空,使用SpEL编写,返回true或者false,只有为true才进行缓存
allEntries:是否清空所有缓存内容,缺省为false,如果指定为true,则方法调用后将立即清空所有缓存
beforeInvocation:是否在方法执行前就清空,缺省为false,如果指定为true,则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法执行抛出异常,则不会清空缓存
例如:
@CacheEvict(value = "cache",key = "#key")
public void del(String key){
}
调用这个方法,就会将指定的key的数据删除掉
@CacheEvict(value = "cache",allEntries =true)
public void del(String key){
}
调用这个方法,清除cache中所有缓存
@CacheEvict(value = "cache",condition = "#key.length()<3")
public void del(String key){
}
当key的长度满足条件的时候,就会在redis中删除对应的缓存
@CacheConfig
所有的@Cacheable() 里面都有一个value=“xxx”的属性,这显然如果方法多了,写起来也是挺累的,如果可以一次性声明完那就省事了,所以,有了@CacheConfig这个配置,如果你在你的方法写别的名字,那么依然以方法的名字为准。
例如:
@CacheConfig("aa")
public class SpringCacheDemo {
@Cacheable
public void del(String key){
}
}
@Caching
作用:有时候我们可能组合多个Cache注解使用;比如用户新增成功后,如果我们要通过用户的属性值获取用户的话,就可以使用到这个标签
属性:
cacheable:添加@Cacheable注解
put:添加 @CachePut 注解
例如:
@Caching(
cacheable = {
@Cacheable(value = "user", key = "#key")
},
put = {
@CachePut(value = "user", key = "#result.id", condition = "#result != null"),
@CachePut(value = "user", key = "#result.name", condition = "#result != null"),
@CachePut(value = "user", key = "#result.sex", condition = "#result != null")
}
)
public User setCache(String key){
User user = new User("11", "22", "33");
return user;
}
@Cacheable(value = "user",key = "#key")
public User getCache(String key){
return null;
}
当我执行setCache()方法的时候,就可以通过传入用户的(id,name,sex)到getCache()方法中获取到存入到缓存中的user对象
下图为通过sex可以获取到user:
redis中存入数据形式:
@Cacheable与@CachePut区别
@CachePut也可以声明一个方法支持缓存功能。与@Cacheable不同的是使用@CachePut标注的方法在执行前不会去检查缓存中是否存在之前执行过的结果,而是每次都会执行该方法,并将执行结果以键值对的形式存入指定的缓存中。所以@CachePut一般用于存值,@Cacheable用于取值。
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对象 | 当前方法调用使用的缓存列表(如@Cacheable(value={“cache1”, “cache2”})),则有两个cache | root.caches[0].name |
argument name | 执行上下文 | 当前被调用的方法的参数,如findById(Long id),我们可以通过#id拿到参数,如果为findById(User user),如右边所示 | user.id |
result | 执行上下文 | 方法执行后的返回值(仅当方法执行之后的判断有效,如‘unless’,'cache evict’的beforeInvocation=false) | result |
使用中碰到的问题:
使用缓存注解一直不能生效,存入不到redis:
@RequestMapping("/set")
public Object setCache( String key){
return new SpringCacheDemo().setCache(key);
}
因为@Cacheable这些注解是使用AOP代理实现的,必须走代理才能生效;
通过创建对象来使用缓存方法,这样就会导致一个问题,创建对象方法调用对象的缓存方法不会走代理,就不能正常创建缓存,所以每次都只是执行了方法体本身,并没有通过AOP对方法进行增强。
解决方式:
通过Spring注入:
@Autowired
SpringCacheDemo springCacheDemo;