如何通过spring-aop的方式自定义注解来实现spring-cache的功能

本篇文章给大家分享的是有关如何通过spring-aop的方式自定义注解来实现spring-cache的功能,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。

创新互联服务项目包括陇西网站建设、陇西网站制作、陇西网页制作以及陇西网络营销策划等。多年来,我们专注于互联网行业,利用自身积累的技术优势、行业经验、深度合作伙伴关系等,向广大中小型企业、政府机构等提供互联网行业的解决方案,陇西网站推广取得了明显的社会效益与经济效益。目前,我们服务的客户以成都为中心已经辐射到陇西省份的部分城市,未来相信会继续扩大服务区域并继续获得客户的支持与信任!

设计的过程中参考一下几个原则:

  • 代码无侵入

  • 按需加载

  • 配置多样化

首先自定义注解:只能作用于方法上,运行期有效,key支持spel表达式,其中FunctionEnum是根据业务自定义的一个枚举

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface GlobalCache {

    /**
     * SPEL表达式,缓存key
     * @return
     */
    String key() default "";

    String value() default "";

    /**
     * 当前具体的操作
     * eg:信息新增,删除等
     *
     * @return
     */
    FunctionEnum functionEnum() default FunctionEnum.DEFAULT;

}

通过定义aop的切面来解析当前这个注解,核心实现如下

@Around("@annotation(com.xxx.xxxx.core.foreign.annotation.GlobalCache)")
    public Object globalCacheAround(ProceedingJoinPoint joinPoint) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        ServiceData result;
        GlobalCache globalCache = method.getAnnotation(GlobalCache.class);
        String cacheKey = globalCache.functionEnum().name() + ":" + ForeignUtils.combineParam(methodSignature.getParameterNames(),joinPoint.getArgs(),globalCache.key(),String.class,"test-spel-123");
        if ("GET".equals(request.getMethod())) {
            result = defaultredisTemplate.opsForValue().get(cacheKey);
            if (result != null) {
                log.info("命中缓存,缓存的key:{}", cacheKey);
                return result;
            }
        }
        Map httpParams = ForeignUtils.builtParams(methodSignature.getParameterNames(), request);
        result = CompletableFuture.supplyAsync(() -> {
            //重定向相关操作
            return redirectUrl(cacheKey,request,httpParams,ForeignUtils.getRequestBody(method,joinPoint));
        }, LocalThreadPool.FOREIGN_EXEC_CACHE).whenComplete((serviceData, ex) -> {
            if (ex == null) {
                //本地缓存的业务处理
                notice.onSuccess(globalCache, httpParams, serviceData);
            } else {
                notice.onError(ex, serviceData);
                throw new ForeignInvokeException("current request was deny...");
            }
        }).join();
        return result;
    }

在构造的过程中遇到很多小的零碎的问题,其中涉及到如何解析PUT请求中的body等等,下面附上ForeignUtils工具类的代码

    /**
     * 组装缓存key
     * 格式: 方法名:参数值1:参数值2
     * 自动解析格式
     *
     * @param functionName 当前操作对应的名称
     * @param args         所有变量对应的参数
     * @return
     */
    public static String combineParameter(String functionName, Method method, Object[] args) {
        Class[] classArr = method.getParameterTypes();
        for (int index = 0; index < classArr.length; index++) {
            if (classArr[index] == HttpServletRequest.class) {
                //是否存在其他待忽略的?
                continue;
            }
            functionName += ":" + args[index];
        }
        return functionName;
    }

    /**
     * 请求参数的参数名称和参数对应的值   key参数:value参数变量
     * title:test-123,subtitle:test-subtitle-123
     *
     * @param params
     * @param request
     * @return
     */
    public static Map builtParams(String[] params, HttpServletRequest request) {
        Map keyMap = Maps.newHashMap();
        for (int i = 0; i < params.length; i++) {
            String value = request.getParameter(params[i]);
            if (StringUtils.isNotBlank(value)) {
                keyMap.put(params[i], value);
            }
        }
        return keyMap;
    }


    /**
     * 拼装http后请求参数,占位符的方式
     * title={title}&subtitle={subtitle}
     * 可以使用queryString()替代
     *
     * @param httpParams
     * @return
     */
    public static String builtHttpParams(Map httpParams) {
        String result = "";
        for (Map.Entry entry : httpParams.entrySet()) {
            result += entry.getKey() + "= {" + entry.getKey() + "}&";
        }
        if (result.endsWith("&")) {
            return result.substring(0, result.length() - 1);
        }
        return result;
    }

    /**
     * 获取当前请求中的body值
     *
     * @param method
     * @param joinPoint
     * @return
     */
    public static Object getRequestBody(Method method, ProceedingJoinPoint joinPoint) {
        Annotation[][] currentAnnotionArr = method.getParameterAnnotations();
        Object body = null;
        for (int index = 0; index < currentAnnotionArr.length; index++) {
            try {
                if (currentAnnotionArr[index][0].annotationType() == RequestBody.class) {
                    body = joinPoint.getArgs()[index];
                    break;
                }
            } catch (Exception e) {

            }
        }
        return body;
    }

    /**
     * 获取请求中path的参数对
     * @param method
     * @param joinPoint
     * @return
     */
    public static String getPathArgs(Method method, ProceedingJoinPoint joinPoint) {
        Annotation[][] currentAnnotionArr = method.getParameterAnnotations();
        String pathValue = null;
        for (int index = 0; index < currentAnnotionArr.length; index++) {
            try {
                if (currentAnnotionArr[index][0].annotationType() == PathVariable.class) {
                    pathValue = String.valueOf(joinPoint.getArgs()[index]);
                    break;
                }
            } catch (Exception e) {

            }
        }
        return pathValue;
    }


    private static ExpressionParser parser = new SpelExpressionParser();


    /**
     * 解析SPEL表达式 缓存对应key信息
     *
     * @param params
     * @param args
     * @param spel
     * @param clazz
     * @param defaultResult
     * @return
     */
    public static  T combineParam(String[] params, Object[] args, String spel, Class clazz, T defaultResult) {
        EvaluationContext context = new StandardEvaluationContext();
        for (int index = 0; index < params.length; index++) {
            context.setVariable(params[index], args[index]);
        }
        try {
            Expression expression = parser.parseExpression(spel);
            return expression.getValue(context, clazz);
        } catch (Exception e) {
            return defaultResult;
        }
    }

上面的工具类主要涉及到参数的组装,解析等;

以上就是如何通过spring-aop的方式自定义注解来实现spring-cache的功能,小编相信有部分知识点可能是我们日常工作会见到或用到的。希望你能通过这篇文章学到更多知识。更多详情敬请关注创新互联行业资讯频道。


文章题目:如何通过spring-aop的方式自定义注解来实现spring-cache的功能
链接URL:http://scyanting.com/article/jgshho.html