Memcache+Spring AOP
2016-06-02 14:56
323 查看
<aop:aspectj-autoproxy proxy-target-class='false'/>
proxy-target-class属性值决定是基于接口的还是基于类的代理被创建。
如果proxy-target-class 属性值被设置为true,那么基于类的代理将起作用(这时需要cglib库)。
如果proxy-target-class属值被设置为false或者这个属性被省略,那么标准的JDK 基于接口的代理将起作用。
package org.digdata.swustoj.aop.cache; import java.lang.reflect.Method; import java.util.List; import java.util.Map; import org.apache.log4j.Logger; import org.aspectj.lang.ProceedingJoinPoint; 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.digdata.swustoj.base.IMemCacheTemplate; import org.digdata.swustoj.model.CacheAccess; import org.digdata.swustoj.model.CacheFlush; import org.digdata.swustoj.util.ClassUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; /** * * @author wwhhf * @since 2016年6月1日 * @comment 缓存切面管理 order值越小,顺序越高 cacheKey->className.methodName(args).version * cacheValue->data versionKey->className.version cacheValue->Integer */ @Order(2) @Aspect @Component public class MemCacheAspect { private static Logger logger = Logger.getLogger(MemCacheAspect.class); private static final Class VERSION_KEY_TYPE = Long.class; private static final String VERSION_SUFFIX = "version"; @Autowired private IMemCacheTemplate iMemCacheTemplate = null; /** * * @author wwhhf * @since 2016年6月2日 * @comment 修改方法 */ @Pointcut("execution(* org.digdata.swustoj.mybatis.dao.impl.*.*(..)) " + "|| execution(* org.digdata.swustoj.service.impl.*.*(..)) ") public void methods() { } /** * * @author wwhhf * @since 2016年6月1日 * @comment 先进行访问缓存,若命中则直接返回,否则继续执行方法 * @param joinpoint * @throws Throwable */ @Around("methods()") public Object cacheAccess(ProceedingJoinPoint joinpoint) throws Throwable { String clazzName = joinpoint.getTarget().getClass().getName(); String methodName = joinpoint.getSignature().getName(); Object[] args = joinpoint.getArgs(); Method method = ((MethodSignature) joinpoint.getSignature()) .getMethod(); boolean hasAnnotation = method.isAnnotationPresent(CacheAccess.class); if (hasAnnotation) {// 存在需要缓存数据的注解 String version_key = getVersionKey(clazzName);// 获取缓存版本号的key Long version_value = (Long) this.iMemCacheTemplate.getObject( version_key, VERSION_KEY_TYPE); // 获取缓存版本号 if (version_value == null) { // 版本号过期了,重新建立缓存版本号,该类以前的缓存全部过期 this.iMemCacheTemplate.set(version_key, version_value = getNextVersionValue());// 重新设置缓存版本号 System.out.println("缓存初始化: " + version_key + " -> " + version_value); String cache_key = ClassUtil.getMethodInfo(clazzName, methodName, args, version_value);// 获得缓存的key // ============================================ Object cache_value = joinpoint.proceed(args);// 缓存未命中 // ============================================ System.out.println("缓存未命中: " + cache_key); this.iMemCacheTemplate.set(cache_key, cache_value);// 缓存数据 return cache_value; } else {// 版本号未过期,查询该类此版本的缓存 CacheAccess annotation = method .getAnnotation(CacheAccess.class);// 获得注解 Class clazz = annotation.type(); // 获得json的class String cache_key = ClassUtil.getMethodInfo(clazzName, methodName, args, version_value);// 获得cache_key Object cache_value = null; if (clazz == String.class) { // String cache_value = this.iMemCacheTemplate.getString(cache_key); } else if (clazz == List.class) { // List Class subClazz = annotation.subType(); cache_value = this.iMemCacheTemplate.getList(cache_key, subClazz); } else if (clazz == Map.class) { // Map cache_value = this.iMemCacheTemplate.getMap(cache_key); } else { // Object cache_value = this.iMemCacheTemplate.getObject(cache_key, clazz); } if (cache_value == null) { // 缓存未命中,需要缓存数据 System.out.println("缓存未命中: " + cache_key); // ==================================== cache_value = joinpoint.proceed(args); // ==================================== this.iMemCacheTemplate.set(cache_key, cache_value); } else { // 缓存命中 System.out.println("缓存命中: " + cache_key); } return cache_value; } } else {// 不存在注解 return joinpoint.proceed(args); } } /** * * @author wwhhf * @since 2016年6月1日 * @comment 先进行缓存清除,再执行方法 * @param joinpoint * @throws Throwable */ @Around("methods()") public Object cacheFlush(ProceedingJoinPoint joinpoint) throws Throwable { String clazzName = joinpoint.getTarget().getClass().getName(); Object[] args = joinpoint.getArgs(); Method method = ((MethodSignature) joinpoint.getSignature()) .getMethod(); boolean hasAnnotation = method.isAnnotationPresent(CacheFlush.class); if (hasAnnotation) {// 存在清除缓存的注解 improveVersion(clazzName);// 提高缓存的版本号 } return joinpoint.proceed(args); } /** * @author wwhhf * @since 2016年6月5日 * @comment 提高相应类的版本 * @param clazzName */ private void improveVersion(String clazzName) { // 获取缓存版本号的key String version_key = getVersionKey(clazzName); // 获取缓存版本号 Long version = (Long) this.iMemCacheTemplate.getObject(version_key, VERSION_KEY_TYPE); if (version != null) { // 版本号过期则不管,让查询统一处理 // 版本号未过期,提高版本号 this.iMemCacheTemplate.set(version_key, version = getNextVersionValue()); System.out.println("缓存版本提高: " + version_key + " -> " + version); } } /** * * @author wwhhf * @since 2016年6月2日 * @comment 获取类名对应的缓存版本号 * @param className * @return */ private String getVersionKey(String className) { StringBuffer sb = new StringBuffer(className).append(".").append( VERSION_SUFFIX); return sb.toString(); } /** * * @author wwhhf * @since 2016年6月2日 * @comment 获取类名对应的下一次的缓存版本号(时间戳) * @param className * @return */ private Long getNextVersionValue() { return System.currentTimeMillis(); } }
package org.digdata.swustoj.model; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * * @author wwhhf * @since 2016年6月1日 * @comment 表示该方法需要先进行缓存清除,再执行该方法 */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @Documented public @interface CacheFlush { }
/** * * @author wwhhf * @since 2016年5月26日 * @comment 条件查询标签 * @param search_ids * @param search_name * @param condition * @param page * @param rows * @return */ @CacheAccess(type = List.class, subType = Tags.class) public List<Tags> selectTags(List<Integer> search_ids, String search_name, String condition, Integer page, Integer rows); /** * * @author wwhhf * @since 2016年5月26日 * @comment 条件查询标签的数量 * @param search_ids * @param search_name * @param condition * @param page * @param rows * @return */ @CacheAccess(type = Integer.class) public Integer selectTagsNum(List<Integer> search_ids, String search_name, String condition); /** * * @author wwhhf * @since 2016年5月26日 * @comment 批量删除标签 * @param tids * @return */ @CacheFlush public Boolean deleteTags(List<Integer> tids); /** * * @author wwhhf * @since 2016年5月26日 * @comment 添加标签 * @param record * @return */ @CacheFlush public Boolean insertTags(Tags record); /** * * @author wwhhf * @since 2016年5月26日 * @comment 更新标签 * @param record * @return */ @CacheFlush public Boolean updateTags(Tags record);
原先版本的缓存策略:Mybatis一级缓存+mysql自身缓存
现版本缓存策略:memcache+原版本
时间对比:
原:400多ms
现:160左右ms
不足
service层缓存建议不使用:service调用别的dao层的修改方法,一定要通过service层调用,否则会出现缓存同步问题。相关文章推荐
- key/value存储系统-Memcached、Redis、Tair
- 编译PHP-memcache扩展
- Nginx+Tomcat+MemCached 集群配置手册
- CentOS release 6.5下安装php-memcached
- Memcached的MemCachedClient设置过期时限
- MemcacheClient 封装
- MemcacheClient设置过期时间
- CentOS环境PHP下安装memcache扩展
- 关于Memcache mutex设计模式的.net实现
- 分布式缓存集群方案特性使用场景(Memcache/Redis(Twemproxy/Codis/Redis-cluster))优缺点对比及选型
- Redis和Memcache性能测试对比
- Linux下安装配置MemCached(以及libevent)
- 个人画的第一幅图memcached
- memcached在windows下的安装与命令使用方法
- Memcache安全问题
- Memcached 安装配置
- 160530、memcached集群(spring集成的配置)
- Ubuntu server 11.04安装memcache及php使用memcache来存储session的方法
- Memcached缓存系统的介绍、安装以及应用方法详解
- windows下Nginx+memcached+Tomcat集群搭建