Spring Cache 配置的 Pointcut、Advice 和 Advisor
上篇讲到,Spring Cache 在 AdviceMode.Proxy 模式会注入 AutoProxyRegistrar 和 ProxyCachingConfiguration 这两个类,其中 AutoProxyRegistrar 是一个与 cache 功能无关的 AOP 类,已经在上一篇中介绍过。
这篇将详细深入 ProxyCachingConfiguration 的配置类。
ProxyCachingConfiguration 解析
首先可以看到 ProxyCachingConfiguration 继承自 AbstractCachingConfiguration,所以我们先看 AbstractCachingConfiguration 的源码。
注:这个 AbstractCachingConfiguration 也是其他代理模式下配置的基类
ProxyCachingConfiguration 的基类 —— AbstractCachingConfiguration
AbstractCachingConfiguration 源码
1 |
|
这里涉及到一个 CachingConfigurer 的接口,容器内应当注册了 0 个或 1 个 CachingConfigurer,当有 CachingConfigurer 的时候,会为 Cache 功能提供 CacheManager、CacheResolver、KeyGenerator、CacheErrorHandler 这四项配置。顺便从容器取到 @EnableCaching 注解的参数保存在 enableCaching 中。
AbstractCachingConfiguration 总结
如果有配置 CachingConfigurer,则将其中的 CacheManager、CacheResolver、KeyGenerator、CacheErrorHandler 保存在类中。同时取到 @EnableCaching 注解的参数保存在类中。
ProxyCachingConfiguration 定义
ProxyCachingConfiguration 源码
1 |
|
注:所有的 Configuration 和 Bean 都加上了 @Role(BeanDefinition.ROLE_INFRASTRUCTURE) 以便于被 AutoProxyRegistrar 过滤注册。具体逻辑见上一篇。
配置类一共注入了三个类:CacheOperationSource、CacheInterceptor、BeanFactoryCacheOperationSourceAdvisor。额外做的操作就是将基类拿到的 CacheManager、CacheResolver、KeyGenerator、CacheErrorHandler 尽可能注入 CacheInterceptor 中,将 EnableCaching 注解中的 order 注入到 BeanFactoryCacheOperationSourceAdvisor 中,并将这三者接线。
我们就按 CacheOperationSource、CacheInterceptor、BeanFactoryCacheOperationSourceAdvisor 的顺序看这三个类。
ProxyCachingConfiguration 注入的类
从 CacheOperationSource 到 AnnotationCacheOperationSource
CacheOperationSource 只是一个接口,实际注册的是 AnnotationCacheOperationSource。
CacheOperationSource 接口只包含一个 Collection<CacheOperation> getCacheOperations(Method method, Class<?> targetClass) 方法,targetClass 和 method 分别是调用者的类和调用的方法。接口方法应当将 method 上的 Cacheable 之类的注解,将其解析为 CacheOperation 集合并返回。关于 CacheOperation 的细节见下文,点击跳转。
AbstractFallbackCacheOperationSource 实现了 CacheOperationSource,并做了一级 CacheOperations 的缓存:
1 | private final Map<Object, Collection<CacheOperation>> attributeCache = |
getCacheOperations 方法优先从 attributeCache 缓存拿 CacheOperation 集合,否则使用 computeCacheOperations 方法计算 CacheOperation 集合并放进缓存。
computeCacheOperations 源码如下,过程加了注解:
1 | private Collection<CacheOperation> computeCacheOperations(Method method, Class<?> targetClass) { |
至于 findCacheOperations(Class<?> clazz) 和 findCacheOperations(Method method) 是由子类实现的抽象方法。
AnnotationCacheOperationSource 继承自 AbstractFallbackCacheOperationSource,根据不同的构造方式可以指定 publicMethodsOnly 和 annotationParsers,这里以默认构造函数为例。
默认构造函数只指定了 publicMethodsOnly 为 true,annotationParsers 只包含一个 SpringCacheAnnotationParser。
下一章我们再来详细看一看 SpringCacheAnnotationParser 这个类,现在我们先暂时知道 SpringCacheAnnotationParser 是一个取到 method 或 clazz 上注解并解析整理成 CacheOperation 集合的解析器类就可以了。
AnnotationCacheOperationSource 关键的功能代码如下:
1 |
|
因为 annotationParsers 只有一个 SpringCacheAnnotationParser,所以本质上就是执行了一行 return springCacheAnnotationParser.parseCacheAnnotations(method); 或 return springCacheAnnotationParser.parseCacheAnnotations(clazz);。
AnnotationCacheOperationSource 小结
我们可以看出,AnnotationCacheOperationSource 最终实现的就是取到方法或目标类上注解并将其解析为 CacheOperation 集合。
CompositeCacheOperationSource
CacheOperationSource 还有一个实现 —— CompositeCacheOperationSource 表示 CacheOperationSource 的聚合,有一个私有的 CacheOperationSource 数组,其 getCacheOperations 方法会将这些 CacheOperationSource 的 getCacheOperations 的结果聚合到一个集合中返回。
CacheOperation
CacheOperation 有三个实现类:CacheEvictOperation、CachePutOperation、CacheableOperation,对应三种注解的操作。其本身具有以下的字段:
1 | private final String name; |
CacheInterceptor
CacheInterceptor 继承自 CacheAspectSupport,实现了 MethodInterceptor。
MethodInterceptor 的本质是一个增强 Advice。实现 MethodInterceptor 的目的是为了可以被 Advisor 调用。
关键代码如下:
1 |
|
可以看出,其实就是调用了基类 CacheAspectSupport 的 execute 方法并拆包了一下基类抛出的异常。
因为此处过于复杂,我们放在下下一章详细讲 CacheAspectSupport 这个类。现在我们只需要知道,CacheInterceptor 提供了一个 Advice,在方法执行前后使用 cacheOperationSource 取到 CacheOperation 集合并执行对应的缓存操作。
BeanFactoryCacheOperationSourceAdvisor
BeanFactoryCacheOperationSourceAdvisor 继承自 AbstractBeanFactoryPointcutAdvisor,其 pointcut 使用的是固定的 CacheOperationSourcePointcut。
CacheOperationSourcePointcut
CacheOperationSourcePointcut 继承自 StaticMethodMatcherPointcut,被 set 了上文的 CacheOperationSource,其 match 方法实现如下:
1 |
|
也就是说,能取出 CacheOperation 的方法都会作为切入点。
BeanFactoryCacheOperationSourceAdvisor 小结
也就是说,BeanFactoryCacheOperationSourceAdvisor 会对所有能取出 CacheOperation 的方法执行 CacheInterceptor 这个 Advice。