写本身的缓存框架,JAD-CACHE架构设计篇

    在以前一篇《写一个本身的通用缓存框架,以同时支持ehcache、mecache以及springcache注解等等》博文中,列出了本身的通用缓存框架须要实如今的大体功能总结以下:git

    一、提供统一的缓存操做api;spring

    二、支持同时使用多种缓存实现;设计模式

    三、提供灵活的配置;api

    四、须要防止缓存穿透;缓存

    五、须要能够灵活指定缓存存活时间;服务器

    六、须要任意控制缓存的停用或启用。微信

    目前这个框架的编码部分已完成,并取名为JAD-CACHE,取这个名字的缘由是由于它是个人我的的JAD项目的一部分,JAD项目是本人用业余时间开发一个企业基础架构平台,因涉及的东西比较多,并且不少模块尚未彻底完成。目前准备把其中作的比较完善的缓存模块单独从原项目中剥离出来做为一个独立的项目并准备开源给你们测试和使用,因而也就有了JAD-CACHE。架构

     本文先展现这个框架的原理及架构设计,后续开放源代码后再发布一些使用手册方面的文章。框架

     JAD-CACHE缓存框架是在spring cache模块的基础上扩展而来,在上一篇博文《通用缓存框架,spring缓存模块原理分析篇》已经系统分析过srping cache的原理,这里再也不重复。spring cache模块重要的两个类就是org.springframework.cache.Cache和 org.springframework.cache.CacheManager。如今我跟据本身的须要对它们进行扩展。测试

    我设计的Cahce相关的扩展类图以下:

图:Cahce扩展类类图1

       上图中灰色部分是spring自已的类,其它的是扩展出来的。上图ManageredCache是一个接口,表示这个Cache可由本框架的CacheClient实例管理起来(关于CacheClient的概念稍后介绍)。ManageredCache接口在父接口Cache的基础上,增长了isAllowNullValues()等等方法,做用分别以下:

getCacheClient()

得到管理它的CacheClient实例

isAllowNullValues()

可否在此缓存中保存null值,防止缓存穿透

getActivityTime()

得到此缓存中对像存活时间,注意这个存活时间是一个业务存活时间,开发人员可经过配置指定一个默认的时间,也能够在调用put()方法缓存对像时经过参数另外指定一个存活时间。这样,在调用get()方法从缓存中取出对像后,会先经过个这个方法判断对像是否失效(即便它依旧存在于缓存中,但咱们能够在业务的角度上觉得它失效了),这个存活时间应该短于用户在ehcache.xml等配置文件配置的存活时间,这样就实现了个性化指定同一类型不一样对像的存活时间。

put(Object, Object,int)

这个方法跟父类Cache接口的put(Object,Object)功能相同,就是把对像缓存起来,但它支持一个int类型的参数,用于指定对像存活时间的秒数。

size()

统计对像总数

keySet()

得到全部key

    全部要缓存的数据都不是直接持久化到缓存容器中的,而是被装包成了一个个CacheValue类型的实例,在上图的类图中,能够看到,CacheValue类包含两个属性expiryTime和value,其中expiryTime是超时时间,value就是据体的数据对像。若是数据对像为null值,就转换成NullCacheData实例。在AbstractManageredCache这个抽象类的相关方法中,就实现了这些逻辑。

     AbstractManageredCache是对ManageredCache接口的抽象实现,实现了在操做缓存以前,先经过管理它的CacheClient实例判断当前缓存客户端的状态是否已开启 (调用cacheClient的isStarted()方法),若是启用,就调用父接口Cache中声明的getNativeCache()得到具体的缓存实例操做缓存,若是没有启用,就什么也不作。同时,在它的put()方法实现过程当中,会跟据它的activityTime属性指定存活时间,或跟据allowNullValues属性决定是否缓存null值,并将全部要缓存的数据包装成CacheValue实例持久化到缓存容器中。而在get()方法实现的罗辑,也会作相应的操做,跟据activityTime属性踢出超时的对像,并将缓存容器中的CacheValue实例转换成原始的数据类型。

    在spring原来的缓存模型中,全部的Cache实例都被ManagerCache所管理。但本框架抽像出了一个叫CacheClient的概念,全部的缓存实例都被扩展成了ManageredCache对像,并被一个CacheClient实例管理起来(而此CacheClient实例又持有一个CacheManager的引用,这样一来Cache也就能够经过CacheClient间接的被ManagerCache管理)。这样作有一个好处就是:在Cache操做缓存以前,先经过它的CacheClient判断当前的缓存状态,跟据这个装态决定是否要进行操做。设计CacheClinet还有一个目地,就是让多个缓存实现能更好的共存于同一个应用之中,好比让EhCache实现的缓存交给一个CacheClinet管理,让MemCache实现的缓存交给另外一个CacheClinet管理。在spring原来的缓存模块中,设计了一个叫CompositeCacheManager的类,能够同时配置多个CacheManager实例以达到这个目地。但我弃用它,改用CacheClinet的目地,就是想增长能够任意停用或启用某些Cache的功能。好比,当memcache服务器挂掉时,咱们经过它对应的CacheClinet实例改变这个实例管理的全部Cache的状态,停用它,从而达到从应用层上禁用或启用缓存的目地。CacheClient相关的类图以下:

图:CacheClient相关类图

    上图中的CacheClient类是一个接口,它声明的一些诸如start(),stop()等方法,用于修改本实例的状态,启用或停用,而isStarted()就是用来检查状态的,返回当前Client是否启用。每个CacheClient实例管理一个CacheManager,经过该接口中的getCacheManager()能够得到它所控制的CacheManager实例引用,每一个一个实例有一个惟一的名字,经过getClientName()能够获取它的名字。除此外,此接口还有一些诸如getAllowNullValues(),setDefActivityTime()之类的方法。这是为了方便开发人员对缓存的配置,开发人员在配置CacheClient实例时,能够在这里配置allowNullValues, defActivityTime等属性,这样再在配置CacheManager或者Cache实例时就能够不指定了这些属性了,Cache会自动继承它的Client的属性值。这些配置在CacheClient接口的抽像实现类AbstractCacheClient中都有相应的实现。

     在AbstractCacheClient中还有一个重要的属性,就是autoStart属性。这个属性若是配置为true,那在spring容器初始化的时候,这个Client实例一但生成,就会自动调用它的start()启动它,以使得它所控制的CacheManager能够正常操做缓存。不然,它不会自动启动,它所控制的全部Cache都处于禁用状态。

    另外,为了方便配置,在AbstractCacheClient还提供了autoCreateCache属性,用于指定此客户端可否自动建立缓存实例。在Spring原来的缓存配置中,须要把用到的每一个Cache都写到配置文件中,要么配到ehcache.xml中,要么在配置CacheManager时附加Cache实列相关的配置。不然,在操做没有配置的缓存时,会提示找不到某某名称的cache。在本框架中,若是指定了autoCreateCache属性为true,在调用CacheManager.getCache(String name)获取不到Cache时,会自动建立一个默认的(经过覆盖CacheManager.getMissgeCache()实现)。固然,若是指定autoCreateCache为false时,就不会自动建立,这要求用户在ehcache.xml中本身配置。固然,为了方便,本框架,还能够直接在CacheClient中配置,上面的类图AbstractCacheClient中两个属性cacheNames和cacheBeans就是用于这个配置的。用户可经过cacheNames只配置名称,或者经过cacheBeans属性配置一个类型为的JadCache实例bean。这个JadCache相似于spring 在实现ehcache时提供的EhCacheFactoryBean。只不过这个更加简洁通用。若是只经过cacheNames配置一个Cache的名称,那么此Cache实例的相关属性都采用默认值这要求用户在ehcache.xml配置文件中配置一个defaultCache,或须要在memcache.xml中配置一个默认的cacheclient。

    每个CacheClient惟一管理一个CacheManager实例(在上面类图中能够看到,AbstractCacheClient类中有一个JadCacheManager类型的属性:cacheManager。关于本框架的CacheManager扩展稍后介绍)。CacheClient在被spring初始化时,会自动调用registryCacheManager()方法,跟据不一样的缓存实现厂商生成一个对应的CacheManager实例,并注册到spring context中,同时调用initCache()方法经过配置中的cacheNames或cacheBeans自动初始化全部的Cache实例。初始化完成后,再调用registryToMasterCacheManager()方法,这个方法稍后介绍。

    一个应用系统中,能够有一个或多个CacheClient实例,每一个CacheClient实例控制一个CacheManger。开发人员经过配置不一样的CacheClient实例能够实现同时支持多个不一样的缓存实现,好比,把EhCache相关的缓存配置到一个CacheClient中而把MemCache配置到另外一个CacheClient中。

    为了统一管理全部CacheClient实例,本框架设计了一个叫CacheClientManager来管理所CacheClient实例,它有一个抽像实现AbstractCacheClientManager,这个抽像类中,也有allowNullValues, defActivityTime等CacheClient中具的相同的属性,只不过这里的属性做为一个全局的配置,使得CacheClient能够省去这些配置而直接使用CacheClientManager中的配置。整个应用中,只能有CacheClientManager实例,但这个实例能够管理一个或多个CacheClient。而一般况下,一些简单的应用系统中,每每只有一种缓存实现,也就是只须要配置一个CacheClient,所以AbstractCacheClientManager给出了两个不一样的实现类,分别是上图中红颜色的SingleClientManager和MultiClientManager,分别表示单CacheClient管理或多CacheClient管理器。开发人员可跟据业务状况选择性使用其中一个进行配置。

    前文提到,每一个CacheClient在初始化时,会自动生成一个对应的CacheManager实例并注册到Spring上下文中,但Spring在操做缓存时,为了能准确的经过CacheManager找到相应名称的Cache实例,这就要求还须要对这些CacheManager实例进行统一管理。在spring原来的缓存模块中,提供了一个叫CompositeCacheManager的实现类,以组合设计模式的方式来管理这些CacheManager实例,这个CompositeCacheManager实现类有一个列表指向全部CacheManager实例的引用。在执行getCache(String)时会遍历这个列表,循环调用每一个实例的getCache(String)方法,而后返回一个不为null的Cache,可是若是全部的CacheManager都获取不到Cache时,这个方法最终是会返回null的。然而,在本框架中,是支持找不到Cache时自动建立的,因此在本框架中,我设计了一个叫MasterCacheManager的类来管理这些CacheManager,同时,这个类有一个叫defCacheManager的CacheManager属性来指定一个默认的CacheManager。在跟据名称找不到任何Cache时,就自动调用这个默认CacheManager的addCache()方法来自动建立一个。本框架CacheManager相关的类图以下所示:

图:CacheManager类图

    上图灰色总分是spring缓存模块自带的类,其它颜色是扩展类。其中最右边的MasterCacheManager类就是上文提到管理全部CacheManager的实现类。上图左边的JadCacheManager是一个接口,提供initCache(JadCache)和newCache(JadCache)两个方法,这两个方法,主要是用于在CacheClient初始化过程自动生成CacheManager实现类后,准备经过initCache()方法来初始化配置中的Cache来调用的。对于MasterCacheManager类的实例化,开发人员无需额外在spring context中配置,由于在CacheClientManager的初始化过程当中,会自动注册一个MasterCacheManager类型的实例到spring context中(上面类图AbstractCacheClientManager这个类中的registerMasterManager()方法就是用来作这个事的)。而这个类中cacheManagerMap的属性就是按名称组织起来的CacheManager类型的集合。在每一个CacheClient初始化时自动生成CacheManager实例后,会调用CacheClient类的registryToMasterCacheManager()方法,这个方法会从当前Spring conetxt中获取到MasterCacheManager实例,而后调用它的register()方法,把它注册到MasterCacheManager实例中(添加到cacheManagerMap集合)。

上面类图中的JadAbstractCacheManger是借用了Srping的AbstractCacheManger对JadCacheManager的一个抽象实现,后面在集成EhCache或MemCache等全部缓存时就从这个类往下扩展。

以上就是本框架的一个整体设计,由于篇附过长。后面再在其它的文章中给出在这个基础上扩展EhCache和MemCache的方案,并实现一个基于Map的内存缓存实现。  

目前JAD-CACHE项目已在开源中国码云平台上开源,地址:

https://git.oschina.net/457049726/jad-cache

想关注更多信息或者想及时了解动态的同窗们能够扫如下二维码关注个人微信公众号,多谢

相关文章
相关标签/搜索