代码获取地址:我的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>
很简单,很好用吧~