代码获取地址:我的github项目,MyCodes/OSGi_Ehcache_bundle目录
本文以开源的EhCahe实现了一个简单的通用缓存bundle。
虽然之前我有几篇博客设计到了OSGi框架,但是缺少一个详细的介绍,所以关于OSGi的相关资料,请参考链接 http://blog.csdn.net/abram163/article/details/2534646 里面搜集的资料还是比较好的。
在准备缓存bundle的时候,我简单在网上搜了下JAVA缓存的开源实现,见 http://www.open-open.com/13.htm 。其中ehcache是一个纯Java的过程中缓存实现Hibernate2.1,Spring都支持EHcache嵌入。这里,我没有用到Hibernate或者Spring等框架,而是在Equinox这个OSGi框架中直接嵌入EhcacheAPI,提供出一个能调用put(key, value)和get(key)的服务bundle。当然,在测试的时候,你完全可以用纯java的形式写一下Ehcache的工程,再进行少量重构,改写成bundle形式。
简单介绍下EhCache吧。其实除了作为bundle,我还为我们软件工程课上做论坛的组推荐用ehcache为热门帖子做缓存,因为ehcache很好上手。Ehcache是纯java的轻量级缓存,支持内存和硬盘缓存(在.xml配置),LFU,LRU的缓存实现方式也只要写在配置文件里即可。他的整体结构如下:
CacheManager
Cache Cache
Element Element Element Element Element Element
以下是.xml具体配置,defaultCache是默认cache,.xml文件允许用户配置自己需要的不同cache
<ehcache> <diskStore path="java.io.tmpdir"/> <defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true" diskPersistent="false" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU" /> <cache name="mycache" maxElementsInMemory="10000" eternal="false" maxElementsOnDisk="1000" overflowToDisk="true" timeToIdleSeconds="300" timeToLiveSeconds="600" memoryStoreEvictionPolicy="LFU" /> </ehcache>
然后由配置好的.xml创建CacheManager,然后由CacheManager创建xml内的不同种类的cache,最后新建Element(存着键值对)添加到相应的cache内,即完成了最简单的get,put功能的缓存。比如:
// 读取.xml配置文件,创建cachemanager CacheManager manager = new CacheManager(“XmlStringPath”); // 得到配置文件里的cache名字 String names[] = manager.getCacheNames(); // 创建你想要的cache Cache cache = manager.getCache(name[0]); // 以键值对的形式存入cache Element element = new Element(key, value); // Object, Object cache.put(element); // 从cache取出 cache.get(key);
对xml中配置参数的几点说明:
· Cache配置
· name:Cache的唯一标识
· maxElementsInMemory:内存中最大缓存对象数。
· maxElementsOnDisk:磁盘中最大缓存对象数,若是0表示无穷大。
· eternal:Element是否永久有效,一但设置了,timeout将不起作用。
· overflowToDisk:配置此属性,当内存中Element数量达到maxElementsInMemory时,Ehcache将会Element写到磁盘中。
· timeToIdleSeconds:设置Element在失效前的允许闲置时间。仅当element不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
· timeToLiveSeconds:设置Element在失效前允许存活时间。最大时间介于创建时间和失效时间之间。仅当element不是永久有效时使用,默认是0.,也就是element存活时间无穷大。
· diskPersistent:是否缓存虚拟机重启期数据。(这个虚拟机是指什么虚拟机一直没看明白是什么,有高人还希望能指点一二)。
· diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
· diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
· memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。这里比较遗憾,Ehcache并没有提供一个用户定制策略的接口,仅仅支持三种指定策略,感觉做的不够理想。
最后EhCache官网详细API:http://www.ehcache.org/documentation/apis/index
并附上我的bundle,测试运行正常(图片上传不了= =):
鉴于上传有问题,我还是附上关键代码:
CacheActivator.java
public class CacheActivator implements BundleActivator { private ServiceRegistration sr = null; public void start(BundleContext bundleContext) throws Exception { // CacheServiceImpl cs = new CacheServiceImpl(); // cs.put("k1", null); // sr = bundleContext.registerService(CacheService.class.getName(), new CacheServiceImpl(), null); System.out.println("Cache service starts..."); } public void stop(BundleContext bundleContext) throws Exception { sr.unregister(); System.out.println("Cache service stopped..."); } }
CacheService.java
public interface CacheService { // 以图书服务为例,存入书名和byte流信息 void put(String resname, byte[] content); // 传入书名,获得byte流信息 byte[] get(String resname); }
CacheServiceImpl.java
public class CacheServiceImpl implements CacheService { // String fileName = "src/cache/mycache.xml"; String fileName = ""; CacheServiceImpl() throws IOException { // TODO Auto-generated constructor stub // this.copyConfigFileOut("mycache.xml"); // 构造时,在指定路径生成.xml,提供给CacheManager作配置文件 fileName = "./src/cache/mycache.xml"; } // .xml里除了default的cache, 还有一个自己配置的mycache // public static void copyConfigFileOut(String configFileName) throws IOException // { // InputStream is = CacheServiceImpl.class.getResourceAsStream(configFileName);//"mycache.xml"); //要读取的文件 // // File file = new File("E:\\cacheXML"); // file.mkdir(); // // File localFile = new File("E:\\cacheXML\\"+configFileName);//要写入的文件 // // if(!localFile.exists()) // localFile.createNewFile(); // FileOutputStream fos = new FileOutputStream(localFile); // DataOutputStream dos = new DataOutputStream (fos); // // int c;//表示成功读了多少字节,下面这种while方法是读完剩余的整个文件,生成的文件会很大,不可采用,应采用 dest.write(value,0,valueLen); // while((c=is.read())!=-1) // dos.write(c); // // dos.close(); // is.close(); // } @Override public void put(String resname, byte[] content) { CacheManager manager = new CacheManager(fileName); String names[] = manager.getCacheNames(); Cache cache = manager.getCache(names[0]); // 存入cache cache.put(new Element(resname, content)); int disksize = cache.getDiskStoreSize(); long memsize = cache.getMemoryStoreSize(); manager.shutdown(); System.out.println("Store into cache successfully..."); System.out.println("The DiskStoreSize is " + disksize); System.out.println("The MemoryStoreSize is " + memsize); } @Override public byte[] get(String resname) { CacheManager manager = new CacheManager(fileName); String names[] = manager.getCacheNames(); Cache cache = manager.getCache(names[0]); Element element = cache.get(resname); System.out.println("Get the cache data successfully..."); manager.shutdown(); return (byte[]) element.getValue(); } // public static void main(String[] args) throws IOException { // // TODO Auto-generated method stub // CacheServiceImpl cs = new CacheServiceImpl(); // byte[] b1 = null; // cs.put("k1", b1); // // // } }
mycache.xml(同上)
<ehcache> <diskStore path="java.io.tmpdir"/> <defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true" diskPersistent="false" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU" /> <cache name="mycache" maxElementsInMemory="10000" eternal="false" maxElementsOnDisk="1000" overflowToDisk="true" timeToIdleSeconds="300" timeToLiveSeconds="600" memoryStoreEvictionPolicy="LFU" /> </ehcache>
很简单,很好用吧~