AbstractCacheResolver
具体实现根据调用上下文提供缓存名称集合。
// @since 4.1 实现了InitializingBean public abstract class AbstractCacheResolver implements CacheResolver, InitializingBean { // 课件它还是依赖于CacheManager的 @Nullable private CacheManager cacheManager; // 构造函数统一protected protected AbstractCacheResolver() { } protected AbstractCacheResolver(CacheManager cacheManager) { this.cacheManager = cacheManager; } // 设置,指定一个CacheManager public void setCacheManager(CacheManager cacheManager) { this.cacheManager = cacheManager; } public CacheManager getCacheManager() { Assert.state(this.cacheManager != null, "No CacheManager set"); return this.cacheManager; } // 做了一步校验而已~~~CacheManager 必须存在 // 这是一个使用技巧哦 自己的在设计框架的框架的时候可以使用~ @Override public void afterPropertiesSet() { Assert.notNull(this.cacheManager, "CacheManager is required"); } @Override public Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context) { // getCacheNames抽象方法,子类去实现~~~~ Collection<String> cacheNames = getCacheNames(context); if (cacheNames == null) { return Collections.emptyList(); } // 根据cacheNames 去CacheManager里面拿到Cache对象, 作为最终的返回 Collection<Cache> result = new ArrayList<>(cacheNames.size()); for (String cacheName : cacheNames) { Cache cache = getCacheManager().getCache(cacheName); if (cache == null) { throw new IllegalArgumentException("Cannot find cache named '" + cacheName + "' for " + context.getOperation()); } result.add(cache); } return result; } // 子类需要实现此抽象方法 @Nullable protected abstract Collection<String> getCacheNames(CacheOperationInvocationContext<?> context); }
此抽象类一样的,只是模版实现了resolveCaches()
方法。抽象方法的实现交给了实现类
SimpleCacheResolver
public class SimpleCacheResolver extends AbstractCacheResolver { ... @Override protected Collection<String> getCacheNames(CacheOperationInvocationContext<?> context) { return context.getOperation().getCacheNames(); } ... }
这个实现太简单了,没啥好说的。
NamedCacheResolver
public class NamedCacheResolver extends AbstractCacheResolver { @Nullable private Collection<String> cacheNames; public NamedCacheResolver() { } public NamedCacheResolver(CacheManager cacheManager, String... cacheNames) { super(cacheManager); this.cacheNames = new ArrayList<>(Arrays.asList(cacheNames)); } /** * Set the cache name(s) that this resolver should use. */ public void setCacheNames(Collection<String> cacheNames) { this.cacheNames = cacheNames; } @Override protected Collection<String> getCacheNames(CacheOperationInvocationContext<?> context) { return this.cacheNames; } }
此解析器的特点是,可以自己setCacheNames()。
若内建的不符合条件,我们可以自己实现一个自己的CacheResolver。比如实现和业务相关的缓存处理器(若Class==某Class,做些特殊的操作之类的)
需要注意的是:即使你配置使用的是CacheResolver,你也必须在配置里提供cacheNames至少一个的,因为毕竟是根据你配置的CacheNames去CacheManager里找(当然,若是你的自定义实现除外)
CacheOperationSourcePointcut
Pointcut小伙伴应该不陌生,在AOP章节重点又重点的描述过,我们知道Pointcut直接关乎到是否要生成代理对象,所以此类还是蛮重要的。
// @since 3.1 它是个StaticMethodMatcherPointcut 所以方法入参它不关心 abstract class CacheOperationSourcePointcut extends StaticMethodMatcherPointcut implements Serializable { // 如果你这个类就是一个CacheManager,不切入 @Override public boolean matches(Method method, Class<?> targetClass) { if (CacheManager.class.isAssignableFrom(targetClass)) { return false; } // 获取到当前的缓存属性源~~~getCacheOperationSource()是个抽象方法 CacheOperationSource cas = getCacheOperationSource(); // 下面一句话解释为:如果方法/类上标注有缓存相关的注解,就切入进取~~ // 具体逻辑请参见方法:cas.getCacheOperations(); return (cas != null && !CollectionUtils.isEmpty(cas.getCacheOperations(method, targetClass))); } @Override public boolean equals(Object other) { if (this == other) { return true; } if (!(other instanceof CacheOperationSourcePointcut)) { return false; } CacheOperationSourcePointcut otherPc = (CacheOperationSourcePointcut) other; return ObjectUtils.nullSafeEquals(getCacheOperationSource(), otherPc.getCacheOperationSource()); } @Override public int hashCode() { return CacheOperationSourcePointcut.class.hashCode(); } @Override public String toString() { return getClass().getName() + ": " + getCacheOperationSource(); } /** * Obtain the underlying {@link CacheOperationSource} (may be {@code null}). * To be implemented by subclasses. */ @Nullable protected abstract CacheOperationSource getCacheOperationSource(); }
CacheErrorHandler
处理缓存发生错误时的策略接口。在大多数情况下,提供者抛出的任何异常都应该简单地被抛出到客户机上,但是在某些情况下,基础结构可能需要以不同的方式处理缓存提供者异常。这个时候可以使用此接口来处理
接口内容十分之简单:
public interface CacheErrorHandler { void handleCacheGetError(RuntimeException exception, Cache cache, Object key); void handleCachePutError(RuntimeException exception, Cache cache, Object key, @Nullable Object value); void handleCacheEvictError(RuntimeException exception, Cache cache, Object key); void handleCacheClearError(RuntimeException exception, Cache cache); }
pring对它唯一内建实现为SimpleCacheErrorHandler,代码我不贴了,全是空实现,所以它是一个Adapter适配器形式的存在。
若你想自己提供CacheErrorHandler,你可以继承自SimpleCacheErrorHandler来弄~~~
AbstractCacheInvoker
它的作用是在进行缓存操作时发生异常时,调用组件CacheErrorHandler来进行处理~
// @since 4.1 public abstract class AbstractCacheInvoker { //protected属性~ protected SingletonSupplier<CacheErrorHandler> errorHandler; protected AbstractCacheInvoker() { this.errorHandler = SingletonSupplier.of(SimpleCacheErrorHandler::new); } protected AbstractCacheInvoker(CacheErrorHandler errorHandler) { this.errorHandler = SingletonSupplier.of(errorHandler); } // 此处用的obtain方法 它能保证不为null public CacheErrorHandler getErrorHandler() { return this.errorHandler.obtain(); } @Nullable protected Cache.ValueWrapper doGet(Cache cache, Object key) { try { return cache.get(key); } catch (RuntimeException ex) { getErrorHandler().handleCacheGetError(ex, cache, key); // 只有它有返回值哦 返回null return null; // If the exception is handled, return a cache miss } } ... // 省略doPut、doEvict、doClear 处理方式同上 }
可见这个类在Spring4.1提出,专门用于处理异常的,毕竟CacheErrorHandler也是Spring4.1后才有。
总结
本篇文章为讲解缓存注解的深入原理分析进行铺垫,所以密切关注这篇文章:
【小家Spring】玩转Spring Cache — @Cacheable/@CachePut/@CacheEvict注解的使用以及原理深度剖析