AOP注解形式 整合memcache

1.首先自定义注解 :添加缓存

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface Memcached {
    // key的前缀 default=STATIC的可以使用OMS清理缓存
    String prefix() default "STATIC_";
    // key
    String key()  default "";
    // 过滤
    String conditions() default "true";
    // 緩存分組
    String group() default "hos-portal-mclient1";
    // 缓存有效期 2天 单位s
    int expiration() default 60 * 60 * 48;
}

2.切面类

@Aspect
public class MemCachedAop {

    private static final Logger log = LoggerFactory.getLogger(MemCachedAop.class);

    @Value("${enable.static.cache}")
    private boolean enableCache;

    @Pointcut("execution(* com.ylzinfo.hospital.portal.service.appservice.*.*.*(..))")
    protected void appservicePointcut(){}

    @Autowired
    private ICacheClient cacheClient;

    /**
     *  写入或者读取缓存
     *  仅针对有注解的且该包下的方法
     */
    @Around("(@annotation(memcached) && appservicePointcut())")
    public Object doMemcachedAround(ProceedingJoinPoint call, Memcached memcached) throws Throwable {
        String packageName = call.getSignature().getDeclaringTypeName();
        String methodName = call.getSignature().getName();
        log.info("执行方法: {} -> {}", packageName, methodName);
        //返回最终结果
        Object result = null;
        //校验conditions
        if (null != memcached
                && checkConditions(call,memcached.conditions())
                && enableCache) {
            String key = resolvingKey(call,memcached.prefix(),memcached.key());
            String group = memcached.group();
            result = cacheClient.get(group, key);
            if (null == result) {
                // memcached中不存在
                try {
                    //执行aop拦截的方法
                    result = call.proceed();
                    //获取注解配置memcached过期时间
                    int expiration = memcached.expiration();
                    cacheClient.put(group, key, result, expiration);
                    log.info("\n【写入Memcached缓存】" +
                            "\ngroup={}" +
                            "\nkey={}" +
                            "\nvalue={}" +
                            "\nexpiration={}",group,key, JSON.toJSON(result),expiration);
                } catch (Throwable e) {
                    log.error("执行方法失败: {} -> {}", packageName, methodName);
                    log.error("失败原因:{}",e.getMessage());
                }
            }else{
                // memcached中存在 直接返回
                log.info("\n【读取Memcached缓存】" +
                        "\ngroup={}" +
                        "\nkey={}" +
                        "\nvalue={}",group,key,JSON.toJSON(result));
            }
        }else {
            try {
                result = call.proceed();
            } catch (Throwable e) {
                log.error("执行方法失败: {} -> {}", packageName, methodName);
                log.error("失败原因:{}",e.getMessage());
            }
        }
        return result;
    }



    /**
     * 获取缓存的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);
    }

    /**
     *  获取被拦截方法对象
     *
     *  MethodSignature.getMethod() 获取的是顶层接口或者父类的方法对象
     *    而缓存的注解在实现类的方法上
     *  所以应该使用反射获取当前对象的方法对象
     */
    public Method getMethod(ProceedingJoinPoint pjp){
        //获取参数的类型
        Object [] args=pjp.getArgs();
        Class [] argTypes=new Class[pjp.getArgs().length];
        for(int i=0;i<args.length;i++){
            argTypes[i]=args[i].getClass();
        }
        Method method=null;
        try {
            method=pjp.getTarget().getClass().getMethod(pjp.getSignature().getName(),argTypes);
        } catch (NoSuchMethodException e) {
            log.error(e.getMessage());
        } catch (SecurityException e) {
            log.error(e.getMessage());
        }
        return method;
    }

    /**
     * 解析key
     * @author zengfanqi
     * @date 2019/5/6
     * @param
     * @return String
     */
    public String  resolvingKey(ProceedingJoinPoint call,String prefix,String key){

        //如果key为空直接将方法名称作为key
        String methodName = call.getSignature().getName();
        if(StringUtils.isEmpty(key)){
            return prefix + methodName;
        }

        //判断key是否是spel表达式
        if(key.startsWith("#")){
            Method method=getMethod(call);
            String parsekey = parseKey(key,method,call.getArgs());
            if(StringUtils.isEmpty(parsekey)){
                parsekey = methodName;
            }
            key = prefix+parsekey;
        }else{
            key = prefix+key;
        }
        return key;
    }

    /**
     * 校验conditions
     * @author zengfanqi
     * @date 2019/5/6
     * @param
     * @return
     */
    public boolean checkConditions(ProceedingJoinPoint call,String conditions){
        boolean flag = false;
        Method method=getMethod(call);
        String condition = parseKey(conditions,method,call.getArgs());
        if("true".equals(condition)){
            flag = true;
        }
        return flag;
    }
}

希望支付宝扫一扫天天领红包

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值