最近目标是写一个只需要本地的缓存,并且可以设置过期时间。
经过了解呢,spring有自带的缓存springcache,了解了一下发现使用是挺方便的,老早之前整合redis的时候还使用过。但是未能满足业务需求的是,无法设定过期时间。
那就准备自己实现一下子呢。
了解到,有两个玩意,CacheManager和Cache两个ConcurrentMap,前者用来管理cache的,可以通过name获取cache,后边是保存缓存内容,通过key获取缓存值。
而我的需求的过期时间细粒度并不高,相同name空间定时清空就可以了,因此只用重新实现CacheManage就可以了。
然后感觉还是心里不踏实,寻思还是看看源码吧,缕一缕实现流程,看看咱这思路有错没。
AOP拦截方法
SpringAOP实现的CacheInterceptor对添加缓存注解的方法进行了拦截,所以这里就是咱分析的入口啦。
发现里面的实现是调用execute方法,显而易见是实现在父类CacheAspectSupport
里面的,咱接着看:
可以嘛,十分简短。。
首先是getCacheOperations()
:
getCacheOperations
getCacheOperations()获取的是CacheOperation对象列表,也就是CachePutOperation、CacheableOperation、CacheEvictOperation分别对应集中注解的实体类,并且是这里是有缓存的,有就直接获取,没有就创建再返回.
然后分析其获取过程,一路找下来终于发现了咱定义的注解为何能联系起来了。
在SpringCacheAnnotationParser的parseCacheAnnotations()
方法中,去匹配Cacheable\CacheEvict\Cacheput\Caching等注解类型,构造相应对象。构造的CacheOperation
就像个实体类了,里面装有cacheNames\key\cacheManager\cacheResolver等信息了,终于联系起来了。
完事如果获取到了CacheOperations就会调用咱私有的execute,感觉是重点来了。
私有execute
方法里面注解挺详细的,确实是在实现业务操作了,也就是咱的取缓存、放缓存等。
问题出现,流程都走完了,咱们说了半天,发现整个流程好像没咋出现之前了解到的CacheManager和Cache呢,所以还是再把目标瞄准上面私有的excute方法里面,进一步剖析,看看【从缓存取】是怎么一个样子。
上面提到咱获取到了cacheOperations集合,但是其类型还是有好几种不好统一管理。又一看,excute的入参是一个名叫CacheOperationContexts
的内部类,并且确实是由CacheOperations构造出来的,那么咱解析看看。
发现里面就两个属性context和sync,并且构造方法确实是对通过传入的cacheOperations存放进context(是一个multivalueMap),以cacheOperation的class为key,CacheOperationContext
对象为值
???我看到这个值的时候蒙了,然后才发现CacheOperationContext
比CacheOperationContexts
少了一个s,是另外一个内部类,里面存有了我们希望看到的Cache。发掘发掘这里的Cache是怎么来的呢
发现CacheOperationContext
的构造方法里面cache属性是通过AbstractCacheResolver#resolveCaches
来获取到的,通过调用CacheManager
的getCache,好家伙太感动了,再让我看看CacheManager
哪来的。
然后又让我发现:setCacheManager
是在CacheAspectSupport
里面的getCacheOperationMetadata()
方法里面,初始化成功之后,会从BeanFactory通过CacheManager.class
的方式set好cacheManager,所以我们自定义cachemanager之后,加上@primary注解就可以产生作用了。
CacheAspectSupport
类还有个CachePutRequest的内部类是用于往cache里面放key和value的
至此,cache获取到了,我的目的也达到了。
总结
1.CacheAspectSupport
类的任务很重啊,里面的execute完成了缓存的业务实现。
2.这一整套流程虽然看着复杂,但根本还是Cache
在完成任务,并用CacheManager
来管理Cache
。
3.CacheManager
和Cache
在整体流程里面的只是负责单纯的功能提供,没有去干预别的流程,所以进行改动还是没啥太大问题的。