Spring的缓存机制探索

2022-08-11 17:37:37 浏览数 (1)

好久没有写博客了,这段时间尽炒股了。作为一个靠技术吃饭的人,多少有种不无正确的感觉。每当闲暇的时候我总在想,如何才能真正的提升自我,最终我得出的结论是写笔记,记录思维,探索自己疑惑,直到解决了自己的所有的疑问,那么我觉得就比别人强了很多。然后我好久没有写笔记了,毫无疑问这段时间我是茫然且空洞的。可能是自己短暂没有了疑问吧,或者已经丧失了发现疑问的能力了,好在周五上班闲的没事,逐个去看看每个工程的代码,然后我发现了一点有意思的地方,因此在这里记录一下。

我们之前在学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();
              }
       }
}

安了~

0 人点赞