作者回复: 它们是不一样的,spring.cache.cache-names=coffee,是用来配置默认缓存的,启动时会把其中指定的缓存创建出来,运行时的缓存不能超出我这指定的范围(有同学反馈这个与底层的缓存实现有关,因此补充一下,比如Simple的不能超过,但Redis的可以),不配的话就看代码里用到哪些动态创建。@CacheConfig用来配置类级别共享的缓存配置,配置不在@CacheConfig里,就需要加在@Cacheable里。
作者回复: 你是说你没有配置proxyTargetClass,所以Spring用了默认的false?事实上,虽然你没有配置,但Spring Boot替你配了,你可以DEBUG一下看看你的Bean是不是被CGLIB增强了,即使你最后想尽一切办法设置成了false,Spring在判断你的Bean没有实现任何接口后,还是会给你设置为true,详见ProxyProcessorSupport.evaluateProxyInterfaces中有一行proxyFactory.setProxyTargetClass(true)。去年还有人给Spring Boot提过类似的issue,https://github.com/spring-projects/spring-boot/issues/12194 。
作者回复: 如果是默认的,那就在JVM里,如果你用的是Redis的缓存,那就存在Redis里,缓存就是用空间换时间。如果是放在Redis里的,Value很大就会带来一定的反序列化开销,Redis本身对大Key操作也有开销,尽量不要太大。另外,一定要设置过期时间,哪怕你的东西不变,可以设置一个比较长的时间,后面续期,也不要不设,除非你很确定,你就是永久的。
作者回复: 默认Spring会用序列化的方式来做转换,你可以设置大家都序列化成JSON,后面的课程的例子里我们会讲到怎么设置Redis的序列化和反序列化方式。
作者回复: 可以看下CompositeCacheManager,这里可以组合多个CacheManager,每个都能用不同的配置
作者回复: 就是个string,你取不到是因为代码里设置了个比较短的过期时间5000,一下子就过期了,你把这个值设长点,然后就能看到了。
作者回复: Spring Boot会根据Classpath里的内容自动来判断的,有Redis相关类和配置时会用Redis。你可以用spring.cache.type来指定类型
作者回复: 因为默认用的是SimpleKeyGenerator,只看参数,大家都没参数就都是SimpleKey.EMPTY,所以直接就把无参数的缓存给清掉了。至于清哪个Cache,是因为加了CacheConfig
作者回复: 这个注解缓存的是方法的结果,不管方法里是做什么的。
作者回复: 第三级已经不是缓存了,就是击穿后访问数据库了。至于前两级,如果你不打算自己手工编写,想用Spring的缓存抽象,可以看看CompositeCacheManager
作者回复: 两个没什么关系
作者回复: 堆里缓存的东西多,年老代被占用的空间就会多,如果本身你的系统还是大量使用内存的,就会有点吃力,GC会变得频繁等等的。你可以计算一下,缓存的数据大概有多少MB,如果很大,可以设置LRU策略,并不用把所有的内容都放在JVM里,可以结合JVM和Redis,JVM内部没命中的,再访问Redis,替换掉很久没用的缓存。仅供参考。
作者回复: 可以的,你担心的是同时引入Jedis和Lettuce的依赖是吧,最差的情况不就是都自己手写配置Bean么,也不会再差了
作者回复: 可以看下CompositeCacheManager,这里可以组合多个CacheManager,每个都能用不同的配置
作者回复: 你的理解是对的。至于spring.cache.cache-names=coffee,是用来配置默认缓存的,启动时会把其中指定的缓存创建出来。@CacheConfig用来配置类级别共享的缓存配置。
作者回复: 我的猜测是这样的,仅供参考。@Cacheable加上后,这个方法在命中缓存时是不会被执行的,你做的AOP日志增强是要这个方法被执行才会打。
作者回复: 这里如果使用的是Simple的缓存,你会发现的确会报错,如果是Redis,不会报错,Redis里会看到你CacheName前缀的缓存,还是和底层的缓存实现有关的。