如何通过spring-aop的方式自定义注解来实现spring-cache的功能
发表于:2025-12-02 作者:千家信息网编辑
千家信息网最后更新 2025年12月02日,本篇文章给大家分享的是有关如何通过spring-aop的方式自定义注解来实现spring-cache的功能,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小
千家信息网最后更新 2025年12月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的功能,小编相信有部分知识点可能是我们日常工作会见到或用到的。希望你能通过这篇文章学到更多知识。更多详情敬请关注行业资讯频道。
参数
缓存
注解
方式
表达式
功能
业务
代码
信息
变量
名称
工具
方法
更多
格式
知识
篇文章
过程
实用
有效
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
网络安全检查常用命令
加强网络安全防疫措施
云南朝花夕拾互联网科技有限公司
软件开发代码精简
数据库报警铃声
加强网络安全技能培训
争做网络安全宣传员征文
使用国外服务器安全吗
五一假期网络安全提醒
有没有世界通用服务器
软件开发的具体实现措施
数据库系统事务的管理实验报告
国家对网络安全培训的要求
网络安全宣传片创意名字
网络安全绘画怎么画
轴流风机数据库
临沂顺商网络技术服务有限公司
安全服务器端口
软件开发的未来前景如何
驼峰数据库
前端node怎么做成临时数据库
查询行程码显示服务器内部错误
曙光g30服务器更改启动项
战地5自己开的服务器没人来
京东方软件开发和富士康
战地1服务器选什么
顺德发布网络安全
云计算和软件开发就业方向
wps表格编程连接数据库
软件开发课程设计评语