springboot 配置ehcache缓存,通过注解定制多租户(multiTenantId)生成缓存的key,并且实现注解按照tenantId清除缓存,tanant之间缓存互相不影响

调研背景

    本公司有一项功能需求,由于查询的数据太多会导致访问时间超优化API接口,但是这不是长久之计,便决定引入缓存,但是此 缓存能够实现按照不同租户的ID号码在同一个cacheName中去生成能识别租户的key,而且在使用cacheEvict时候能够清除在当前租户在cacheName里面所有的缓存,不能清除用户在这个cacheName里面的缓存,并开始了我的调研,和不断的debug,查看底层实现的代码,最终经过一个星期的调研,实现了这个功能,现在想分享给大家,希望对你们今后会给你们帮助和思路。

分析如何定制生成的缓存key,满足我们的要求。

    因为想用注解的方式去生成缓存,@Cacheable()可以生成缓存,那么我便去研究这个注解的实现,通过查看他的方法,我们可以看到 ,如果我们想定制key的话,那么这个keyGenerator()是不是有什么用处,经调查发现,这个是生成默认的key。如果用在方法上,是将方法的强求参数全部都给按照顺序和值,然后返回的参数形成一个唯一的key。那此时思路就来了 ,那么是不是可以直接在这上面定义当前租户的tenantId,那么就开始去动手,重写keyGenerator()

springboot 配置ehcache缓存,通过注解定制多租户(multiTenantId)生成缓存的key,并且实现注解按照tenantId清除缓存,tanant之间缓存互相不影响_第1张图片

这两个类就是我重写的。下面我贴出里面的重写的源码。

springboot 配置ehcache缓存,通过注解定制多租户(multiTenantId)生成缓存的key,并且实现注解按照tenantId清除缓存,tanant之间缓存互相不影响_第2张图片

springboot 配置ehcache缓存,通过注解定制多租户(multiTenantId)生成缓存的key,并且实现注解按照tenantId清除缓存,tanant之间缓存互相不影响_第3张图片

重写了keyGenerator()方法,将只是生成参数key修改成前面有tenantId+simpleKey(还是以前的参数key)这样就按照租户生成了同一个参数的不同缓存,存在于同一个CacheName 的集合下面

分析springboot缓存源码:

    springboot如何使用配置ehcache缓存,文章一搜一大把,这里就不再赘述 。首先就开始分析源码:以及改造生成的key的思路:

springboot 配置ehcache缓存,通过注解定制多租户(multiTenantId)生成缓存的key,并且实现注解按照tenantId清除缓存,tanant之间缓存互相不影响_第4张图片

springboot 配置ehcache缓存,通过注解定制多租户(multiTenantId)生成缓存的key,并且实现注解按照tenantId清除缓存,tanant之间缓存互相不影响_第5张图片

首先可以看到,springboot通过@EnableCaching为入口开启缓存,进入注解我们可以看到@Import(CachingConfigurationSelector.Class)导入了配置的选择器。springboot 配置ehcache缓存,通过注解定制多租户(multiTenantId)生成缓存的key,并且实现注解按照tenantId清除缓存,tanant之间缓存互相不影响_第6张图片

由于在注解里面默认就会声明默认的是按照poxy代理的的方式加载模式

springboot 配置ehcache缓存,通过注解定制多租户(multiTenantId)生成缓存的key,并且实现注解按照tenantId清除缓存,tanant之间缓存互相不影响_第7张图片

这边底层添加了代理模式的配置 ,那么我们再进入到里面,

springboot 配置ehcache缓存,通过注解定制多租户(multiTenantId)生成缓存的key,并且实现注解按照tenantId清除缓存,tanant之间缓存互相不影响_第8张图片

接着配置里面主要是定义了cache的拦截器。我们再进入到拦截器可以发现里面调用了invoke()方法,这个方法主要是实现了,若缓存中存在则直接返回返回缓存的方法,没有就会去执行方法。

我们主要是看看他的父类,cacheAspectSupport这个类,然后再这个类里面我们可以看到又很多的方法,找到了,我们需要的功能,是清除的方法,大家可以debug进来,能够看到最终会进入到这个类里面

springboot 配置ehcache缓存,通过注解定制多租户(multiTenantId)生成缓存的key,并且实现注解按照tenantId清除缓存,tanant之间缓存互相不影响_第9张图片

cacheEvict会执行我标记的地方如果allEntries=true就会执行doClean()否则会执行下面的doEvict,那么顿时清除缓存的思想便油然而生,我们可以重写这个方法,但是如果要重写这个方法,那我们是不是就应该要把前面的都要重写一遍,对哒,springboot注解就是如此之烦躁,那你既然想要定制,那你就当然别怕麻烦。但是又出现了一个问题,那你是不是注解也要换,如果你不换注解,重写的东西太多了。所以一拍即合,开干,直接从源头开始重写,下面贴出我重写的代码的图,从上到下。

springboot 配置ehcache缓存,通过注解定制多租户(multiTenantId)生成缓存的key,并且实现注解按照tenantId清除缓存,tanant之间缓存互相不影响_第10张图片

首先放上我重写的所有类,大家可以看到,从注解,到上面给大家截图的源码我都重写了,只不过都加了个前缀,printSaas,其实内容都是复制过来,但是做了一些修改。我们从上到下,看看哪些修改,我会标记出来

springboot 配置ehcache缓存,通过注解定制多租户(multiTenantId)生成缓存的key,并且实现注解按照tenantId清除缓存,tanant之间缓存互相不影响_第11张图片springboot 配置ehcache缓存,通过注解定制多租户(multiTenantId)生成缓存的key,并且实现注解按照tenantId清除缓存,tanant之间缓存互相不影响_第12张图片

这边注释掉两行代码是因为,我还没弄清这个具体是干啥的,但是我大概了解是由于我换了新注解,不注释掉这两行的话会报错,报没有开启EnableCaching,然后我跟踪下去,是因为上面两行代码也是与下图一样,是因为通过了EnableCacing注册的所以会报错。我也懒得再去重写,太多太深了,所以对我业务没影响我就注释掉了

springboot 配置ehcache缓存,通过注解定制多租户(multiTenantId)生成缓存的key,并且实现注解按照tenantId清除缓存,tanant之间缓存互相不影响_第13张图片

这个图做个说明:首先我重新定义了cache拦截器,然后我重写了下面这个方法,是因为,这里面本来定义的是EnableCaching.class.getName,如果你不重写,那么容器则无法识别你的新注解,会报错。

springboot 配置ehcache缓存,通过注解定制多租户(multiTenantId)生成缓存的key,并且实现注解按照tenantId清除缓存,tanant之间缓存互相不影响_第14张图片

这是最后一张,就是为了重写doclear()方法,主要思路是循环cache下面所有的key,判断如果当前的租户Id号与key的tenantId相等,那么则通过key去清除。为了适应多种cacheManage我做了一些判断,因为ehcacheCache无法转成googleCache,因为我的程序默认是GuavaCacheManage,我也没找到到底是怎么默认的(希望哪位大神知道可以告知我一下)我知道他的机制是通过autoConfiguration去遍历各种cacheManage,如果又合适的或者说再condition中匹配成功的就使用哪个cacheManager。我就是在resource下面建立了一个ehcache.xml便使用了ehcache。这一块还是没完全弄懂他的机制是啥,希望有知道的大神和我说一声。

 

最后我的研究已经说完了,可能我的说法有误,但是我确实实现了这个需求和功能,希望大神指教。

你可能感兴趣的:(cache)