如何通过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; } } MaphttpParams = 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 MapbuiltParams(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的功能,小编相信有部分知识点可能是我们日常工作会见到或用到的。希望你能通过这篇文章学到更多知识。更多详情敬请关注行业资讯频道。
参数
缓存
注解
方式
表达式
功能
业务
代码
信息
变量
名称
工具
方法
更多
格式
知识
篇文章
过程
实用
有效
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
三维数据采集软件开发
网络技术有限公司的客服电话
小米air软件开发
塘沽海洋科技互联网信息技术
想做一名网络安全员怎么做
网络安全查滴滴
中服云北京网络技术有限公司
客户服务器模式
呈贡软件开发公司
修复网络技术
软件开发案例分析实验报告
设备管理软件开发程序代码
抽奖更新数据库操作是放到哪一步
网络安全宣传大使滕秋月
我国网络安全挑战的现实案例
徐汇区机电网络技术设置
画报数据库
无线异构网络技术
南京泰治软件开发面试
办公网络安全稳定的意义
意大利警察数据库
机关单位网络安全事件个人检查
个性化网络技术厂家现货
pyqt5查询数据库
布乔网络技术
设备管理软件开发程序代码
惠州bim软件开发
数据库查询小数位数怎么设置
普陀区辅助网络技术备案
秦淮区常规软件开发专业服务