利用Spring AOP 更新memcached 缓存策略的实现(二)
来源:互联网 发布:俄克拉荷马大学知乎 编辑:程序博客网 时间:2024/04/19 07:18
承接上文,本人终于履行承诺,实现了不使用数据库实现更新缓存的方法,上文链接:利用Spring AOP 更新memcached 缓存策略的实现(一)
实现思路:
1. 执行业务逻辑查询时,第一次在memcached中不存在,则将查询结果序列化后存入memcached中(key:业务方法名+参数类型+参数值+版本号 转 MD5),并且存入当前业务包的版本号(key:业务包名,value:版本号)
2. 执行业务逻辑查询时,检索memcached中已存在key,反序列化后返回Sevice
3. 修改操作时,修改业务逻辑之后,对应业务的包名版本号自增长,查询时重新存入memcached,原key值慢慢的慢慢的就等着死亡吧~~
具体代码:
1. 配置spring aop 查看上文
2. 下载memcached的jar包,相关方法请参考本人之前的博客:这里
3. 编写两个注解,分别为@Cache和@CacheUpdate
package com.dsideal.common;import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Inherited;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;/** * 用于查找的时候,放置缓存信息 * @author Administrator * */@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)@Documented@Inheritedpublic @interface Cache { //key的前缀 String prefix(); //缓存有效期 1000*60*60*2=2小时 long expiration() default 1000*60*60*2;}
package com.dsideal.common;import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Inherited;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited/** * 修改时标注 * @author 周枫 * */public @interface CacheUpdate { //key的前缀 String prefix();}
4. memcached的配置类为
package com.dsideal.sys.memcached;import java.util.Date;import com.danga.MemCached.MemCachedClient;import com.danga.MemCached.SockIOPool;public class MemcacheBlog { // 创建全局的唯一实例 static MemCachedClient memCachedClient=null; // 设置与缓存服务器的连接池 static{ //memcached服务器端IP和端口 String[] servers = {"192.168.100.102:11211"}; SockIOPool pool = SockIOPool.getInstance(); pool.setServers(servers); pool.setFailover(true); // 设置初始连接数、最小和最大连接数以及最大处理时间 /* pool.setInitConn(5); pool.setMinConn(5); pool.setMaxConn(250); pool.setMaxIdle(1000 * 60 * 60 * 6); */ pool.setInitConn(10); pool.setMinConn(5); pool.setMaxConn(250); pool.setMaintSleep(30); // 设置主线程的睡眠时间 // 设置TCP的参数,连接超时等 pool.setNagle(false); pool.setSocketTO(3000); pool.setAliveCheck(true); pool.initialize(); memCachedClient = new MemCachedClient(); memCachedClient.setPrimitiveAsString(true); } /** * <p>功能: * get:获取数据的方法 * get_multi:一次取得多条数据;getmulti可以非同步地同时取得多个键值, 其速度要比循环调用get快数十倍 * </p> * @author 周枫 * @date 2013-4-3 * @param * @return Object */ public static Object get(String key) { return memCachedClient.get(key); } /** * <p>功能: * add:仅当存储空间中不存在键相同的数据时才保存 * replace:仅当存储空间中存在键相同的数据时才保存 * set:与add和replace不同,无论何时都保存</p> * @author 周枫 * @date 2013-4-3 * @param * @return Object */ public static boolean set(String key,Object o) { return memCachedClient.set(key, o); } public static boolean set(String key,Object o,Date ExpireTime) { return memCachedClient.set(key, o, ExpireTime); } public static boolean exists(String key) { return memCachedClient.keyExists(key); } public static boolean delete(String key) { return memCachedClient.delete(key); } public static boolean replace(String key,Object o) { return memCachedClient.replace(key, o); } }
5. spring-aop实现类
package com.dsideal.sys.memcached;import java.lang.reflect.Method; import java.util.ArrayList;import java.util.Date; import java.util.List; import javax.annotation.Resource; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.Signature; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.stereotype.Component; import com.alibaba.fastjson.JSON;import com.dsideal.common.Cache;import com.dsideal.common.CacheUpdate;import com.dsideal.common.Flush;import com.dsideal.sys.bean.CacheLog;import com.dsideal.sys.bean.SysLoginPersonBean;import com.dsideal.sys.service.ICacheLogService;import com.dsideal.common.MD5;@Aspect @Component public class CacheAopNoMysql { // @Pointcut("execution(* add*(..)) || (execution(* del*(..))) || (execution(* get*(..)))") //* com.dsideal.sys.service.impl.*.getMemcache*(..) @Pointcut("execution (* com.dsideal.sys.service.impl.*.memcache*(..))") public void pointcut(){} //方法执行前调用 //@Before("pointcut()") public void before() { System.out.println("before"); //2 } @Resource private ICacheLogService cacheLogService; //方法执行的前后调用 @Around("pointcut()") //ProceedingJoinPoint 目标类连接点对象 public Object doAround(ProceedingJoinPoint call) throws Throwable{ //返回最终结果 Object result = null; //定义版本号,默认为1 String prefixValue = "1"; Method[] methods = call.getTarget().getClass().getDeclaredMethods(); Signature signature = call.getSignature(); MethodSignature methodSignature = (MethodSignature) signature; Method method = methodSignature.getMethod(); for(Method m:methods){ //循环方法,找匹配的方法进行执行 if(m.getName().equals(method.getName())){ //增加 if(m.isAnnotationPresent(Cache.class)){ Cache cache = m.getAnnotation(Cache.class); Object tempType = m.getGenericReturnType(); //System.out.println(m.get); //如果memcached中存在 if(cache!=null){ //获取注解前缀,这里为 sys,实际使用是为各个业务包名 String prefix = cache.prefix(); //获取版本号 if(null != MemcacheBlog.get(prefix)){ prefixValue = MemcacheBlog.get(prefix).toString(); } //获取方法名+参数类型+参数值+版本号 转 MD5 String tempKey = this.getKey(method, call.getArgs(), prefixValue); //存入memcached的最终key值 String key = prefix+"_"+tempKey; result =MemcacheBlog.get(key); if(null == result){ try { //执行aop拦截的方法 result = call.proceed(); //获取注解配置memcached死亡时间 long expiration = cache.expiration(); //1000*60*60*2==2小时过期 Date d=new Date(); //memcached死亡时间 d=new Date(d.getTime()+expiration); //利用fastjson序列化list<bean>存入memcached中 //具体fastjson使用方法请参考:http://www.cnblogs.com/cczhoufeng/archive/2013/04/03/2997871.html if(prefixValue.equals("1")){ MemcacheBlog.set(prefix, prefixValue); } MemcacheBlog.set(key, JSON.toJSONString(result), d); } catch (Throwable e) { e.printStackTrace(); } } else { //如果memcached中存在结果,需要将result反序列化后返回结果 String memresult = result.toString(); //反序列化 List<SysLoginPersonBean> list = JSON.parseArray(memresult, SysLoginPersonBean.class); result = list; //这里是利用fastjson反序列化输出的方法 //String memresult = result.toString(); //List<SysLoginPersonBean> list = JSON.parseArray(memresult, SysLoginPersonBean.class); //for (int i = 0; i < list.size(); i++) { // System.out.println(list.get(i).getReal_name()); //} } } } else if(m.isAnnotationPresent(CacheUpdate.class)){ //如果修改操作时 CacheUpdate cUpdate = m.getAnnotation(CacheUpdate.class); if(cUpdate!=null){ result = call.proceed(); String prefix = cUpdate.prefix(); //获取当前版本号 if(null != MemcacheBlog.get(prefix)){ prefixValue = MemcacheBlog.get(prefix).toString(); } //修改后,版本号+1 MemcacheBlog.replace(prefix, Integer.parseInt(prefixValue.toString()) + 1); System.out.println(MemcacheBlog.get(prefix).toString()); } }else{ try { result = call.proceed(); } catch (Throwable e) { e.printStackTrace(); } } break; } } return result; } /** * 组装key值 * @param method * @param args * @return */ private String getKey(Method method, Object [] args, String prefixValue){ StringBuffer sb = new StringBuffer(); //获取方法名 String methodName = method.getName(); //获取参数类型 Object[] classTemps = method.getParameterTypes(); //存入方法名 sb.append(methodName); for (int i = 0; i < args.length; i++) { sb.append(classTemps[i]+"&"); if (null == args[i]) { sb.append("null"); } else if ("".equals(args[i])) { sb.append("*"); } else { sb.append(args[i]); } } sb.append(prefixValue); return MD5.getMD5(sb.toString()); } }
6. MD5的实现类,见上文
7. 我做列子用的业务表,mysql数据库,见上文
8. 实体bean,见上文
9. 接口(这里我偷懒了,和上文使用的是同一个接口文件,用不到的自己过滤下吧,呵呵)
package com.dsideal.sys.service;import java.util.List;import com.dsideal.sys.bean.CacheLog;import com.dsideal.sys.bean.SysLoginPersonBean;public interface ICacheLogService { /** * <p>功能:增加memcached数据文件到临时表中</p> * @author 周枫 * @date 2013-4-9 * @param * @return void */ public void add(CacheLog log); /** * <p>功能:查询以prefix为前缀的所有key值,在更新删除时使用此方法</p> * @author 周枫 * @date 2013-4-9 * @param * @return List<CacheLog> */ public List<CacheLog> findListByPrefix(String prefix); /** * <p>功能:删除操作时,aop拦截</p> * @author 周枫 * @date 2013-4-9 * @param * @return void */ public void memcacheDeleteByPrefix(); /** * <p>功能:删除临时表记录的数据</p> * @author 周枫 * @date 2013-4-9 * @param * @return int */ public int deleteByPrefix(String prefix); /** * <p>功能:查找例子,查找所有人员数据,后面的person_id没有使用,只是为了测试key值的生成策略</p> * @author 周枫 * @date 2013-4-9 * @param * @return List<SysLoginPersonBean> */ public List<SysLoginPersonBean> memcacheFindAll(int b_use,String person_id); /** * <p>功能:测试方法,可以忽略</p> * @author 周枫 * @date 2013-4-9 * @param * @return List<CacheLog> */ public List<CacheLog> memcacheCacheLogFindAll(); /** * <p>功能:修改人员</p> * @author 周枫 * @date 2013-4-9 * @param * @return int */ public int memcacheupdateSysLoginPersonBean(String prefix,String person_id,String real_name); /** * <p>功能:不用数据库临时表更新缓存时修改人员</p> * @author 周枫 * @date 2013-4-9 * @param * @return int */ public int memcacheUpdateNoSql(String prefix,String person_id,String real_name);}
10. 接口的实现类,"sys"为业务包名,为key的前缀,expiration:自定义memcached死亡时间,版本号无死亡时间
package com.dsideal.sys.service.impl;import java.util.List;import javax.annotation.Resource;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import com.dsideal.common.Cache;import com.dsideal.common.CacheUpdate;import com.dsideal.common.Flush;import com.dsideal.sys.bean.CacheLog;import com.dsideal.sys.bean.SysLoginPersonBean;import com.dsideal.sys.dao.CacheLogDao;import com.dsideal.sys.service.ICacheLogService;@Servicepublic class CacheLogServiceImpl implements ICacheLogService { @Resource private CacheLogDao dao; @Override public void add(CacheLog log) { dao.add(log); } @Override public List<CacheLog> findListByPrefix(String prefix) { // TODO Auto-generated method stub return dao.findListByPrefix(prefix); } @Override @Flush(prefix="sys") public void memcacheDeleteByPrefix() { // TODO Auto-generated method stub } @Override public int deleteByPrefix(String prefix) { // TODO Auto-generated method stub return dao.deleteByPrefix(prefix); } @Override @Cache(prefix="sys",expiration=1000*60*60*2) public List<SysLoginPersonBean> memcacheFindAll(int b_use,String person_id) { // TODO Auto-generated method stub return dao.findAll(b_use); } @Override @Cache(prefix="sys",expiration=1000*60*60*2) public List<CacheLog> memcacheCacheLogFindAll() { // TODO Auto-generated method stub return dao.findCacheLogAll(); } @Override @Flush(prefix="sys") public int memcacheupdateSysLoginPersonBean(String prefix,String person_id,String real_name) { return dao.updateSysLoginPersonBean(person_id,real_name); } @Override @CacheUpdate(prefix="sys") public int memcacheUpdateNoSql(String prefix,String person_id,String real_name) { return dao.updateSysLoginPersonBean(person_id,real_name); }}
11. dao层
package com.dsideal.sys.dao;import org.springframework.dao.DataAccessException;import org.springframework.stereotype.Repository;import java.util.Date;import java.util.List;import com.dsideal.common.BaseDao;import com.dsideal.common.Utils.RSMapper;import com.dsideal.sys.bean.CacheLog;import com.dsideal.sys.bean.SysLoginPersonBean;@Repositorypublic class CacheLogDao extends BaseDao { public void add(CacheLog log) { try { String sql = "INSERT INTO t_cache_log(prefix,cache_key,add_time) VALUES (?,?,?)"; int result = 0; Date now = new Date(); result = this.jdbcTemplate.update(sql, log.getPrefix(),log.getCache_key(),now); System.out.println("增加成功"); } catch (DataAccessException e) { e.printStackTrace(); System.out.println("增加报错"); } } public int deleteByPrefix(String prefix) { try { String sql = "DELETE FROM t_cache_log WHERE prefix = ?"; int result = 0; result = this.jdbcTemplate.update(sql, prefix); return result; } catch (DataAccessException e) { e.printStackTrace(); } return 0; } public List<CacheLog> findListByPrefix(String prefix) { try { String sql = "SELECT * FROM t_cache_log WHERE prefix = ?"; return RSMapper.queryList(jdbcTemplate, sql, CacheLog.class, prefix); } catch (DataAccessException e) { e.printStackTrace(); } return null; } public List<SysLoginPersonBean> findAll(int b_use) { try { String sql = "SELECT * FROM t_sys_loginperson WHERE b_use = ?"; return RSMapper.queryList(jdbcTemplate, sql, SysLoginPersonBean.class,b_use); } catch (DataAccessException e) { e.printStackTrace(); } return null; } public List<CacheLog> findCacheLogAll() { try { String sql = "SELECT * FROM t_cache_log"; return RSMapper.queryList(jdbcTemplate, sql, CacheLog.class); } catch (DataAccessException e) { e.printStackTrace(); } return null; } public int updateSysLoginPersonBean(String person_id,String real_name) { int result = 0; try { String sql = "UPDATE t_sys_loginperson SET real_name = ? WHERE person_id = ?"; return this.jdbcTemplate.update(sql, real_name,person_id); } catch (DataAccessException e) { e.printStackTrace(); System.out.println("修改时报错"); } return result; }}
12. Service测试类
package com.dsideal.sys.test;import java.util.List;import org.junit.After;import org.junit.Before;import org.junit.Test;import org.junit.runner.RunWith;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.test.context.ContextConfiguration;import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;import com.dsideal.sys.bean.CacheLog;import com.dsideal.sys.bean.SysLoginPersonBean;import com.dsideal.sys.service.ICacheLogService;import com.dsideal.sys.service.impl.CacheLogServiceImpl;@RunWith(SpringJUnit4ClassRunner.class)//指定Spring的配置文件 /为classpath下@ContextConfiguration(locations = {"/spring-mvc.xml"}) public class CacheLogServiceTest { @Autowired private ICacheLogService impl; @Before //在每个测试用例方法之前都会执行 public void init(){ } @After //在每个测试用例执行完之后执行 public void destory(){ } @Test public void add() { CacheLog log = new CacheLog(); impl.add(log); } @Test public void findAll() { int b_use = 1; String person_id = ""; List<SysLoginPersonBean> list = impl.memcacheFindAll(b_use,person_id); for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i).getReal_name()); } } @Test public void deleteByPrefix() { System.out.println("1"); impl.memcacheDeleteByPrefix(); System.out.println("删除成功"); } @Test public void findCacheLogAll() { List<CacheLog> list = impl.memcacheCacheLogFindAll(); for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i).getCache_key()); } } @Test public void updateToDeleteToFind() { String prefix = "sys"; String person_id1 = "0E04DE60-7264-4FE7-9A6C-5AB843B603CC"; String person_id2 = ""; String real_name = "初中历史管理员1"; int result = impl.memcacheupdateSysLoginPersonBean(prefix, person_id1, real_name); if (result > 0) { System.out.println("修改成功"); } int b_use = 1; List<SysLoginPersonBean> list = impl.memcacheFindAll(b_use,person_id2); System.out.println("查询成功"); for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i).getReal_name()); } } @Test public void updateNoSqlToDeleteToFind() { String prefix = "sys"; String person_id1 = "0E04DE60-7264-4FE7-9A6C-5AB843B603CC"; String person_id2 = ""; String real_name = "初中历史管理员2"; int result = impl.memcacheUpdateNoSql(prefix, person_id1, real_name); if (result > 0) { System.out.println("修改成功"); } int b_use = 1; List<SysLoginPersonBean> list = impl.memcacheFindAll(b_use,person_id2); System.out.println("查询成功"); for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i).getReal_name()); } }}
具体测试方法同上文
转载地址: http://www.cnblogs.com/cczhoufeng/archive/2013/04/10/3011648.html
- 利用Spring AOP 更新memcached 缓存策略的实现(二)
- 利用Spring AOP 更新memcached 缓存策略的实现
- 利用Spring AOP 更新memcached 缓存策略的实现
- 利用Spring AOP 更新memcached 缓存策略的实现
- 利用Spring AOP 更新memcached 缓存策略的实现
- 利用Spring AOP 更新Memcached 缓存策略的实现
- 利用Spring AOP 更新memcached 缓存策略的实现(一)
- 利用Spring的aop整合redis缓存
- Spring AOP的实现策略与使用
- 搞定用Spring AOP实现的缓存
- 利用spring aop实现数据源的切换
- 利用spring的aop实现事务管理步骤
- Spring使用memcached实现缓存
- Spring Aop 实现一个简单的memcached小插件
- 利用Spring aop 自带的ehcache来缓存对象
- 探析Spring AOP(二):Spring AOP的实现机制
- Spring中AOP的实现 (二)
- spring aop的实现方式(二)
- BZOJ3993 星际战争(最大流)
- 多进程同步问题,python多进程解读
- Servlet生命周期与工作原理
- Codeforces 653D:Delivery Bears 二分+网络流
- js基础语法若干
- 利用Spring AOP 更新memcached 缓存策略的实现(二)
- ubuntu15安装vim却提示vim包不可用
- 入驻“云栖社区”
- 算法总结(第一篇)
- Checkbox 和RadioButton
- EditPlus配色方案
- 英文歌曲:Just One Last Dance(最后一支舞)
- hdoj4500小Q系列故事——屌丝的逆袭
- 关于tag值使用及注意事项