




已阅读5页,还剩16页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
JAVA缓存技术JavaJNICacheLinuxXML最近再ITEYE上看到关于讨论JAVA缓存技术的帖子比较多,自己不懂,所以上网大概搜了下,找到一篇,暂作保存,后面如果有用到可以参考。此为转贴,帖子来处:/articles/cache-static-files-with-jnotify-and-ehcache 介绍 JNotify:/,通过JNI技术,让Java代码可以实时的监控制定文件夹内文件的变动信息,支持Linux/Windows/MacOS; EHCache:/,一个广泛使用的Java缓存模块,可以做使用内存和文件完成缓存工作。 在Java Web项目中,为了提高WEB应用的响应速度,可以把常用的静态文件(包括css,js和其他各种图片)提前读入到内存缓存中,这样可以减少很多文件系统的IO操作(这往往也是项目性能的瓶颈之一)。但是这么做往往有一个弊端,那就是当实际的静态文件发生改变的时候,缓存并不能得到及时的刷新,造成了一定的滞后现象。有些项目可能没什么问题,但是对于某些项目而言,必须解决这个问题。办法基本有两种,一种是另外开启一个线程,不断的扫描文件,和缓存的文件做比较,确定该文件时候修改,另外就是使用系统的API,来监控文件的改变。前面一种解决办法缺点很明显,费时费力,后面的办法需要用到JNI,并且编写一些系统的本地库函数,幸运的是,JNoify为我们做好了准备工作,直接拿来用就可以了。 本文会简单给出一个利用JNotify和EHCache实现静态文件缓存的一个小例子。 JNotify的准备 在使用JNotify之前,你需要“安装”一下JNotify。JNotify使用了JNI技术来调用系统的本地库(Win下的是dll文件,Linux下是so文件),这些库文件都已近包含在下载包中了。但是如果你直接使用JNotify的话,往往会报错: Java代码 1 BASH 2 java.lang.UnsatisfiedLinkError: no jnotify in java.library.path 3 at java.lang.ClassLoader.loadLibrary(Unknown Source) 4 at java.lang.Runtime.loadLibrary0(Unknown Source) 5 at java.lang.System.loadLibrary(Unknown Source) 6 at net.contentobjects.jnotify.win32.JNotify_win32.(Unknown Source) 7 at net.contentobjects.jnotify.win32.JNotifyAdapterWin32.(Unknown Source) 这是由于jnotify找不到需要的dll或者其他库文件导致的,解决办法是把jnotify压缩包里的库文件放到java.library.path所指向的文件夹中,一般在windows下可以放在jre安装目录/bin下即可。 java.library.path的值可以通过System.getProperty(java.library.path)查看,但是你即使在程序中通过System.setProperty(java.library.path, some/folder/path/contain/dll)来改变java.library.path的值,还是无法加载到对应的dll库文件,原因是JVM只在程序加载之初读取java.library.path,以后再使用java.library.path的时候,用的都是最一开始加载到得那个值。有人认为只是一个bug,并且报告给了SUN(/bugdatabase/view_bug.do?bug_id=4280189)但是好像SUN不认为这是一个BUG。 除了把dll文件放到jre安装目录/bin下,也可以手动指定程序的启动参数: java -Djava.library.path=some/folder/path/contain/dll的方法来达到目的。 EHCache的基本使用方法 EHCache非常容易使用,首先我们要获得一个CacheManager的实例。CacheManager有两种获得方法,一种是实例模式,一种是单例模式。这里我们用后面一种: Java代码 8 /CacheManager manager = new CacheManager(src/ehcache.xml);实例模式 9 CacheManager.create();/单例模式,默认读取类路径下的ehcache.xml作为配置文件 10 Cache cache = CacheManager.getInstance().getCache(staticResourceCache); 11 /staticResourceCache在ehcache.xml中提前定义了 ehcache.xml的简单例子: Java代码 12 ehcache.xml : 13 14 15 16 20 21 然后就可以使用Cache实例来操纵缓存了,主要的方法是 Java代码 22 Cache.get(Object key),Cache.put(new Element(Object key, Object value),Cache.remove(Object key)。 缓存静态文件 首先需要扫描包含静态文件的文件夹,为了方便我们采用Jodd工具包: Java代码 23 import jodd.io.findfile.FilepathScanner; 24 . 25 FilepathScanner fs = new FilepathScanner() 26 Override 27 protected void onFile(File file) 28 cacheStatic(file);/缓存文件的函数,实现见后面 29 30 ; 31 fs.includeDirs(true).recursive(true).includeFiles(true); 32 fs.scan(Configurations.THEMES_PATH);/扫描包含静态文件的文件夹 一般来说,如果客户端浏览器接受GZip格式的文件的话,GZip压缩可以让传输的数据大幅度减少,所以考虑对某些缓存的静态文件提前进行GZip压缩。把读取到的静态文件内容缓存到Cache里,如果静态文件时可以用GZip来传输的话,需要把文件内容首先进行压缩。 Java代码 33 import java.util.zip.GZIPOutputStream;/JDK自带的GZip压缩工具 34 import jodd.io.FastByteArrayOutputStream;/GZip输出的是字节流 35 import jodd.io.StreamUtil;/JODD的工具类 36 37 private static void cacheStatic(File file) 38 if(!isStaticResource(file.getAbsolutePath() 39 return; 40 String uri = toURI(file.getAbsolutePath();/生成一个文件标识 41 FileInputStream in = null; 42 StringBuilder builder = new StringBuilder(); 43 try 44 in = new FileInputStream(file); 45 BufferedReader br = new BufferedReader( 46 new InputStreamReader(in, StringPool.UTF_8); 47 String strLine; 48 while (strLine = br.readLine() != null) 49 builder.append(strLine); 50 builder.append(n);/!important 51 52 53 FastByteArrayOutputStream bao = new FastByteArrayOutputStream(); 54 GZIPOutputStream go = new GZIPOutputStream(bao); 55 go.write(builder.toString().getBytes(); 56 go.flush(); 57 go.close(); 58 cache.put(new Element(uri, bao.toByteArray();/缓存文件的字节流 59 catch (FileNotFoundException e) 60 e.printStackTrace(); 61 catch (UnsupportedEncodingException e) 62 e.printStackTrace(); 63 catch (IOException e) 64 e.printStackTrace(); 65 finally 66 StreamUtil.close(in); 67 68 当文件改变的时候,使用JNotify来改变缓存内容 Java代码 69 /监控Configurations.THEMES_PATH指向的文件夹 70 JNotify.addWatch(Configurations.THEMES_PATH, 71 JNotify.FILE_CREATED | 72 JNotify.FILE_DELETED | 73 JNotify.FILE_MODIFIED | 74 JNotify.FILE_RENAMED, 75 true, new JNotifyListener() 76 77 Override 78 public void fileCreated(int wd, 79 String rootPath, String name) 80 cacheStatic(new File(rootPath+name);/更新缓存 81 82 83 Override 84 public void fileDeleted(int wd, 85 String rootPath, String name) 86 cache.remove(toURI(rootPath)+name);/删除缓存条目 87 88 89 Override 90 public void fileModified(int wd, 91 String rootPath, String name) 92 cacheStatic(new File(rootPath+name); 93 94 95 Override 96 public void fileRenamed(int wd, 97 String rootPath, String oldName, 98 String newName) 99 cache.remove(toURI(rootPath)+oldName); 100 cacheStatic(new File(rootPath+newName); 101 102 ); java动态缓存技术:WEB缓存应用 可以实现不等待,线程自动更新缓存 java动态缓存jar包请下载。源代码: CacheData.java 存放缓存数据的Bean/* * */package com.cari.web.cache;/* * author zsy * */public class CacheData private Object data; private long time; private int count; public CacheData() public CacheData(Object data, long time, int count) this.data = data; this.time = time; this.count = count; public CacheData(Object data) this.data = data; this.time = System.currentTimeMillis(); this.count = 1; public void addCount() count+; public int getCount() return count; public void setCount(int count) this.count = count; public Object getData() return data; public void setData(Object data) this.data = data; public long getTime() return time; public void setTime(long time) this.time = time; CacheOperation.java 缓存处理类package com.cari.web.cache;import java.lang.reflect.Method;import java.util.ArrayList;import java.util.Arrays;import java.util.Hashtable;import mons.logging.Log;import mons.logging.LogFactory;/* * author zsy */public class CacheOperation private static final Log log = LogFactory.getLog(CacheOperation.class); private static CacheOperation singleton = null; private Hashtable cacheMap;/存放缓存数据 private ArrayList threadKeys;/处于线程更新中的key值列表 public static CacheOperation getInstance() if (singleton = null) singleton = new CacheOperation(); return singleton; private CacheOperation() cacheMap = new Hashtable(); threadKeys = new ArrayList(); /* * 添加数据缓存 * 与方法getCacheData(String key, long intervalTime, int maxVisitCount)配合使用 * param key * param data */ public void addCacheData(String key, Object data) addCacheData(key, data, true); private void addCacheData(String key, Object data, boolean check) if (Runtime.getRuntime().freeMemory() 0 & (System.currentTimeMillis() - cacheData.getTime() intervalTime) removeCacheData(key); return null; if (maxVisitCount 0 & (maxVisitCount - cacheData.getCount() = 0) removeCacheData(key); return null; else cacheData.addCount(); return cacheData.getData(); /* * 当缓存中数据失效时,用不给定的方法线程更新数据 * param o 取得数据的对像(该方法是静态方法是不用实例,则传Class实列) * param methodName 该对像中的方法 * param parameters 该方法的参数列表(参数列表中对像都要实现toString方法,若列表中某一参数为空则传它所属类的Class) * param intervalTime 缓存的时间周期,小于等于0时不限制 * param maxVisitCount 访问累积次数,小于等于0时不限制 * return */ public Object getCacheData(Object o, String methodName,Object parameters, long intervalTime, int maxVisitCount) Class oc = o instanceof Class ? (Class)o : o.getClass(); StringBuffer key = new StringBuffer(oc.getName();/生成缓存key值 key.append(-).append(methodName); if (parameters != null) for (int i = 0; i 0 & (System.currentTimeMillis() - cacheData.getTime() intervalTime) daemonInvoke(o, methodName, parameters, key.toString();/缓存时间超时,启动线程更新数据 else if (maxVisitCount 0 & (maxVisitCount - cacheData.getCount() = 0) /访问次数超出,启动线程更新数据 daemonInvoke(o, methodName, parameters, key.toString(); else cacheData.addCount(); return cacheData.getData(); /* * 递归调用给定方法更新缓存中数据据 * param o * param methodName * param parameters * param key * return 若反射调用方法返回值为空则返回该值的类型 */ private Object invoke(Object o, String methodName,Object parameters, String key) Object returnValue = null; try Class pcs = null; if (parameters != null) pcs = new Classparameters.length; for (int i = 0; i parameters.length; i+) if (parametersi instanceof MethodInfo) /参数类型是MethodInfo则调用该方法的返回值做这参数 MethodInfo pmi = (MethodInfo)parametersi; Object pre = invoke(pmi.getO(), pmi.getMethodName(), pmi.getParameters(), null); parametersi = pre; if (parametersi instanceof Class) pcsi = (Class)parametersi; parametersi = null; else pcsi = parametersi.getClass(); Class oc = o instanceof Class ? (Class)o : o.getClass(); / Method m = oc.getDeclaredMethod(methodName, pcs); Method m = matchMethod(oc, methodName, pcs); returnValue = m.invoke(o, parameters); if (key != null & returnValue != null) addCacheData(key, returnValue, false); if (returnValue = null) returnValue = m.getReturnType(); catch(Exception e) log.error(调用方法失败,methodName= + methodName); if (key != null) removeCacheData(key); log.error(更新缓存失败,缓存key= + key); e.printStackTrace(); return returnValue; /* * 找不到完全匹配的方法时,对参数进行向父类匹配 * 因为方法aa(java.util.List) 与 aa(java.util.ArrayList)不能自动匹配到 * * param oc * param methodName * param pcs * return * throws NoSuchMethodException * throws NoSuchMethodException */ private Method matchMethod(Class oc, String methodName, Class pcs ) throws NoSuchMethodException, SecurityException try Method method = oc.getDeclaredMethod(methodName, pcs); return method; catch (NoSuchMethodException e) Method ms = oc.getDeclaredMethods(); aa:for (int i = 0; i ms.length; i+) if (msi.getName().equals(methodName) Class pts = msi.getParameterTypes(); if (pts.length = pcs.length) for (int j = 0; j pts.length; j+) if (!ptsj.isAssignableFrom(pcsj) break aa; return msi; throw new NoSuchMethodException(); /* * 新启线程后台调用给定方法更新缓存中数据据 * param o * param methodName * param parameters * param key */ private void daemonInvoke(Object o, String methodName,Object parameters, String key) if (!threadKeys.contains(key) InvokeThread t = new InvokeThread(o, methodName, parameters, key); t.start(); /* * 些类存放方法的主调对像,名称及参数数组 * author zsy * */ public class MethodInfo private Object o; private String methodName; private Object parameters; public MethodInfo(Object o, String methodName,Object parameters) this.o = o; this.methodName = methodName; this.parameters = parameters; public String getMethodName() return methodName; public void setMethodName(String methodName) this.methodName = methodName; public Object getO() return o; public void setO(Object o) this.o = o; public Object getParameters() return parameters; public void setParameters(Object parameters) this.parameters = parameters; public String toString() StringBuffer str = new StringBuffer(methodName); if (parameters != null) str.append(); for (int i = 0; i parameters.length; i+) if (parametersi instanceof Object) str.append(Arrays.toString(Object)parametersi).append(,); else str.append(parametersi).append(,); str.append(); return str.toString(); /* * 线程调用方法 * author zsy * */ private class InvokeThread extends Thread private Object o; private String methodName; private Object parameters; private String key; public InvokeThread(Object o, String methodName,Object parameters, String key) this.o = o; this.methodName = methodName; this.parameters = parameters; this.key = key; public void run() threadKeys.add(key); invoke(o, methodName, parameters, key); threadKeys.remove(key); /* * 移除缓存中的数据 * param key */ public void removeCacheData(String key) cacheMap.remove(key); /* * 移除所有缓存中的数据 * */ public void removeAllCacheData() cacheMap.clear(); public String toString() StringBuffer sb = new StringBuffer(* ); sb.append(正在更新的缓存数据: ); for (int i = 0; i threadKeys.size(); i+) sb.append(threadKeys.get(i).append( ); sb.append(当前缓存大小:).append(cacheMap.size().append( ); sb.append(*); return sb.toString(); 用法:例1:代码片段如下:public class Test String rulStr=.; String encoding=.; public void getData() DataCreator c = new DataCreator(); String result = c.initUrlData(urlStr,encoding); System.out.println(result); 每次执行上面代码时都要通过调用 initUrlData方法取得数据,假设此方法很耗资源而耗时间,但对数据时实性要求不高,就是可以用以下方式进行缓存处理,保证很快地取得数据,并根据设置的参数自动更新缓存中数据注意:initUrlData方法参数值一样时才属于同一个缓存,否则会生成一个新的缓存,也就是说从缓存
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025版琴行钢琴租赁合同范本含租赁押金及退还规定
- 2025年度国际物流货物安全担保合同范本
- 2025版数控机床购置及培训服务合同
- 2025年二手车维修保养与销售服务合同范本
- 2025年度企业人力资源招聘与配置服务合同
- 贵州省印江土家族苗族自治县2025年上半年事业单位公开遴选试题含答案分析
- 2025版高校期刊论文保密及成果转化协议范本
- 2025版智能砌墙技术施工合同
- 2025年度房地产开发项目营销策划执行合同示范
- 2025房地产开发股东合作协议书:产业园区共建
- (3)-2-1-药物的跨膜转运
- 幼小衔接资料合集汇总
- 八年级数学平面直角坐标系测试题
- GB/T 28575-2020YE3系列(IP55)三相异步电动机技术条件(机座号63~355)
- 储油罐有限空间作业安全技术措施表
- 传媒公司员工劳动合同(标准版)
- 缺血性肠病完整版本课件
- 《室内空间设计》第三章课件
- 学习《北方民族大学学生违纪处分规定(修订)》课件
- 设备出厂检验报告
- Matlab-Simulink模型检查验证与测试
评论
0/150
提交评论