SpringCache初窥
本文的所有实现均基于博客
引入
Q:为啥要使用缓存?
A:对于机器而言,每一次的访问,程序都会按照步骤去执行一遍。但是比如同一个请求,对于服务器而言每次反馈的内容都是一样的,为了避免这种资源的浪费,对于一些重复的操作,而且结果往往是稳定不变的,可以使用缓存。缓存操作就是将第一真实查询的结果进行存储,后续的操作,就直接返回结果,而不再去真正的查询。
内存作为缓存
代码清单
CacheManager是用来配置cache缓存相关的信息。
@Bean
public CacheManager cacheManager(){
SimpleCacheManager simpleCacheManager=new SimpleCacheManager();
//name的作用,开的是工作空间
simpleCacheManager.setCaches(Collections.singletonList(new ConcurrentMapCache("models")));
return simpleCacheManager;
}
Controller用来测试缓存的赋予,删除以及更新。
重要注解解释:
@Cacheable:缓存相关的内存,value指定的是上面我设定的(cacheNames也可以),condition可以设定缓存条件,key可以用来设置缓存的key值(默认为空,key的相关设置可以在解决的问题里面看)
@CacheEvict:消除相关的缓存,特殊的键是allEntries,可以指定是不是全部消除
@CachePut:更新相关缓存
NOTE:三个相关的注解可以使用的键几乎相同,如果想了解更多可以去看看注解的相关源码或者查询相关东西哈
@GetMapping("/get")
// @Cacheable(key="#person.name")
@Cacheable(value="models",key="#person.name")
public Person getPerson(Person person){
System.out.println("Person.address:"+person.getAddress());
return person;
}
// 无条件全部cache,不带key,默认是空?这个测试过了,没有设置过的value会报错的
@PostMapping("/get/new")
@Cacheable(value="new")
public Person getNewCache(Person Person){
Person.setName(Person.getName().toUpperCase());
return Person;
}
//删除cache
@DeleteMapping("/delete/{name}")
@CacheEvict(value="models",key="#name")
public String deleteCache(@PathVariable("name") String name){
System.out.println("system input name:"+name);
return "delete Cache success!";
}
@PutMapping("/put")
@CachePut(value="models",key="#person.name")
public Person putCache(Person person){
System.out.println("key:"+person.getName()+","+"address:"+person.getAddress());
return person;
}
每次都需要手动删除的话,很麻烦的,所以定制了一个定时任务,默认删除所有的key值。
@Scheduled(fixedRate=10000)
@CacheEvict(value="models", allEntries = true)
public void cacheRemove(){
}
存在的问题
使用SimpleCacheManager中的cache(hashmap或者是ConcurrentHashMap)会存储会出现一个问题,那就是在缓存一直在变多的时候内存一直会增长,那就可能会crash掉了;解决这个的办法就是自己remove掉,调用或者是schedule都可以。
解决的办法:使用GuavaCache,可以自定义内存使用多少个键值和过期时间等,具体使用看博客
解决的问题
- cache使用系统内存,默认存在CacheManager中;获取内容需要getNativeCache,这样才能取出数据
- springcache的加载机制:默认是用的SimpleCacheManager,使用的是ConcurrentHashMap
- spring-cache在spring-web程序中带有了重要的context包,本项目功能不需要重新maven加载,其他功能暂时不了解。
- spring-cache中key使用的是Spring Expression Language
- springcache中不存在的键,delete的时候会报错,需要handle???
- 用redis去做缓存后面实现了
遗留的问题
redis的序列化和反序列化的技术和是实现方式。
额外内容
redis作为缓存
这个现在只是copy其他博客的一些实现,暂时还没有自己理解redis的序列化和反序列化的东西,这个需要以后研究一下(可能是下一篇博客吧)
主要实现的代码:
@Bean
public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory){
RedisSerializer<String> redisSerializer = new StringRedisSerializer();
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
Set<String> cacheName=new HashSet<>();
// 一定要有cacheName,不然存储不了
cacheName.add("models1");
cacheName.add("models2");
cacheName.add("models");
//解决查询缓存转换异常的问题
// ObjectMapper om = new ObjectMapper();
// om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
// jackson2JsonRedisSerializer.setObjectMapper(om);
//配置序列化
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMillis(10)) //设置时间10分钟
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
.disableCachingNullValues()
.disableKeyPrefix();
RedisCacheManager cacheManager = RedisCacheManager.builder(redisConnectionFactory)
.initialCacheNames(cacheName)
.cacheDefaults(config)
.build();
return cacheManager;
多cacheManager实现
这是重写cacheConfig就可以实现,这个等有需求再实现吧。
有看博客的小伙伴如果需要我实现的话,我也可以去试试,哈哈哈。(起码要用动力,你说是不?)