Spring引入了对Cache的支持。其使用方法和原理都类似于Spring对事务管理的支持。Spring Cache是作用在方法上的,其核心思想是这样的:当我们在调用一个缓存方法时会把该方法参数和返回结果作为一个键值对存放在缓存中,等到下次利用同样的参数来调用该方法时将不再执行该方法,而是直接从缓存中获取结果进行返回。所以在使用Spring Cache的时候我们要保证我们缓存的方法对于相同的方法参数要有相同的返回结果。
使用Spring Cache需要我们做两方面的事:
1.声明某些方法使用缓存
2. 配置Spring对Cache的支持
spring-data-redis针对jedis提供了如下功能:
1.连接池自动管理,提供了一个高度封装的“RedisTemplate”类
2.针对jedis客户端中大量api进行了归类封装,将同一类型操作封装为operation接口
ValueOperations:简单K-V操作
SetOperations:set类型数据操作
ZSetOperations:zset类型数据操作
HashOperations:针对map类型的数据操作
ListOperations:针对list类型的数据操作
注解缓存的使用
@Cacheable:在方法执行前Spring先查看缓存中是否有数据,如果有数据,则直接返回缓存数据;没有则调用方法并将方法返回值放进缓存。
参数 | 解释 | example |
---|---|---|
value | 缓存的名称,在 spring 配置文件中定义,必须指定至少一个 | 例如: @Cacheable(value=”mycache”) @Cacheable(value={”cache1”,”cache2”} |
key | 缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合 | @Cacheable(value=”testcache”,key=”#userName”) |
condition | 缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存 | @Cacheable(value=”testcache”,condition=”#userName.length()>2”) |
除了上述使用方法参数作为key之外,Spring还为我们提供了一个root对象可以用来生成key。通过该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 |
@CachePut:将方法的返回值放到缓存中。
在支持Spring Cache的环境下,对于使用@Cacheable标注的方法,Spring在每次执行前都会检查Cache中是否存在相同key的缓存元素,如果存在就不再执行该方法,而是直接从缓存中获取结果进行返回,否则才会执行并将返回结果存入指定的缓存中。@CachePut也可以声明一个方法支持缓存功能。与@Cacheable不同的是使用@CachePut标注的方法在执行前不会去检查缓存中是否存在之前执行过的结果,而是每次都会执行该方法,并将执行结果以键值对的形式存入指定的缓存中。
@CacheEvict:删除缓存中的数据。
@CacheEvict是用来标注在需要清除缓存元素的方法或类上的。当标记在一个类上时表示其中所有的方法的执行都会触发缓存的清除操作。@CacheEvict可以指定的属性有value、key、condition、allEntries和beforeInvocation。其中value、key和condition的语义与@Cacheable对应的属性类似。即value表示清除操作是发生在哪些Cache上的(对应Cache的名称);key表示需要清除的是哪个key,如未指定则会使用默认策略生成的key;condition表示清除操作发生的条件。
allEntries是boolean类型,表示是否需要清除缓存中的所有元素。
org.springframework.boot
spring-boot-starter-data-redis
commons-codec
commons-codec
1.14
com.alibaba
fastjson
1.2.54
org.apache.commons
commons-lang3
3.9
org.projectlombok
lombok
true
添加基础参数
spring.redis.database=0
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.timeout=5000
配置RedisConfig
package com.example.redis.config;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.serializer.SerializerFeature;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cache.Cache;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.CacheErrorHandler;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
@Slf4j
@Configuration
@EnableCaching
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
public class RedisConfig extends CachingConfigurerSupport {
/**
* 设置 redis 数据默认过期时间,默认2小时
* 设置@cacheable 序列化方式
*/
@Bean
public RedisCacheConfiguration redisCacheConfiguration(){
RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig();
FastJsonRedisSerializer
package com.example.redis.entity;
import lombok.Data;
/**
* @program: myblog-test
* @description:
* @author: Mr.liu
* @create: 2020-08-21 16:30
**/
@Data
public class User {
private String id;
private String username;
private String password;
}
package com.example.redis.dao;
import com.example.redis.entity.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
/**
* @program: myblog-test
* @description:
* @author: Mr.liu
* @create: 2020-08-21 16:29
**/
@Slf4j
@Service
@CacheConfig(cacheNames = "TEST.USER")
public class UserDao {
/*
* 注解缓存的使用
@Cacheable:在方法执行前Spring先查看缓存中是否有数据,如果有数据,则直接返回缓存数据;没有则调用方法并将方法返回值放进缓存。
@CachePut:将方法的返回值放到缓存中。
@CacheEvict:删除缓存中的数据。
*
* */
@CachePut(key="#user.id")
public User set(User user){
log.info("执行set:"+user.getId());
return user;
}
@Cacheable(key="#user.id")
public User get(User user){
log.info("执行get:"+user.getId());
return user;
}
@CacheEvict(key="#user.id")
//@CacheEvict(allEntries = true)清理全部
public void del(User user){
log.info("执行del:"+user.getId());
}
}
package com.example.redis.dao;
import com.example.redis.config.RedisConfig;
import com.example.redis.entity.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
/**
* @program: myblog-test
* @description:
* @author: Mr.liu
* @create: 2020-08-21 16:57
**/
@Slf4j
@Service
@CacheConfig(cacheNames = {"x","x1"})
public class NoneDao {
@CachePut
public User set(User user){
log.info("执行set:"+user.getId());
return user;
}
@Cacheable
public User get(User user){
log.info("执行get:"+user.getId());
return user;
}
@CacheEvict
//@CacheEvict(allEntries = true)清理全部
public void del(User user){
log.info("执行del:"+user.getId());
}
}
设置Controller进行接口测试
package com.example.redis.controller;
import com.example.redis.dao.NoneDao;
import com.example.redis.dao.UserDao;
import com.example.redis.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @program: myblog-test
* @description:
* @author: Mr.liu
* @create: 2020-08-21 16:29
**/
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserDao userDao;
@Autowired
private NoneDao noneDao;
@Autowired
private RedisTemplate redisTemplate;
@GetMapping("/set/{id}")
public String set(@PathVariable String id){
User user = new User();
user.setId(id);
user.setUsername("jack");
user.setPassword(id);
userDao.set(user);
return "success";
}
@GetMapping("/get/{id}")
public Object get(@PathVariable String id){
User user = new User();
user.setId(id);
User user1 = userDao.get(user);
return user1;
}
@GetMapping("/del/{id}")
public Object del(@PathVariable String id){
User user = new User();
user.setId(id);
userDao.del(user);
return "success";
}
@GetMapping("/redis/set/{id}")
public String set1(@PathVariable String id){
User user = new User();
user.setId(id);
user.setUsername("xxxx");
user.setPassword(id);
redisTemplate.opsForValue().set(user,user);
return "success";
}
/*
* 不指定缓存域名
* */
@GetMapping("/setn/{id}")
public String setn(@PathVariable String id){
User user = new User();
user.setId(id);
user.setUsername("jack");
user.setPassword(id);
noneDao.set(user);
return "success";
}
@GetMapping("/getn/{id}")
public Object getn(@PathVariable String id){
User user = new User();
user.setId(id);
User user1 = noneDao.get(user);
return user1;
}
@GetMapping("/deln/{id}")
public Object deln(@PathVariable String id){
User user = new User();
user.setId(id);
noneDao.del(user);
return "success";
}
}
测试截图
@GetMapping("/redis/set/{id}")
redisTemplate.opsForValue().set(user,user);
重写序列化器和data-redis的StringRedisSerializer区别:可以使用Object类型作为key
@CacheConfig(cacheNames = {"x","x1"})&&DigestUtils.sha256Hex(jsonString);