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。