`
nj_link
  • 浏览: 10281 次
  • 性别: Icon_minigender_1
  • 来自: 厦门
社区版块
存档分类
最新评论

本地缓存实现

    博客分类:
  • java
阅读更多
最近做了个东西,使用的数据是根据元数据进行读取和加工,加工后又基本不变,使用又比较频繁。所以要用到缓存。ehcache是当对象超过配置的最大内存时才部分写入磁盘(非完整),或者配置diskPersistent=true才可以写入磁盘。当初一直以为ehcache在磁盘中读取的缓存是非完整的(重启完就没了)。当初没发现有diskPersistent这个配置,所以就自己先实现了一个简单的。
1、对序列化文件进行读写的类:
/**
 * 对缓存序列号
 * 读写内存对象到文件
 */
public abstract class FileReader {

	/**
	 * 根据key读取缓存中的数据
	 * @param key 多种组合
	 * @return 缓存对象对象
	 * @throws Exception 
	 */
	public Object read(String path) throws Exception {
		Object o = null;
		ObjectInputStream  in = null;
		try {
			//判断文件是否存在
			File file = new File(path);
			if (!file.exists()) {
				return o;
			}
			//读取缓存文件
			in = new ObjectInputStream(new FileInputStream(file));
			o = in.readObject();
		} catch (FileNotFoundException e) {
			throw new Exception("read inputstream exception", e);
		} catch (IOException e) {
			throw new Exception("red inputstream io exception", e);
		} finally {
			if (null != in) {
				try {
					in.close();
				} catch (IOException e) {
					throw new Exception("close inputstream exception", e);
				}
			}
		}
		
		return o;
	}

	/**
	 * @param key 将key当初文件名
	 * @param o 缓存的对象
	 * @throws Exception IO抛出异常
	 */
	public void write(String path, Object o) throws Exception {
		ObjectOutputStream out = null;
		FileOutputStream fout = null;
		File file;
		
		try {
			file = new File(path);
			if (!file.exists()) {
				file.createNewFile();
			}
			fout = new FileOutputStream(file);
			out = new ObjectOutputStream(fout);
			//清空输出流
			out.reset();
			//写入对象
			out.writeObject(o);
		} catch (IOException e) {
			throw new Exception("write outputstream exception", e);
		} finally {
			if (null != out) {
				try {
					out.close();
				} catch (IOException e) {
					throw new Exception("close outputstream exception", e);
				}
			}
			
			if (null != fout) {
				try {
					fout.close();
				} catch (IOException e) {
					throw new Exception("close outputstream exception", e);
				}
			}
		}
	}
}


2、关键的缓存类:
/**
 * 数据内存缓存,同时写入缓存文件,用于重启服务时内存数据消失时读取
 * 此处不用ehcache,因为ehcache需要读取配置,不能及时存入缓存文件,只是部分存放。
 */
public class MpCache extends FileReader {
	private static MpCache mpCache = new MpCache();
	private static Map<CacheKey, Cache> contents;
	private static String path;
	private static State state;
	
	static {
		path = System.getProperty("java.io.tmpdir");
		contents = new HashMap<CacheKey, Cache>();
		state = State.getInstance();
	}
	
	//这是个单例
	public static MpCache getInstance() {
		return mpCache;
	}
	
	/**
	 * 存入缓存数据,同时更新缓存文件
	 * @param k
	 * @param v
	 * @throws Exception
	 */
	public synchronized void put(CacheKey k, Cache v) throws Exception {
		contents.put(k, v);
		write(k, v);
	} 
	
	/**
	 * 读取缓存数据
	 * @param key
	 * @return
	 * @throws Exception
	 */
	public Cache get(CacheKey k) throws Exception {
		Cache c = contents.get(k);
		
		if (null == c && !state.hasSync(k)) {
			c = read(k);
			contents.put(k, c);
		}
		
		return c;
	}
	
	/**
	 * 根据key读取缓存中的数据
	 * @param key 多种组合
	 * @return 缓存对象对象
	 * @throws Exception 
	 */
	private Cache read(CacheKey k) throws Exception {
		String key = k.getKey();
		String p = path.concat(key).concat(".dat");
		Cache c = (Cache) super.read(p);
		return c;
	}

	/**
	 * @param key 将key当初文件名
	 * @throws Exception IO抛出异常
	 */
	private void write(CacheKey k, Object o) throws Exception {
		String key = k.getKey();
		String p = path.concat(key).concat(".dat");
		super.write(p, o);
	}

	public void clear() {
		contents.clear();
		state.clear();
	}
}

3、状态类,对应内存对象是否已经从磁盘中读取过。

/**
 * 文件状态和内存对象是否同步
 */
public class State extends FileReader {
	private static State state = new State();
	private static Map<String, Boolean> map = new HashMap<String, Boolean>();
	
	/**
	 * 
	 * @param key
	 * @return
	 */
	public boolean hasSync(CacheKey key) {
		String k = key.getKey();
		Boolean v = map.get(k);
		if (null == v) {
			//设置已经被同步
			map.put(k, true);
			//返回未同步
			return false;
		}
		
		return v;
	}

	public static State getInstance() {
		return state;
	}

	public void clear() {
		map.clear();
	}
	
}

4、存放的对象需要实现的接口

/**
* 缓存顶层接口
*/
public interface Cache {
CacheKey getCacheKey();
}



5、缓存唯一标识接口
public interface Key {
String getKey();
}

6、缓存唯一标识类
/**
* 存放key值 , 重写hashcode 比较方法
*/
public class CacheKey implements Key,Serializable{
private static final long serialVersionUID = 1L;
//目前只存放属性
private String type;

/**
* 比较文件中的缓存是否是同一个
*/
public boolean equals(Object o) {
if (getKey() == null) {
throw new CacheException("cachekey 不能为空.");
}
if (this == o) {
return true;
}
if (!(o instanceof Key))
return false;

Key otherCache = (Key) o;
return getKey().equals(otherCache.getKey());
}

/**
* hashmap是根据hashcode为key获取数据
* 重写这个方法以取得需要的key对应的数据
*/
public int hashCode() {
if (getKey() == null) {
throw new CacheException("cachekey 不能为空.");
}
return getKey().hashCode();
}

/**
* 仓库编号,包编号,类编号
* @return 唯一key
*/
public String getKey() {
return type;
}

public String getType() {
return type;
}

public void setType(String type) {
this.type = type;
}

}

7、需要缓存的对象
public class Content implements Cache,Serializable {
private static final long serialVersionUID = 6963213185510643340L;
//缓存对象的key, 各种类型的缓存
private CacheKey key;
        private Object obj;

        public String getKey() {
return key.getKey();
}

        public void setObject(Object obj) {
             this.obj = obj;
        }
}
8、最后写一个注册类方便调用
/**
* 注册缓存,将组装完的数据放入内存
* 单服务器用, 多服务器(分布式)时将不可用,文件都不知道在哪个服务器上没有同步。
*/
public class Register {
//整个会话都保存唯一的一个缓存变量
private static MpCache mPcache = MpCache.getInstance();

/**
* 注册解析的内存对象到缓存(全局)
* @throws Exception
*/
public static void regist(Cache c) throws Exception {
CacheKey k = c.getCacheKey();
mPcache.put(k, c);
}

/**
* 根据key值获取缓存对象
* @param key
* @return
* @throws Exception
*/
public static Cache getCache(CacheKey key) throws Exception {
return mPcache.get(key);
}

/**
* 清空缓存对象
*/
public static void clear() {
mPcache.clear();
}
}

话外:分布式缓存也可以用ehcache,或者用mencache。
分享到:
评论

相关推荐

    Java中LocalCache本地缓存实现代码

    本篇文章主要介绍了Java中LocalCache本地缓存实现代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

    Java利用ConcurrentHashMap实现本地缓存demo

    Java利用ConcurrentHashMap实现本地缓存demo; 基本功能有缓存有效期、缓存最大数、缓存存入记录、清理线程、过期算法删除缓存、LRU算法删除、获取缓存值等功能。 复制到本地项目的时候,记得改包路径哦~

    spring简单的缓存

    利用spring实现的简单的缓存的例子,代码解释:http://blog.csdn.net/maoyeqiu/article/details/50238035

    微信小程序基于本地缓存实现点赞功能的方法

    本文实例讲述了微信小程序基于本地缓存实现点赞功能的方法。分享给大家供大家参考,具体如下: wxml中的写法 注意: 1. 使用wx:if={{condition}} wx:else实现图标的切换效果; 2. 为图片绑定点击事件bindtap=to...

    带有本地缓存机制的http连接框架

    非常方便好用的http连接框架,可以方便的发起连接,所有连接的结果都会保存在本地,下次调用时直接从本地读取

    JS localStorage实现本地缓存的方法

    JS localStorage实现本地缓存的方法,需要的朋友可以参考一下

    kotlin-cache:本地缓存实现

    Kotlin缓存Kotlin中的缓存实现可以在代码中本地使用。 这个想法是要消除开发人员为每个项目创建的恒定缓存。 当前实现:永久性快取永久缓存是一个简单的缓存,它将无限期保存该值。用法val cache = PermanentCache ...

    Java本地缓存的实现代码

    本篇文章主要介绍了Java本地缓存的实现代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

    uni-app用sqlite数据库本地缓存

    使用sqlite数据库本地缓存

    java手写本地缓存示例

    基于java的map和timer实现本地缓存及定时清理失效缓存的功能 本项目仅用于初学者学习使用 初学者可基于此项目初步了解缓存实现的基本原理 后期在项目中使用建议使用现成的缓存框架:redis、ehcache等

    实现 Java 本地缓存的方法解析

    主要介绍了实现 Java 本地缓存的方法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

    DurianCoder#springboot-example#Springboot集成GuavaCache实现本地缓存1

    Springboot集成本地缓存Guava本章介绍一个比较好用的本地缓存Guava0x01、添加依赖0x02、添加GuavaLocalCache提供了设置超时时

    ListView实现图片在本地缓存

    一个ListView异步加载并实现图片在本地缓存的例子。

    高速缓存文件读写.cpp

    操作系统实验之第二高速缓存方式实现文件读写操作。

    c#K-V本地缓存

    c#版本的本地缓存,K-V缓存,实现一般缓存接口。实现FIFO,LRU,LFU策略。通过配置类设置缓存信息,主要设置maxcachesize,cachetime

    如何基于LoadingCache实现Java本地缓存

    主要介绍了如何基于LoadingCache实现Java本地缓存,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

    JSP页面缓存cache技术–浏览器缓存介绍及实现方法

    一、概述 缓存的思想可以应用在软件分层的各个层面。它是一种内部机制,对外界而言,是不可感知的。 数据库本身有缓存,持久层也可以缓存...二、缓存实现(浏览器缓存当前访问的JSP动态页面) (一)、服务端方法: 代

    本地缓存之王Caffeine 保姆级教程(值得珍藏)

    自Spring 5开始,Caffeine已成为默认的缓存实现,取代了原先的Google Guava。官方资料显示,Caffeine的缓存命中率已接近理论最优值。实际上,Caffeine与ConcurrentMap在功能上有许多相似之处,都支持并发操作,且...

    android实现清理缓存功能

    android之清理缓存实现,供大家参考,具体内容如下 一. 清理缓存首先要搞清楚清理哪些东西 1、app本身的功能比如录像,录音,更新都会产生文件,需要清理 2、app的默认缓存地址cache 二. 搞清楚要清理的文件夹位置 1、...

Global site tag (gtag.js) - Google Analytics