使用 AOP 和注解实现方法缓存(上)
2016-09-25 本文已影响474人
ByteBlade
前言
做web开发中,提高系统效率,经常用到缓存操作。但是代码中到处都是Cache的操作,为了提高代码的质量,在大神的指导下使用面向切面编程,提供一个基于Method的统一的Cache切入功能。
启用@AspectJ支持
通过在你的Spring的配置中引入下列元素来启用Spring对@AspectJ的支持:
<aop:aspectj-autoproxy/>
自定义一个Cache注解
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
public @interface Cache {
/** * 缓存过期时间,单位是秒 */
int expire() default 10;
}
完成切面
使用注解来创建切面,around方法获取缓存值,如果没有命中到缓存值。应该调用目标函数,通过目标函数计算实际值。
@Aspect
@Component
public class CacheIntercepter{
@Around("@annotation(com.spring.aop.annoation.Cache)")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
if (joinPoint == null) {
return null;
}
String key = getKey(joinPoint);
CacheClient client = new CacheClient();
String clientValue = client.getValue(key);
if (clientValue != null) {
return clientValue;
}
//如果没有命中到缓存值。应该调用目标函数,通过目标函数计算实际值。
return joinPoint.proceed();
}
/**
* 根据参数生成cachekey
* @param joinPoint
* @return
*/
private String getKey(ProceedingJoinPoint joinPoint) {
String result = "";
if (joinPoint.getArgs() == null) {
return result;
}
for (Object key : joinPoint.getArgs()) {
if (key != null) {
result += "_" + key.toString();
}
}
return result;
}
}
缓存客户端的实现
为简化起见,假设key为空值的时候,缓存值为null;
public class CacheClient {
public String getValue(String key){
if (key == null || "".equals(key)) {
System.out.println("未命中cache");
} else {
System.out.println("命中cache");
return "success";
}
return null;
}
}
测试用咧
public class CacheTest extends AbstractTest{
@Autowired
private UserService userService;
@Test
public void test(){
{
String cache_result = userService.getId("12");
System.out.println("命中cache的结果:"+cache_result);
}
{
String uncache_result = userService.getId(null);
System.out.println("未命中cache的结果:"+uncache_result);
}
}
}
运行结果
命中cache
命中cache的结果:success
未命中cache
未命中cache的结果:我的计算值
第一版的代码请移步github,注意是feature-aspectj-aop分支。