基于thrift+ehcache开发缓存服务器

前些天我整理了关于thrift的开发笔记,项目中最近还增加了缓存模块,正规的缓存系统都是是memcache或者redis,mongo来做,现在项目还没达到那种程度,所以就想先找个轻量级别的缓存中间件来搞搞,之前有一些数据量大查询比较耗时,用ehcache缓存一下可以解决不少问题。对于ehcache其实我也不是很了解,在我眼里就是put和get的关系,ehcache虽然小巧但很精致,支持分布式集群,本篇可能暂时还讲不到集群,因为我没搞过今天看时间吧,有时间就整下试试。

首先,我们来了解一下ehcache,ehcache是一个纯Java的进程内的缓存框架,具有快速,精干等特征,是hibernate中默认的cacheProvider。ehcache是一种广泛使用的开源的java分布式缓存,主要面向通用缓存,javaee和轻量级容器,具有内存和磁盘存储,缓存加载器,缓存扩展,缓存异常处理程序,一个gzip缓存servlet过滤器,支持rest和soap api等特征。

下面,我将使用thrift和ehcache结合,完成一个基于ehcache的远程调用的缓存服务。它主要提供put和get两个接口,用户可以调用put接口将数据缓存在服务中,使用get来获取缓存数据。原则上其实我们没有必要对ehcache进行特殊的封装,因为它自己已经封装的很好了,但这里我们做缓存服务,你必须考虑一些问题,例如:你要缓存的内容如何分类?你的缓存接口如何定义适应其他系统?你是否还能支持其他的缓存框架?服务里的每个缓存配置对应的控制器你如何维护等? 这些问题其实就是说你在做缓存服务的时候第一考虑如何实现,第二考虑尽量的可以扩展。


原则上我应该先找一个ehcache的入门案例说一下,这样大家就能明白一些意思,但此类的案例你随便百度一下就能看到很多,所以在这里我就不讲了,可以提供一个传送门:http://blog.csdn.net/longronglin/article/details/6699641


1、第一步,按照惯例,我们需要创建一个maven工程,引入ehcache的jar包,因为我之前创建过thrift的工程,所以这里我直接创建maven moudle就可以了,不了解的同学可以先看我上一篇的内容,传送门:http://blog.csdn.net/qq522935502/article/details/48049013。创建完后,目录结构如下:



在截图里我已经解释的很清除了,这里我就不再使用文字解释了,一会单独看接口的时候再细说。




2、定义thrift实体和接口,通过工具生成Java语言对应的客户端接口,创建实现类。


/**
* 公共返回对象
*/
struct Response {
    1:i32 code;
    2:string msg;
    3:string data;
}

/**
* 缓存Key
*/
struct CacheKey {
	1:i64 clientId;//系统ID
    2:string target;//缓存名称 有约束
    3:string dataKey; //数据Key 要求唯一
}

/**
* 缓存Data
*/
struct CacheData {
	1:string data;
}

/**
* 缓存服务
*/
service CacheService{
	/**
	* 增加一个缓存
	*/
    Response putObject(
    	1:CacheKey cacheKey,
    	2:CacheData cacheData
    );
    
    /**
	* 获取一个缓存
	*/
    CacheData getObject(
    	1:CacheKey cacheKey
    );
}

当前我的服务仅仅提供put和get接口,其他的什么删除啊之后再说。在结构体中,我创建了cacheKey和CacheData两个数据对象:



当然这里设计不一定是最好的~至于cacheData,这里面只有一个data的字符串字段,也就是说需要用户自己负责数据的转换,例如你可以在data放置json数据,取出来后再进行json转换就可以了。



3、第三步,看看我们的缓存服务里面的接口都包括什么:

(1)刚才说了,我的缓存服务虽然使用的是ehcache框架,但并不是就说我要实现ehcache里的所有功能,也有可能我的缓存服务提供的接口比ehcache还要多,随意我不会将ehcache裸体给外部,我需要对其有一层包装,或者说ehcache只是我的缓存服务的一种默认实现也是当前的唯一实现,而我的缓存容器都支持哪些接口呢?

/**
 * 缓存接口
 * @author lvpeng
 */
public interface ICache {
	
	/**
	 * 根据key获取value
	 * @param key
	 * @return
	 */
	public Object get(Object key);

	/**
	 * 增加一个缓存
	 * @param key
	 * @return
	 */
	public void put(String key, Object value);

	/**
	 * 删除缓存
	 * @param key
	 * @return
	 */
	public void remove(Object key);

	/**
	 * 查看缓存大小
	 * @return
	 */
	public long size();

	/**
	 * 清理缓存
	 */
	public void clear();
	
	/**
	 * 判断缓存中是否包含这个KEY
	 * @param key
	 * @return
	 */
	public boolean contain(Object key);

	/**
	 * 获取缓存中的所有key
	 * @return
	 */
	public List<?> keySet();
}

(2)我的缓存器使用了是ehcache这种第三方缓存框架,所以我需要对其进行包装,所以我创建了一个DefaultCacheImpl的类,它是系统的默认实现,如果将来不想使用ehcache了,或者又想更换其他的缓存框架,可以再创建一个新的实现类,这个DefaultCacheImpl的代码如下:




(3)当前我的缓存接口和默认实现都定义好了,原则上就可以对外提供使用了,但不要忘记一个问题就是,当前我的DefaultCacheImpl其实就是对ehcache做了一层非常简单的封装,put的key其实就是一个字符串。那我们如果仅仅是这样就提供出去了,将来如何区分不同系统的缓存内容呢,即使我们针对的就可能只有一个系统,但内容可是差异很大的,且此类的缓存实现不一定就这一个,将来会有很多,不同的缓存实现可能所接受的缓存key键是不同的,我们有必要设置一个缓存管理员对上述信息进行一个全方面的管理,这就是我所定义的CacheManager。 但主要这个类和ehcache的cacheManger是重名的,不要混淆。




(4)终于都封装好了,那是不是就可以使用了。原则上是的,但这里我们还需要考虑一个问题,是不是我们系统里就这一个cacheManger呢?答案是否定的,因为在ehcache里不同的配置内容就会对应一个缓存实例,当前你完全可以将所有数据都放置在一个缓存实例中,但显然是不好的。另外就是,当我们对一个数据进行了put后,下次get回来的时候我们必须知道我们上次使用的是那个cacheManger,这里我们就需要有一个map,存储target和cacheManger的关系。 并且保证同一个缓存实例只能有一份(单例)存在,所以我们必须创建一个cacheMangerFactory。这个工厂用来生产我们的cacheManger,对外提供一个接口,接受target目标实例,返回一个cacheManager(默认实现都是ehcahce)。




但这样并不一定是最好的方案,之后在集群环境下这个map我如何同步呢? 这也是一个问题,我暂时还没有去考虑。有看到我文章对这个有思路的麻烦告诉我下?


4、这就是我的缓存服务核心代码了,其实你发现没,没什么技术含量,只是用了几个类把我想表达的一个设计思路给表达出来了,使其有了一个良好的扩展性。当然并不一定是最好的方案。下面我们来看一下我们的接口是如何完成数据的存储和获取的:




get方法呢?



5、最后我们来看一下客户端是如何使用缓存服务的,当然在这之前我们首先需要将我们的缓存服务通过spring容器启动进程。客户端调用:




这样,关于ehcache的缓存服务就总结到这里了,还没有讲集群的问题,我再研究下再说吧~下午要去逛街quartz一直想整理还没有整理,下周我就不写项目中的技术了,想学习一些android和多线程方面的知识。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值