前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring的缓存机制探索

Spring的缓存机制探索

作者头像
写一点笔记
发布2022-08-11 17:37:37
3000
发布2022-08-11 17:37:37
举报
文章被收录于专栏:程序员备忘录程序员备忘录

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

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

安了~

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-11-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 写点笔记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 Redis
腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档