文档章节

AOP面向切入实现service层嵌入缓存

vill_520
 vill_520
发布于 2015/12/24 20:38
字数 546
阅读 687
收藏 32
//放入缓存注解

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Inherited
public @interface Cacheable { //放入
    String key(); //缓存key

    String fieldKey();// field值

    int expireTime() default 3600;
}
//从缓存中销毁注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface CacheEvict { //销毁
    String key();

    String[] fieldKey();

    int expireTime() default 3600;
}

Aspect类
//环绕切入
@Around(value = "@annotation(com.xx.cache.annotation.Cacheable)")
    public Object cache(ProceedingJoinPoint pjp) {
        Object result = null;

        Method method = getMethod(pjp);
        Cacheable cacheable = method.getAnnotation(Cacheable.class);
        String fieldKey = cacheable.fieldKey();
        if (cacheable.fieldKey().indexOf("#") == 0) {//动态变量存入方式
            fieldKey = parseKey(cacheable.fieldKey(), method, pjp.getArgs());
        }

        if (useCache) {//判断是否开启缓存 开启缓存 从缓存获取 result
            //获取方法的返回类型,让缓存可以返回正确的类型
            Class returnType = ((MethodSignature) pjp.getSignature()).getReturnType();
            //使用redis 的hash进行存取,易于管理
//        result = JedisUtils.hget(cacheable.key(), fieldKey,method.getReturnType());
            result = JedisUtils.hget(cacheable.key(), fieldKey, returnType);
            if (result == null) {
                try {
                    result = pjp.proceed();
//          Assert.notNull(fieldKey);
                    JedisUtils.hset(cacheable.key(), fieldKey, result);
                    logger.debug("The " + cacheable.key() + " add to redis, the fieldKey is " + fieldKey);
                } catch (Throwable e) {
                    e.printStackTrace();
                }
            }
            return result;
        }
        try {
            return pjp.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            return null;
        }
    }
    
//环绕切入
@Around(value = "@annotation(com.xx.cache.annotation.CacheEvict)")
public Object evict(ProceedingJoinPoint pjp) {
    //和cache类似,使用Jedis.hdel()删除缓存即可
    if (useCache) {//判断是否开启缓存
        Method method = getMethod(pjp);
        CacheEvict cacheEvict = method.getAnnotation(CacheEvict.class);
        String[] fieldKeys = cacheEvict.fieldKey();
        int deleteSuccessFlag = 0;
        for (String fieldKey : fieldKeys) {
            if (fieldKey.indexOf("#") == 0) {//动态变量存入方式
                String t = fieldKey;
                fieldKey = parseKey(fieldKey, method, pjp.getArgs());
                if (fieldKey == null) {
                    logger.error("cache evict fieldkey {} connot be null, that may be cause data connot sync ", t);
                    t = null;
                }
            }
            deleteSuccessFlag += JedisUtils.hdel(cacheEvict.key(), fieldKey == null ? "" : fieldKey);
            logger.debug("The reference fieldkey: " + fieldKey + " for " + cacheEvict.key() + " has been delete from redis");
        }
        logger.debug("Delete " + deleteSuccessFlag + " " + cacheEvict.key() + "from redis");
    }

    try {
        return pjp.proceed();
    } catch (Throwable e) {
        e.printStackTrace();
        return null;
    }
}

/**
 * 获取缓存的key
 * key 定义在注解上,支持SPEL表达式
 *
 * @param key
 * @param method
 * @param args
 * @return
 */
private String parseKey(String key, Method method, Object[] args) {
    //获取被拦截方法参数名列表(使用Spring支持类库)
    LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer();
    String[] paraNameArr = u.getParameterNames(method);
    //使用SPEL进行key的解析
    ExpressionParser parser = new SpelExpressionParser();
    //SPEL上下文
    StandardEvaluationContext context = new StandardEvaluationContext();
    //把方法参数放入SPEL上下文中
    for (int i = 0; i < paraNameArr.length; i++) {
        context.setVariable(paraNameArr[i], args[i]);
    }
    return parser.parseExpression(key).getValue(context, String.class);
}


使用,在service调用前使用:

@Cacheable(key = "biz_member",fieldKey = "#id")
public Member get(String id) {
    return super.get(id);
}

@CacheEvict(key = "member",fieldKey = {"#member.id","#member.account"})
public Serializable save(Member member) {
        return dao.insert(member);
}

@CacheEvict(key = "member",fieldKey = {"#member.id","#member.account"})
public void delete(Member member) {
    dao.delete(member);
}



转载请声明。



© 著作权归作者所有

共有 人打赏支持
vill_520
粉丝 3
博文 5
码字总数 2584
作品 0
武汉
技术主管
Android中AOP实践之一概念篇

预热 在说AOP之前先来说说java最经典的OOP(面向对象编程),我们通过面向对象的封装思想把同一类事物的共性归为一类中,方便我们统一管理。比如我们会把汽车的轮子,发动机,车身喷漆都放在...

LaxusJ
2017/11/12
0
0
使用Spring进行面向切面编程(AOP)

转载于http://www.blogjava.net/supercrsky/articles/174368.html 文章太长,写的很好,没看完,转过来慢慢理解,品味 简介 面向切面编程(AOP)提供另外一种角度来思考程序结构,通过这种方...

zmf
2014/09/04
0
0
spring aop + xmemcached 配置service层缓存策略

Memcached 作用与使用 基本介绍 1,对于缓存的存取方式,简言之,就是以键值对的形式将数据保存在内存中。在日常业务中涉及的操作无非就是增删改查。加入缓存机制后,查询的时候,对数据进行...

bxst
06/26
0
0
Spring Boot 使用AOP统一处理Web请求日志

AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是Spring框架中的一个重要内容,它通过对既有程序定义...

小致dad
08/08
0
0
深入了解 Dojo 的面向方面编程

简介: 面向方面的编程 “Aspect Oriented Programming,AOP” 相信大家都不陌生了。Java 中的 AspectJ 工具包对此有很好的支持。但是,在 web 开发中,似乎很少听到类似的工具。随着 Web2.0...

IBMdW
2012/03/06
597
0

没有更多内容

加载失败,请刷新页面

加载更多

Win10内部更新:警告用户别用chrome和Firefox

简评:别和 Chrome 和 Firefox 约行不,我 Edge 明明更美、屁股更翘、更性感。。。 微软正在测试 Windows 10 的一个更新:警告用户不要安装 Chrome 和 Firefox。是测试人员发现的这个新警告,...

极光推送
31分钟前
2
0
Java并发编程高阶技术 高性能并发框架源码解析与实战

全网唯一深度解析并发编程框架disruptor底层源码课程,助你成为并发编程高手,拿下高薪 网盘地址下载

qq__2304636824
今天
1
0
day92-20180918-英语流利阅读-待学习

健身最大的敌人不是懒惰,而是逞强 Daniel 2018-09-19 1.今日导读 还记得 2008 年北京奥运会运动员刘翔的退赛风波吗?那天几乎所有中国人都将视线聚焦在了鸟巢体育馆 110 米栏的项目上,迫不...

飞鱼说编程
今天
8
0
70.shell的函数 数组 告警系统需求分析

20.16/20.17 shell中的函数 20.18 shell中的数组 20.19 告警系统需求分析 20.16/20.17 shell中的函数: ~1. 函数就是把一段代码整理到了一个小单元中,并给这个小单元起一个名字,当用到这段...

王鑫linux
今天
3
0
分布式框架spring-session实现session一致性使用问题

前言:项目中使用到spring-session来缓存用户信息,保证服务之间session一致性,但是获取session信息为什么不能再服务层获取? 一、spring-session实现session一致性方式 用户每一次请求都会...

WALK_MAN
今天
7
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部