这是我第二次写blog了。今天把我自己写的一个通用数据缓存贴出来,如有不足地方还请大家多多指教。开发过程中会碰到很多场景要大批量查询数据库中的数据,如果一个大型系统要怎么去解决这个问题,大批量用户访问,每次都访问数据库的话,那对性能的影响可想而知。
下面是代码部分
CacheDeal.java 核心处理代码
package org.zjbtiteam.cache; import java.util.Date; public class CacheDeal { private CacheEntity cache = new CacheEntity(); private long expireTime = 1200000L;// 20分钟 private long maxCacheSize = 80L; // 最大缓存数量 private Long[] longArray = new Long[]{expireTime, maxCacheSize}; private long loadtime; // 加载时间 private static CacheDeal cacheDeal = null; private JdomXmlOperator jdomXmlOperator = new JdomXmlOperator(); private Reflection reflection = new Reflection(); private CacheDeal() { } public synchronized static CacheDeal getInstance() { if (cacheDeal == null) cacheDeal = new CacheDeal(); return cacheDeal; } /** * * @param 实例对象 * @param invokeFunction 表示要调用的函数名 * @param []objValue数组 * @return * @throws Exception */ public synchronized Object getListByParams(Object obj, String invokeFunction, Object[] objValue) throws Exception { longArray = jdomXmlOperator.getCacheConfig("cache.xml"); expireTime = longArray[0]; maxCacheSize = longArray[1] * 3; StringBuilder sbuilder = new StringBuilder(); sbuilder.append(obj.getClass()); sbuilder.append(invokeFunction); sbuilder.append(CacheDeal.class.getMethod("getListByParams",new Class[]{Object.class, String.class, Object[].class})); if(objValue.length>0) { sbuilder.append(objValue.getClass()); // 被调用方法的参数类型 } for (int i = 0; i < objValue.length; i++) { sbuilder.append(objValue[i]); } String signClass = sbuilder.toString(); int index = cache.getGlobalList().indexOf(signClass); // 判断在缓存中存不存在,-1表示不存在,否者替换原来的值 if (cache.getGlobalList().contains(signClass)) { loadtime = (Long) cache.getGlobalList().get(index + 1); // 判断时间有没有超时 if (new Date().getTime() > loadtime + expireTime) { reflection.reflectionByParams(obj, invokeFunction, objValue,index - 1, "getListByParams", this, new Class[]{Object.class, String.class, Object[].class},cache); } else return cache.getGlobalList().get(index - 1); } else // 在缓存中不存在 { if (cache.getGlobalList().size() >= maxCacheSize) { cache.getGlobalList().clear(); } reflection.reflectionByParams(obj, invokeFunction, objValue, -1,"getListByParams", this, new Class[]{Object.class,String.class, Object[].class}, cache); } // 刷新索引 index = cache.getGlobalList().indexOf(signClass); return cache.getGlobalList().get(index - 1); } public synchronized void reLoadListByParams(Object obj, String invokeFunction, Object[] objValue) throws Exception { longArray = jdomXmlOperator.getCacheConfig("cache.xml"); expireTime = longArray[0]; maxCacheSize = longArray[1] * 3; StringBuilder sbuilder = new StringBuilder(); sbuilder.append(obj.getClass()); sbuilder.append(invokeFunction); sbuilder.append(CacheDeal.class.getMethod("getListByParams",new Class[]{Object.class, String.class, Object[].class})); if(objValue.length>0) { sbuilder.append(objValue.getClass()); // 被调用方法的参数类型 } for (int i = 0; i < objValue.length; i++) { sbuilder.append(objValue[i]); } String signClass = sbuilder.toString(); int index = cache.getGlobalList().indexOf(signClass); // 判断在缓存中存不存在,-1表示不存在,否者替换原来的值 if (cache.getGlobalList().contains(signClass)) { reflection.reflectionByParams(obj, invokeFunction, objValue,index - 1, "getListByParams", this, new Class[]{Object.class, String.class, Object[].class}, cache); } else // 在缓存中不存在 { if (cache.getGlobalList().size() >= maxCacheSize) { cache.getGlobalList().clear(); } reflection.reflectionByParams(obj, invokeFunction, objValue, -1,"getListByParams", this, new Class[]{Object.class,String.class, Object[].class}, cache); } } }
Reflection.java 作用是使用反射调用方法,并添加到缓存
package org.zjbtiteam.cache; import java.lang.reflect.Method; import java.util.Date; public class Reflection { public void reflectionByParams(Object obj, String invokeFunction, Object[] objValue, int oldIndex, String thisClassMethodName,Object className,Class []classes,CacheEntity cache) throws Exception { Class _class = obj.getClass(); Method method = _class.getMethod(invokeFunction, new Class[]{objValue.getClass()}); Object resultObj = method.invoke(obj, new Object[]{objValue}); StringBuilder sbuilder = new StringBuilder(); sbuilder.append(_class); sbuilder.append(invokeFunction); sbuilder.append(className.getClass().getMethod(thisClassMethodName,classes)); sbuilder.append(objValue.getClass()); // 被调用方法的参数类型 for (int i = 0; i < objValue.length; i++) { sbuilder.append(objValue[i]); } String signClass = sbuilder.toString(); this.setCacheValue(resultObj, signClass, oldIndex,cache); } /** * * @param resultObj * @param fileName * @param oldIndex * 表示CacheEntity中的list在globalList中存放的索引号 */ public void setCacheValue(Object resultObj, String fileName, int oldIndex,CacheEntity cache) { // cache.setList(list); // 判断在缓存中存不存在,-1表示不存在,否者替换原来的值 if (oldIndex == -1) cache.getGlobalList().add(resultObj); // 将单个List添加到全局的List中 else cache.getGlobalList().set(oldIndex, resultObj);// 替换原来的值 cache.getGlobalList().add(fileName); // 标志该类不带参数的方法是否已经加载了 cache.getGlobalList().add(new Date().getTime()); // 标志添加时间,定期刷新用到 } }
CacheEntity.java是个实体类
package org.zjbtiteam.cache; import java.util.ArrayList; import java.util.List; import java.util.Map; public class CacheEntity { private List globalList = new ArrayList(); private Map map; public Map getMap() { return map; } public void setMap(Map map) { this.map = map; } public List getGlobalList() { return globalList; } public void setGlobalList(List globalList) { this.globalList = globalList; } }
JdomXmlOperator.java是操作xml配置文件,这样用户就可以在xml文件中设置要不要使用缓存,及刷新时间。
package org.zjbtiteam.cache; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.jdom.Document; import org.jdom.Element; import org.jdom.input.SAXBuilder; public class JdomXmlOperator { Document doc = null; public JdomXmlOperator() { } private boolean isNumeric(String str) { Pattern pattern = Pattern.compile("[0-9]*"); Matcher isNum = pattern.matcher(str); return isNum.matches() ? true : false; } // 改变属性节点的值 protected Long[] getCacheConfig(String filename) { SAXBuilder sb = new SAXBuilder();// 建立构造器 try { doc = sb.build(JdomXmlOperator.class.getClassLoader().getResourceAsStream(filename));// 读入指定文件 } catch (Exception e) { } Element root = doc.getRootElement();// 获得根节点 List list = root.getChildren();// 将根节点下的所有子节点放入List中 final String NULLSTR = ""; long expireTime = 1200000L; long maxCacheSize = 80L; String expireTimeByConfig = null; String maxCacheSizeByConfig = null; for (int i = 0; i < list.size(); i++) { Element item = (Element) list.get(i);// 取得节点实例 if (item.getAttribute("expireTime") != null) { expireTimeByConfig = item.getAttribute("expireTime").getValue() .intern();// 取得属性值 } if (item.getAttribute("maxCacheSize") != null) { maxCacheSizeByConfig = item.getAttribute("maxCacheSize") .getValue().intern();// 取得属性值 } if (expireTimeByConfig != null && (!NULLSTR.equals(expireTimeByConfig))) { if (this.isNumeric(expireTimeByConfig)) { long longTime = Long.valueOf(expireTimeByConfig); // 如果大于0,则使用配置的的刷新时间 if (longTime >= 0) { expireTime = longTime * 60 * 1000; } } } if (maxCacheSizeByConfig != null && (!NULLSTR.equals(maxCacheSizeByConfig))) { if (this.isNumeric(maxCacheSizeByConfig)) { long cacheSize = Long.valueOf(maxCacheSizeByConfig); // 如果大于0,则使用配置的的刷新时间 if (cacheSize >= 0) { maxCacheSize = cacheSize; } } } if (maxCacheSizeByConfig != null && expireTimeByConfig != null) { break; } } return new Long[]{expireTime, maxCacheSize}; } }
cache.xml放在classpath下,配置作用
<?xml version="1.0" encoding="UTF-8"?> <configs> <!-- 如果不使用缓存技术,将expireTime设置为0,单位是分钟 --> <timeConfig expireTime="20" /> <!-- 缓存最大数量,建议在50-100之间,当达到最大数量的时候清空缓存 --> <cacheConfig maxCacheSize="80" /> </configs>
调用方式:
例如
A类调用B类的test()方法
本来是
B b=new B();
b.test(new Object[]{obj,obj,obj});
使用缓存则修改成
CacheDeal cacheDeal=org.zjbtiteam.cache.CacheDeal.getInstance();
B b=new B();
cacheDeal.getListByParams(b, "test", new Object[]{obj,obj,obj});
无参数的话就传空数组
请大家多多指教^_^!虽然写得不怎么样,但也算正版的,严重鄙视盗版!