大家都知道spring的缓存机制,可能都会用缓存标签@Cacheable等标签,可是大家有没有想过,为什么在方法上加了标签以后,这个方法就能用缓存呢,作为一名咸鱼coding,当然要知其然也要知其所以然啦,废话不多说,开始吧!
首先我们应该意识到,@Cache运用的是java的动态代理技术,java会给运用了缓存的标签生成一个动态的代理类,如果实现了接口,运用的就是jdk的动态代理,类的动态代理用的是cglib的动态代理技术,那么动态代理类是什么时候生成的呢,首先是spring默认的配置一个advisor(要理解advisor大家首先要知道springAOP的知识):
@Configuration public class ProxyCachingConfiguration extends AbstractCachingConfiguration { @Bean(name = CacheManagementConfigUtils.CACHE_ADVISOR_BEAN_NAME) @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public BeanFactoryCacheOperationSourceAdvisor cacheAdvisor() { BeanFactoryCacheOperationSourceAdvisor advisor = new BeanFactoryCacheOperationSourceAdvisor(); advisor.setCacheOperationSource(cacheOperationSource()); advisor.setAdvice(cacheInterceptor()); if (this.enableCaching != null) { advisor.setOrder(this.enableCaching.<Integer>getNumber("order")); } return advisor; } //这是为了后面的切点执行时候需要的,为什么这么说后面我会说明; @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public CacheOperationSource cacheOperationSource() { return new AnnotationCacheOperationSource(); } //我的理解这是一个增强 @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public CacheInterceptor cacheInterceptor() { CacheInterceptor interceptor = new CacheInterceptor(); interceptor.setCacheOperationSources(cacheOperationSource()); if (this.cacheResolver != null) { interceptor.setCacheResolver(this.cacheResolver); } else if (this.cacheManager != null) { interceptor.setCacheManager(this.cacheManager); } if (this.keyGenerator != null) { interceptor.setKeyGenerator(this.keyGenerator); } if (this.errorHandler != null) { interceptor.setErrorHandler(this.errorHandler); } return interceptor; } } 我们再来看看BeanFactoryCacheOperationSourceAdvisor,
public class BeanFactoryCacheOperationSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor { @Nullable private CacheOperationSource cacheOperationSource; //CacheOperationSourcePointcut相当于一个切点,运用了CacheOperationSource的判断逻辑 private final CacheOperationSourcePointcut pointcut = new CacheOperationSourcePointcut() { @Override @Nullable protected CacheOperationSource getCacheOperationSource() { return cacheOperationSource; } }; /** * Set the cache operation attribute source which is used to find cache * attributes. This should usually be identical to the source reference * set on the cache interceptor itself. */ public void setCacheOperationSource(CacheOperationSource cacheOperationSource) { this.cacheOperationSource = cacheOperationSource; } /** * Set the { @link ClassFilter} to use for this pointcut. * Default is { @link ClassFilter#TRUE}. */ public void setClassFilter(ClassFilter classFilter) { this.pointcut.setClassFilter(classFilter); } @Override public Pointcut getPointcut() { return this.pointcut; } }
切面生成了,什么时候执行呢,spring默认的生成代理类的时候规则是这样的,先找到所有的class文件,然后去匹配所有的advisor,如果匹配成功,那么就生成代理类,执行的时候就植入通知(有的叫增强),我们不必知道具体的底层开始类(实际我也没有深究),我们只要知道当匹配advisor的时候会调用CacheOperationSourcePointcut的matches方法,matches方法的匹配逻辑是这样的,查找targetClass类上面是否有四个注解,分别是Cacheable、CacheEvict、CachePut、Caching,如果有这四个注解,则生成TargetClass代理对象,并将注解信息缓存起来,具体的执行代码如下,大家也可以一直跟下去;
@SuppressWarnings("serial") public class SpringCacheAnnotationParser implements CacheAnnotationParser, Serializable { @Override @Nullable public Collection<CacheOperation> parseCacheAnnotations(Class<?> type) { DefaultCacheConfig defaultConfig = getDefaultCacheConfig(type); return parseCacheAnnotations(defaultConfig, type); } @Override @Nullable public Collection<CacheOperation> parseCacheAnnotations(Method method) { DefaultCacheConfig defaultConfig = getDefaultCacheConfig(method.getDeclaringClass()); return parseCacheAnnotations(defaultConfig, method); } @Nullable protected Collection<CacheOperation> parseCacheAnnotations(DefaultCacheConfig cachingConfig, AnnotatedElement ae) { Collection<CacheOperation> ops = parseCacheAnnotations(cachingConfig, ae, false); if (ops != null && ops.size() > 1 && ae.getAnnotations().length > 0) { // More than one operation found -> local declarations override interface-declared ones... Collection<CacheOperation> localOps = parseCacheAnnotations(cachingConfig, ae, true); if (localOps != null) { return localOps; } } return ops; } @Nullable private Collection<CacheOperation> parseCacheAnnotations( DefaultCacheConfig cachingConfig, AnnotatedElement ae, boolean localOnly) { Collection<CacheOperation> ops = null; Collection<Cacheable> cacheables = (localOnly ? AnnotatedElementUtils.getAllMergedAnnotations(ae, Cacheable.class) : AnnotatedElementUtils.findAllMergedAnnotations(ae, Cacheable.class)); if (!cacheables.isEmpty()) { ops = lazyInit(null); for (Cacheable cacheable : cacheables) { ops.add(parseCacheableAnnotation(ae, cachingConfig, cacheable)); } } Collection<CacheEvict> evicts = (localOnly ? AnnotatedElementUtils.getAllMergedAnnotations(ae, CacheEvict.cl