一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第17天,点击查看活动详情。
前言
一般在我们的开发中通常会把redis当做缓存来使用,我们会手动对需要缓存的对象进行操作,在redis中读写。久而久之,我们会自己封装一个redis的工具类来作为我们数据对象和redis中间的桥梁。但是这样有一个缺点,就是缓存的读写和我们的业务代码耦合程度太高了,功能模块之间的界限不清晰。
spring 在解耦方面提供了AOP切面这一概念。使用注解进行标记很好地达到了解耦的目的。spring cache模块提供了整合redis的方法,方便地将redis缓存和业务代码分离,但又能保证redis缓存地读写。
搭建环境
首先我们需要引入依赖。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
这里一个是redis模块,另外一个是cache缓存模块。最后一个是lettuce的连接池依赖。 然后修改我们地application.yml配置文件。
spring:
application:
name: REDIS
data:
redis:
repositories:
enabled: false
cache:
type: redis
redis:
host: 127.0.0.1
password: 7rWBBtyi2H3Cc9ld
port: 6379
lettuce:
pool:
max-wait: -1ms
timeout: 20000
这里首先定义了缓存的类型是redis。然后配置了redis的服务地址以及端口和密码。我提供的是最简单的配置。
spring cache提供了抽象的缓存方法接口,我们可以根据使用不同的缓存载体来选择它对应的缓存实现。下面我们需要创建一个redis缓存的配置类。
@EnableCaching
@Configuration
public class RedisConfiguration extends CachingConfigurerSupport {
@Bean(name = "selfKeyGenerator")
public KeyGenerator sassKeyGenerator(){
final String prefix = "self";
final String sp = ":";
return (target, method, params) -> {
StringBuilder sb = new StringBuilder();
sb.append(prefix).append(sp);
sb.append(target.getClass().getSimpleName())
.append(sp);
sb.append(method.getName());
for (Object param:params){
sb.append(sp);
sb.append(param);
}
return sb.toString();
};
}
@Bean
public CacheManager cacheManager(LettuceConnectionFactory connectionFactory){
RedisSerializationContext.SerializationPair<Object> pair = RedisSerializationContext.SerializationPair
.fromSerializer(new GenericJackson2JsonRedisSerializer());
RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration
.defaultCacheConfig()
.serializeValuesWith(pair)
.entryTtl(Duration.ofMinutes(10));
return RedisCacheManager
.builder(RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory))
.cacheDefaults(defaultCacheConfig).build();
}
/**
* @description 将redisTemplate注入容器
* @author zhou
* @create 2021/4/20 17:30
* @param
* @return org.springframework.data.redis.core.RedisTemplate<java.lang.String,java.lang.Object>
**/
@Bean
public RedisTemplate<String,Object> redisTemplate(LettuceConnectionFactory connectionFactory){
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
this.initRedisTemplate(redisTemplate,connectionFactory);
return redisTemplate;
}
/**
* @description 初始化redis序列化方式,不开启事务
* @author zhou
* @create 2021/4/20 17:29
* @param
* @return void
**/
private void initRedisTemplate(RedisTemplate<String,Object> redisTemplate,LettuceConnectionFactory connectionFactory){
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
// 开启事务
//redisTemplate.setEnableTransactionSupport(true);
redisTemplate.setConnectionFactory(connectionFactory);
}
首先我们需要一个cacheManager,这个是我们的缓存管理器。我们选择redisCacheManager作为它的实现。这里声明了缓存的序列化方式,所有缓存管理器中缓存的过期时间为10分钟。别的配置默认,那么spring就会读取配置文件里面的参数了。
第二个是KeyGenerator,这个是定义key的生成前缀,方便和别的缓存做区分。
最后要注意在类上加@EnableCaching来激活缓存的配置。
方法验证
这里我们数据层使用jpa来做验证。我们先对应写好增删改查的几个方法
@Slf4j
@Service
@CacheConfig(keyGenerator = "selfKeyGenerator",cacheNames = "book")
public class BookServiceImpl implements BookService {
@Autowired
private BookRepository bookRepository;
@Override
@CachePut(key = "#bookPO.bookId")
public BookPO add(BookPO bookPO) {
bookPO.setCreateDate(LocalDateTime.now());
bookPO.setUpdateDate(LocalDateTime.now());
bookRepository.save(bookPO);
return bookPO;
}
@Override
@CachePut(key = "#id",unless = "null == #result")
@Transactional(rollbackFor = Exception.class)
public BookVO update(Long id, BookPO bookPO) {
bookPO.setBookId(id);
int i = bookRepository.updateBook(bookPO);
if (0 == i){
return null;
}
BookVO bookVO = new BookVO();
bookVO.setBookId(id);
bookVO.setBookName(bookPO.getBookName());
return bookVO;
}
@Override
@Cacheable(key = "#id",unless = "null == #result")
public BookVO get(Long id) {
BookPO one = bookRepository.getOne(id);
if (null == one){
return null;
}
BookVO bookVO = new BookVO();
bookVO.setBookId(one.getBookId());
bookVO.setBookName(one.getBookName());
return bookVO;
}
@Override
@CacheEvict(key = "#id")
public void delete(Long id) {
bookRepository.deleteById(id);
}
先来看@CacheConfig 这个注解主要是在类上声明类级别缓存的一些配置,比如, 可以选择这个类中缓存的key的生成器是哪个,以及这个类中缓存的名称是什么。
然后是@CachePut,这个我加在了新增的方法上,目的是当我添加一条记录时,增加一个对应的缓存。这个注解官方的接释是在不干扰方法执行的情况下更新缓存时,可以使用该注释,也就是只要执行了该方法就会添加一个缓存,那么往往是添加在新增方法上用于添加缓存。
@Cacheable这个注解我放在了查询的方法上,目的是,当调用方法时,这个注解会判断,是否命中缓存,如果命中,则返回缓存;如果没有命中缓存,方法执行结束后,添加一份缓存。可以认为程序首先会查询缓存,如果缓存中存在需要的数据,那么直接返回;如果不存在那么会查询数据库,然后把方法的返回值缓存下来。
@CacheEvict这个注解时用于清除缓存,当中有可选参数allEntries=true,如果为true为清空当前cacheName下所有的缓存。一般我们不会这么做,所以都是指定缓存的id来清除。可以看到通常使用sprign表达式来读取方法入参。
以上就是spring boot redis 的简单整合了。