千家信息网

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

发表于:2025-02-02 作者:千家信息网编辑
千家信息网最后更新 2025年02月02日,本篇文章给大家分享的是有关如何通过spring-aop的方式自定义注解来实现spring-cache的功能,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小
千家信息网最后更新 2025年02月02日如何通过spring-aop的方式自定义注解来实现spring-cache的功能

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

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

  • 代码无侵入

  • 按需加载

  • 配置多样化

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

@Target({ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @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.parse_Expression(spel);            return expression.getValue(context, clazz);        } catch (Exception e) {            return defaultResult;        }    }

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

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

0