您的位置:首页 > 编程语言 > ASP

spring aop aspect + annotation实现缓存命中判断

2016-06-02 14:22 603 查看
    最近看到了一种使用aop和注解的方式实现缓存命中判断的实现方式,觉得非常不错。借鉴过来,进行分享。

    1、引入spring和aspect相关依赖

<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.6</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.6</version>
</dependency>
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>


2、创建Cache注解类,用于标识需要添加缓存的方法。

@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Cache {
//缓存时间,默认60秒
int expire() default 60;

//缓存实体类型
Class<?> clazz();

//缓存中存放的具体类型
CacheType cacheType();

}


3、创建CacheType类,标识缓存的类型,目前仅有Object和List两种,其他的可以根据项目的需求自己添加。

public enum CacheType {
OBJECT,
LIST,
;
}


4、创建Cache切面类,用于解析Cache注解,实现缓存命中判断。

public class CacheAspect {

private Logger logger = LoggerFactory.getLogger(CacheAspect.class);

public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
MethodSignature ms = (MethodSignature)pjp.getSignature();
Method method = ms.getMethod();
Cache annotation = method.getAnnotation(Cache.class);

//获取注解信息
int expire = annotation.expire();
Class<?> clazz = annotation.clazz();
CacheType cacheType = annotation.cacheType();

//获取类名、方法名、参数名
String className = pjp.getTarget().getClass().getSimpleName();
String methodName = pjp.getSignature().getName();
Object[] args = pjp.getArgs();
StringBuffer sb = new StringBuffer();
for(Object arg : args) {
if(arg != null) {
sb.append("_").append(arg.toString());
}
}
//用类名、方法名、参数名作为缓存的key
String cacheKey = className.concat("_").concat(methodName).concat(sb.toString());
Object obj = CacheUtils.getFromCache(cacheKey, clazz, cacheType);
//命中缓存,直接返回信息
if(obj != null) {
logger.info("cache hit for key:"+cacheKey);
return CallResult.success(obj);
} else {
//未命中缓存,查询结果,并放到缓存中
CallResult result = (CallResult)pjp.proceed();
if(result.isSuccess()) {
logger.info("put to cache for key:"+cacheKey);
CacheUtils.put2Cache(cacheKey, result.getResultObject(), expire);
}
return result;
}
}
}


5、缓存添加、获取实现类,该例子仅使用内存作为缓存,在实际的项目中,可能会使用redis、memcache等缓存。

public class CacheUtils {

private static Logger logger = LoggerFactory.getLogger(CacheUtils.class);

private static ConcurrentHashMap<String, String> map = new ConcurrentHashMap<String, String>();

public static void put2Cache(String key, Object result, int expire) {
String str = JSON.toJSONString(result);
map.put(key, str);
}

public static Object getFromCache(String key, Class clazz, CacheType cacheType) {
try {
String result = map.get(key);
if(StringUtils.isNotBlank(result)) {
if(CacheType.LIST.equals(cacheType)) {
List list = JSON.parseObject(result, List.class);
List retList = new ArrayList();
for(Object obj : list) {
retList.add(JSON.parseObject(obj.toString(), clazz));
}
return retList;
} else {
return JSON.parseObject(result, clazz);
}
}
} catch (Exception e) {
logger.error("getFromCache exception",e);
}
return null;
}
}


6、spring配置文件:

<aop:aspectj-autoproxy proxy-target-class="true" />

<bean id="cacheService" class="com.demo.lizhy.service.impl.CacheServiceImpl" />

<bean id="cacheAspect" class="com.demo.lizhy.service.aspect.CacheAspect" />
<aop:config>
<aop:aspect ref="cacheAspect">
<aop:around method="<strong>doAround</strong>" pointcut="@annotation(com.demo.lizhy.service.aspect.Cache)" />
</aop:aspect>
</aop:config>



<aop:aspectj-autoproxy />有一个proxy-target-class属性,默认为false,表示使用jdk动态代理织入增强,当配为<aop:aspectj-autoproxy  poxy-target-class="true"/>时,表示使用CGLib动态代理技术织入增强。不过即使proxy-target-class设置为false,如果目标类没有声明接口,则spring将自动使用CGLib动态代理。


7、实际使用:CacheService

public class CacheServiceImpl implements CacheService {
private Logger logger = LoggerFactory.getLogger(CacheServiceImpl.class);
@Override
@Cache(expire = 100, clazz = String.class, cacheType = CacheType.OBJECT)
public CallResult<String> getCacheInfo(String name) {
logger.info("search from db=========");
return CallResult.success(name);
}
}


注意:

JoinPoint:提供访问当前被通知方法的目标对象、代理对象、方法参数等数据:

ProceedingJoinPoint:用于环绕通知,使用proceed()方法来执行目标方法:
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  spring aop annotation aspect