本篇文章給大家分享的是有關(guān)如何通過spring-aop的方式自定義注解來實現(xiàn)spring-cache的功能,小編覺得挺實用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。
創(chuàng)新互聯(lián)服務(wù)項目包括隴西網(wǎng)站建設(shè)、隴西網(wǎng)站制作、隴西網(wǎng)頁制作以及隴西網(wǎng)絡(luò)營銷策劃等。多年來,我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢、行業(yè)經(jīng)驗、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機(jī)構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,隴西網(wǎng)站推廣取得了明顯的社會效益與經(jīng)濟(jì)效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到隴西省份的部分城市,未來相信會繼續(xù)擴(kuò)大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!
設(shè)計的過程中參考一下幾個原則:
代碼無侵入
按需加載
配置多樣化
首先自定義注解:只能作用于方法上,運(yùn)行期有效,key支持spel表達(dá)式,其中FunctionEnum是根據(jù)業(yè)務(wù)自定義的一個枚舉
@Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface GlobalCache { /** * SPEL表達(dá)式,緩存key * @return */ String key() default ""; String value() default ""; /** * 當(dāng)前具體的操作 * eg:信息新增,刪除等 * * @return */ FunctionEnum functionEnum() default FunctionEnum.DEFAULT; }
通過定義aop的切面來解析當(dāng)前這個注解,核心實現(xiàn)如下
@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(() -> { //重定向相關(guān)操作 return redirectUrl(cacheKey,request,httpParams,ForeignUtils.getRequestBody(method,joinPoint)); }, LocalThreadPool.FOREIGN_EXEC_CACHE).whenComplete((serviceData, ex) -> { if (ex == null) { //本地緩存的業(yè)務(wù)處理 notice.onSuccess(globalCache, httpParams, serviceData); } else { notice.onError(ex, serviceData); throw new ForeignInvokeException("current request was deny..."); } }).join(); return result; }
在構(gòu)造的過程中遇到很多小的零碎的問題,其中涉及到如何解析PUT請求中的body等等,下面附上ForeignUtils工具類的代碼
/** * 組裝緩存key * 格式: 方法名:參數(shù)值1:參數(shù)值2 * 自動解析格式 * * @param functionName 當(dāng)前操作對應(yīng)的名稱 * @param args 所有變量對應(yīng)的參數(shù) * @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; } /** * 請求參數(shù)的參數(shù)名稱和參數(shù)對應(yīng)的值 key參數(shù):value參數(shù)變量 * 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后請求參數(shù),占位符的方式 * 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; } /** * 獲取當(dāng)前請求中的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的參數(shù)對 * @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表達(dá)式 緩存對應(yīng)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; } }
上面的工具類主要涉及到參數(shù)的組裝,解析等;
以上就是如何通過spring-aop的方式自定義注解來實現(xiàn)spring-cache的功能,小編相信有部分知識點可能是我們?nèi)粘9ぷ鲿姷交蛴玫降?。希望你能通過這篇文章學(xué)到更多知識。更多詳情敬請關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。