# SpringCacheDemo **Repository Path**: eason93/SpringCacheDemo ## Basic Information - **Project Name**: SpringCacheDemo - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2019-04-18 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## SpringCache初窥 本文的所有实现均基于[博客](https://www.cnblogs.com/imyijie/p/6518547.html) ### 引入 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的相关设置可以在[解决的问题](#question)里面看) @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,可以自定义内存使用多少个键值和过期时间等,具体使用看[博客](https://www.cnblogs.com/fingerboy/p/9549937.html) ### 解决的问题 1. cache使用系统内存,默认存在CacheManager中;获取内容需要getNativeCache,这样才能取出数据 2. springcache的加载机制:默认是用的SimpleCacheManager,使用的是ConcurrentHashMap 3. spring-cache在spring-web程序中带有了重要的context包,本项目功能不需要重新maven加载,其他功能暂时不了解。 4. spring-cache中key使用的是[Spring Expression Language](https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#expressions) 5. springcache中不存在的键,delete的时候会报错,需要handle???? 6. 用redis去做缓存后面实现了 ### 遗留的问题 redis的序列化和反序列化的技术和是实现方式。 ## 额外内容 ### redis作为缓存 这个现在只是copy其他博客的一些实现,暂时还没有自己理解redis的序列化和反序列化的东西,这个需要以后研究一下(可能是下一篇博客吧) 主要实现的代码: ``` @Bean public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory){ RedisSerializer redisSerializer = new StringRedisSerializer(); Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); Set 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就可以实现,这个等有需求再实现吧。 有看博客的小伙伴如果需要我实现的话,我也可以去试试,哈哈哈。(起码要用动力,你说是不?)