java文件读取缓存类
流程图:
<pre>
final 外部对象操作时:
通过文件名 -- 在map中找到对应 -- 判断是否修改 --否 -- 返回缓存对象
|
是
|
调用reload,根据传入的handler进行reload,更新缓存对象,更新操作时间
</pre>
主要根据的是文件的修改时间,如果本次读取时的修改时间和缓存中的时间相同,则直接返回缓存,否则的话就重新加载文件,更新缓存和时间
重新加载文件的时候需要传入一个 ReloadHandler,以实现更大的灵活性(策略模式),返回一个新的对象并缓存
(待完善:自动清理功能
方案1:FIFO 最简单,但是效率比较低
方案2:访问次数多的留下,少的去掉
方案3:记得大学里编译原理有个更好的方式,忘记了。
)暂时用FIFO
接口:
/** * 重新加载接口 * @author qihuan * */public interface ReloadHandler { /** * 分析文件 * @return 要缓存的内容 */ Object processNewCache() throws Exception;}
/** * <pre> * final 外部对象操作时: * 通过文件名 -- 在map中找到对应 -- 判断是否修改 --否 -- 返回缓存对象 * | * 是 * | * 调用reload,根据传入的handler进行reload,更新缓存对象,更新操作时间 * </pre> * @author qihuan */public class FileCache { /** 缓存map */ private static Map<String, CacheElement> cacheMap = new HashMap<String, CacheElement>(); private static FileCache fileCache; private static final int MAX_SIZE = 20; private Queue<String> fileQueue = new LinkedList<String>(); /** * 单例,多线程一样自信 * * @return fileCache单例 */ public static FileCache getInstance(){if(null == fileCache){ fileCache = new FileCache();}return fileCache; } /** * 获取缓存对象 * 获取缓存,如果文件被修改,则重新加载最近配置,内存中超过20个文件缓存,会自动清理 * @param fileName * @return * @throws Exception */ public Object getCache(String fileName,ReloadHandler handler) throws Exception{fileName = fileName.trim();if(isModified(fileName)){ reLoad(fileName,handler);}return cacheMap.get(fileName).getCache(); } /** * 重新加载 * @param fileName * @param handler * @throws Exception */ private void reLoad(String fileName, ReloadHandler handler) throws Exception {CacheElement ele = cacheMap.get(fileName);if(null == ele){ //文件没有加载过 ele = new CacheElement(); //设置File对象 ele.setFile(new File(fileName)); cacheMap.put(fileName, ele); //添加新的缓存,记录到队列中 if(!fileQueue.contains(fileName)){//如果队列中没记录这个,则试图添加并进行清理cacheClean();fileQueue.add(fileName); }}//更新缓存ele.setCache(handler.processNewCache());//更新修改时间ele.setLastEditTime(ele.getFile().lastModified()); } /** * 判断是否已经修改 * * @param diXmlName * @return */ private boolean isModified(String fileName) {CacheElement cacheElement = cacheMap.get(fileName);if (null == cacheElement) { //配置文件没有被加载过 return true;}if (cacheElement.getFile().lastModified() != cacheElement.getLastEditTime()) { //被修改 return true;}// 没有变化return false; } /** * FIFO 清理缓存, */ private void cacheClean(){//缓存超过限制之后,进行清理if(fileQueue.size() >= MAX_SIZE ){ String fileName = fileQueue.poll(); cacheMap.put(fileName, null); cacheMap.remove(fileName);} } //私有构造 private FileCache(){} /** * 缓存元素 * * @author qihuan */ class CacheElement {public long lastEditTime;public File file;public Object cache;public long getLastEditTime() { return lastEditTime;}public void setLastEditTime(long lastEditTime) { this.lastEditTime = lastEditTime;}//setters and getters... }}
测试类:/*** 每2秒去获取一次缓存日期,如果文件更新了,则会返回新的缓存日期*/public class CacheTest { @Test public void getFileContent() { int count = 10; while (count-- > 0) { try { getCache(); TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } } private void getCache() throws Exception { Date date = (Date)FileCache.getInstance().getCache("e:/1.txt", new ReloadHandler() { @Override public Object processNewCache() { System.out.print("find change "); return new Date(); } }); System.out.println(date); }}output:find change Wed Dec 28 15:25:46 CST 2011 (初始化)Wed Dec 28 15:25:46 CST 2011Wed Dec 28 15:25:46 CST 2011Wed Dec 28 15:25:46 CST 2011Wed Dec 28 15:25:46 CST 2011find change Wed Dec 28 15:25:56 CST 2011Wed Dec 28 15:25:56 CST 2011Wed Dec 28 15:25:56 CST 2011Wed Dec 28 15:25:56 CST 2011Wed Dec 28 15:25:56 CST 2011
/** * 获取配置 * * @param diXmlName * 接口配置文件名称 * @param diXmlPath * 接口配置文件完整路径 * @return * @throws DataConfigException */ public DataInterfaceConfig getConfig(final String diXmlName) throws DataConfigException {DataInterfaceConfig config = null;final String diXmlPath = Constant.CONFIG_HOME + File.separator + "diConfig" + File.separator + diXmlName;try { config = (DataInterfaceConfig) FileCache.getInstance().getCache(diXmlPath, new ReloadHandler() { @Override public Object processNewCache() throws Exception { //重新加载配置文件 return DataInterfaceConfigParser.parser(diXmlPath); } });} catch (Exception e) { throw new DataConfigException(e);}return config; }
/** * 从缓存中 根据code 获取 接口配置 * @param code * @return * @throws BizException */ public DataInterface getDataInterfaceByCode(String code) throws BizException{Map<String,DataInterface> dataInterface = null;//获取缓存 try {dataInterface = (Map<String,DataInterface>) FileCache.getInstance().getCache(Constant.CONFIG_HOME + File.separator + Constant.DIGROUP_CONFIG_XML, new ReloadHandler() { @Override public Object processNewCache() throws Exception {return getAllConfigInGroup(); }}); } catch (Exception e) {throw new BizException(e); }return dataInterface.get(code); }