springboot框架学习积累—SpringBoot缓存管理之相关组件
1.SpringBoot支持的缓存组件有哪些
- 在
SpringBoot
中,数据的缓存管理存储依赖于Spring
框架中cache
相关的org.springframework.cache.Cache
和org.springframework.cache.CacheManager
缓存管理器接口 - 如果当前程序没有定义类型为
CacheManager
的Bean
组件或者是名为cacheResolver
缓存解析器,SpringBoot
将尝试选择并启用以下缓存组件(按照指定顺序)
- Generic
- JCache (JSR-107) (EhCache3 、Hazelcast、 Infinispan等)
- EhCache 2.x
- Hazelcast
- Infinispan
- Couchbase
- Redis
- Caffeine
- Simple
2.SpringBoot基于注解的Redis缓存实现
-
添加redis的依赖启动器:由于引入了
Redis
的依赖启动器,所以会将默认的SimpleCacheConfiguration
缓存配置类变成RedisCacheConfiguration
这个缓存配置类,容器中使用的缓存管理器也从ConcurrentMapCacheManager
变成了RedisCacheManager
,这时候缓存管理器创建的Cache
是RedisCache
,进而操作Redis进行数据的缓存<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
-
对Redis服务进行配置
#Redis服务地址 spring.redis.host=127.0.0.1 #Redis服务端口号 spring.redis.port=6379 #Redis服务密码 spring.redis.password= #对基于注解的Redis缓存数据统一设置有效期为1分钟,单位毫秒 spring.cache.redis.time-to-live=60000
-
编写业务层,实现Redis缓存逻辑
controller
/** * @author yy */ @RestController public class CommentController { @Autowired private CommentService commentService; /** * 查询 * * @param id * @return */ @RequestMapping(value = "/findCommentById") public Comment findCommentById(Integer id){ Comment comment = commentService.findCommentById(id); return comment; } /** * 修改 * * @param comment * @return */ @RequestMapping("/updateComment") public Comment updateComment(Comment comment){ Comment commentById = commentService.findCommentById(comment.getId()); commentById.setAuthor(comment.getAuthor()); Comment comment1 = commentService.updateComment(commentById); return comment1; } /** * 删除 * * @param id */ @RequestMapping("/deleteComment") public void deleteComment(Integer id){ commentService.deleteComment(id); }
service
/** * @author yh */ @Service public class CommentService { @Autowired private CommentRepository commentRepository; /** * @Cacheable: 将该方法查询结果comment存放在springboot默认Simple缓存中(前提是没有引入其他缓存组件) * cacheNames: 起一个缓存命名空间 对应缓存唯一标识 * unless:当满足等号后面的条件时,结果不进入缓存 */ @Cacheable(cacheNames = "comment",unless = "#result == null ") public Comment findCommentById(Integer id){ Optional<Comment> byId = commentRepository.findById(id); if (byId.isPresent()){ //获取comment对象 Comment comment = byId.get(); return comment; } return null; } /** * 更新 */ @CachePut(cacheNames = "comment",key = "#result.id") public Comment updateComment(Comment comment){ commentRepository.updateComment(comment.getAuthor(),comment.getId()); return comment; } /** * 删除 */ @CacheEvict(cacheNames = "comment") public void deleteComment(Integer id){ commentRepository.deleteById(id); } }
3.SpringBoot基于API的Redis缓存实现
/**
* @author yh
*/
@Service
public class ApiCommentService {
@Autowired
private CommentRepository commentRepository;
@Autowired
private RedisTemplate redisTemplate;
/**
* 查询方法,使用API方式进行缓存。
* 先去缓存中查找,缓存中有直接返回,没有,查询数据库
*
* @param id
* @return
*/
public Comment findCommentById(Integer id){
//通过key找Object对象,get括号中的是key
Object o = redisTemplate.opsForValue().get("comment_" + id);
if (o!=null){
//查询到了数据直接返回
return (Comment) o;
}else {
//缓存中没有,去数据库中找
Optional<Comment> byId = commentRepository.findById(id);
if (byId.isPresent()){
//获取comment对象
Comment comment = byId.get();
//将查询结果放到缓存中,并且设置有效期
redisTemplate.opsForValue().set("comment_" + id,comment,1, TimeUnit.DAYS);
return comment;
}
}
return null;
}
/**
* 修改
*
* @param comment
* @return
*/
public Comment updateComment(Comment comment){
commentRepository.updateComment(comment.getAuthor(),comment.getId());
//将数据在数据库中修改完成,再存到redis库里面,将更新数据
redisTemplate.opsForValue().set("comment_" + comment.getId(),comment);
return comment;
}
/**
* 删除
*
* @param id
*/
public void deleteComment(Integer id){
commentRepository.deleteById(id);
redisTemplate.delete("comment_" + id);
}
}
4.SpringBoot之Redis缓存默认序列化机制
-
查看源码,可以将源码分成两部分 1.声明了key,value各种序列化的初始值,初始值为空 2.进行默认序列化设置方式,默认设置是JDK序列化方式
public class RedisTemplate<K, V> extends RedisAccessor implements RedisOperations<K, V>, BeanClassLoaderAware { // 声明了key,value各种序列化的初始值,初始值为空 @Nullable private RedisSerializer keySerializer = null; @Nullable private RedisSerializer valueSerializer = null; @Nullable private RedisSerializer hashKeySerializer = null; @Nullable private RedisSerializer hashValueSerializer = null; ... // 进行默认序列化设置方式,默认设置是JDK序列化方式 public void afterPropertiesSet() { super.afterPropertiesSet(); boolean defaultUsed = false; if(this.defaultSerializer == null) { this.defaultSerializer = new JdkSerializationRedisSerializer( this.classLoader != null? this.classLoader:this.getClass().getClassLoader()); } ... } ... }
2. 根据上述源码分析可以得出以下两个重要结论
5.SpringBoot之Redis缓存自定义序列化机制
-
引入
Redis
的依赖后,SpringBoot
提供的RedisAutoConfiguration
自动配置会生效,RedisAutoConfiguration
这个类有关于RedisTemplate
的定义方式public class RedisAutoConfiguration { //将方法的返回值注入到ioc容器中,key是方法名 @Bean //当redisTemplate这个bean不存在时生效,如果自定义了一个redisTemplate的bean,那么这个方法的返回值就失效了 @ConditionalOnMissingBean(name = "redisTemplate") public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException { RedisTemplate<Object, Object> template = new RedisTemplate<>(); template.setConnectionFactory(redisConnectionFactory); return template; } ... }
6.SpringBoot缓存管理之自定义RedisCacheManager
@Configuration
class RedisCacheConfiguration {
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory
redisConnectionFactory, ResourceLoader
resourceLoader) {
RedisCacheManagerBuilder builder =
RedisCacheManager.builder(redisConnectionFactory).cacheDefaults(this.determineConfiguration(resourceLoader.getClassLoader()));
List<String> cacheNames = this.cacheProperties.getCacheNames();
if (!cacheNames.isEmpty()) {
builder.initialCacheNames(new LinkedHashSet(cacheNames));
}
return
(RedisCacheManager) this.customizerInvoker.customize(builder.build());
}
private org.springframework.data.redis.cache.RedisCacheConfiguration
determineConfiguration(ClassLoader classLoader) {
if (this.redisCacheConfiguration != null) {
return this.redisCacheConfiguration;
} else {
Redis redisProperties = this.cacheProperties.getRedis();
org.springframework.data.redis.cache.RedisCacheConfiguration
config =
org.springframework.data.redis.cache.RedisCacheConfiguration.defaultCacheConf
ig();
config =
config.serializeValuesWith(SerializationPair.fromSerializer(
new
JdkSerializationRedisSerializer(classLoader)));
...
return config;
}
}
}
制,需要自定义RedisCacheManager
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
// 分别创建String和JSON格式序列化对象,对缓存数据key和value进行转换
RedisSerializer<String> strSerializer = new StringRedisSerializer();
Jackson2JsonRedisSerializer jacksonSeial =
new Jackson2JsonRedisSerializer(Object.class);
// 解决查询缓存转换异常的问题
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jacksonSeial.setObjectMapper(om);
// 定制缓存数据序列化方式及时效
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofDays(1))
.serializeKeysWith(RedisSerializationContext.SerializationPair
.fromSerializer(strSerializer))
.serializeValuesWith(RedisSerializationContext.SerializationPair
.fromSerializer(jacksonSeial))
.disableCachingNullValues();
RedisCacheManager cacheManager = RedisCacheManager
.builder(redisConnectionFactory).cacheDefaults(config).build();
return cacheManager;
}