好久没有写博客了,这段时间尽炒股了。作为一个靠技术吃饭的人,多少有种不无正确的感觉。每当闲暇的时候我总在想,如何才能真正的提升自我,最终我得出的结论是写笔记,记录思维,探索自己疑惑,直到解决了自己的所有的疑问,那么我觉得就比别人强了很多。然后我好久没有写笔记了,毫无疑问这段时间我是茫然且空洞的。可能是自己短暂没有了疑问吧,或者已经丧失了发现疑问的能力了,好在周五上班闲的没事,逐个去看看每个工程的代码,然后我发现了一点有意思的地方,因此在这里记录一下。
我们之前在学concurentHashMap的时候说,我们可以用此来做cache,然后提高系统的性能。但是如果我们代码需要部署很多个实例,那么这种本地cache就没有办法保持同步,这就让我想起了mybatis的一级缓存和二级缓存。在集群或者分布式的情况下就是业务错误的始作俑者,所以我们不得不采用一种集中式的cache管理机制,就如集群会话存储一样,因此这块祭出我们的redis,此刻我们立即想到采用redis的姿势。但是考虑到spring项目的cache机制已经成型,因此我们最小成本的对接新缓存就是重写spirng的cache的操作逻辑。而对于redis客户端的初始化太多了,就没必要说了,所以我们定位到springCache机制的操作代码就比较重要了,so 我们来吧!
我们继续看下这个autoCacheConfigure配置。
我们主要看下@import的你内容。
代码语言:javascript复制 static class CacheConfigurationImportSelector implements ImportSelector {
CacheConfigurationImportSelector() {
}
//这块返回了很多类路径,让spirng进行初始化。
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
CacheType[] types = CacheType.values();
String[] imports = new String[types.length];
for(int i = 0; i < types.length; i) {
//我们看一下这块的CacheConfiguration
imports[i] = CacheConfigurations.getConfigurationClass(types[i]);
}
return imports;
}
}
我们看一下这里的静态初始化部分,发现这块提供的可用的cache管理配置器还挺多,基本上每个类都是一个cache的管理器,也就是我们的注解基于其中的任何一个都可以完成cache的管理。我们这里看一下这个simpleCacheConfigtion.class吧,该类是springCache的默认方式。
我们看到这里的cacheManager类非必要的,因为这里默认初始化了一个ConcurrentMapCacheManager。而这里的cacheManger就是实现了cachManager接口的类,也就是具体操作cache的逻辑部分。我们大概看一下这里的ConcurrentMapCacheManager的部分。
看到这块就是concurentHashMap。我们再看一下上边的 RedisCacheConfiguration.class
我们看到我们只需要自己实现cacheManager接口,然后将类注册为cacheManager到spring中,并最终设置进cacheManagerCustomizer中即可。
而至于我们的注解@CachePut是什么时候进行解析的,我们继续跟踪。
发现了很多拦截器,观察一下其基本的实现方式为动态代理。继续跟踪,我们发现如下代码。在spirng的initiallizingben接口的作用下,对我们的拦截器进行初始化,并实例化该类。
代码语言:javascript复制 public void afterPropertiesSet() {
this.getCacheOperationSource();
this.cacheResultInterceptor = new CacheResultInterceptor(this.getErrorHandler());
this.cachePutInterceptor = new CachePutInterceptor(this.getErrorHandler());
this.cacheRemoveEntryInterceptor = new CacheRemoveEntryInterceptor(this.getErrorHandler());
this.cacheRemoveAllInterceptor = new CacheRemoveAllInterceptor(this.getErrorHandler());
this.initialized = true;
}
通过operation决策采用那种拦截器,进行缓存处理。而operation的解析是在这里完成的,如下图所示。
这一切拦截器的调用的源头是spring方法拦截器MethodInterceptor,这块可以看一下具体的实现逻辑哈,这里就不写了。
代码语言:javascript复制public class CacheInterceptor extends CacheAspectSupport implements MethodInterceptor, Serializable {
@Override
@Nullable
public Object invoke(final MethodInvocation invocation) throws Throwable {
Method method = invocation.getMethod();
CacheOperationInvoker aopAllianceInvoker = () -> {
try {
return invocation.proceed();
}
catch (Throwable ex) {
throw new CacheOperationInvoker.ThrowableWrapper(ex);
}
};
try {
return execute(aopAllianceInvoker, invocation.getThis(), method, invocation.getArguments());
}
catch (CacheOperationInvoker.ThrowableWrapper th) {
throw th.getOriginal();
}
}
}
安了~