您的位置:首页 > 数据库 > Memcache

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层调用,否则会出现缓存同步问题。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: