網站首頁 編程語言 正文
前言:要是想對某個接口進行加鎖操作,每次在方法前加鎖,方法結束釋放鎖會顯得很麻煩,這里可以基于AOP的環繞通知@Around實現功能。
1、基于RedisTemplate實現封裝分布式鎖
RedisTemplate實現setnx分布式鎖https://blog.csdn.net/qq_39648029/article/details/124926230
2、自定義注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @program: zy-common
* @description: 分布式鎖注解,方法注解
* @author: zhangyi
* @create: 2022-05-10 16:17
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ZyLock {
/**
* 鎖的key
*
* @return
*/
String value();
}
3、aop實現
package com.zyweb.admin.aop.lock;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.zy.base.utils.RedisUtil;
import com.zy.base.vo.ResponseVo;
import com.zyweb.admin.aop.dict.Dict;
import com.zyweb.admin.service.impl.DictServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @program: zy-common
* @description: 字典切面
* @author: zhangyi
* @create: 2022-05-10 16:33
*/
@Aspect
@Component
@Slf4j
public class ZyLockAop {
@Autowired
private RedisUtil redisUtil;
/**
* 切點,切入 controller 包下面的所有方法
*/
@Pointcut("execution( * com.zyweb.admin.controller.*.*(..))")
public void zyLock() {
}
@Around("zyLock()")
public Object AroundLock(ProceedingJoinPoint joinPoint) throws Throwable {
//獲取自定義注解 @ZyLock
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature = (MethodSignature) signature;
Method method = methodSignature.getMethod();
ZyLock zyLock = method.getAnnotation(ZyLock.class);
if (zyLock != null) {
//得到注解值
String key = zyLock.value();
//得到獲取參數000
Object[] args = joinPoint.getArgs();
String[] parameterNames = methodSignature.getParameterNames();
//最后加密的key
// 判斷是否是動態值,動態值前綴是#
if (key.startsWith("#")) {
//取出#號后面的數據
String substring = key.substring(1);
//根據.進行拆分,如果拆分后只有一個值,則表示單個參數,否則表示對象
String[] split = substring.split("\\.");
//第0個數據,表示參數名,找到他的索引,索引表示args的參數值
int i = getIndex(parameterNames, split[0]);
if (i < 0) {
return ResponseVo.error("@ZyLock注解解析失敗");
}
//找到要取的那個參數了
Object arg = args[i];
//判斷是否是對象
if(isObject(arg)){
String[] ofRange = Arrays.copyOfRange(split, 1, split.length);
key = getVal((JSONObject)arg, ofRange);
}else{
key=arg.toString();
}
}
//獲取鎖,10秒過期
boolean nx = redisUtil.setNx(key, 10);
//如果沒有拿到鎖,表示該鎖被占用
if (!nx) {
return ResponseVo.error("鎖獲取失敗,請重新發起請求");
}
//環繞通知,執行目標方法
Object proceed = joinPoint.proceed();
//釋放鎖
redisUtil.del(key);
return proceed;
} else {
return joinPoint.proceed();
}
}
//找出對象中改層級下的值
public String getVal(JSONObject obj, String[] split) {
for (String s : split) {
Object o = obj.get(s);
if(o==null){
return "";
}
//表示json字符串,則還需要轉換
if (o instanceof String) {
return o.toString();
} else {
JSONObject jo = JSONObject.parseObject(JSON.toJSONString(o));
return getVal(jo, Arrays.copyOfRange(split, 1, split.length));
}
}
return "";
}
public int getIndex(String[] arr, String val) {
for (int i = 0; i < arr.length; i++) {
if (arr[i].equals(val)) {
return i;
}
}
return -1;
}
// 判斷參數是不是JSON對象
public boolean isObject(Object obj) {
try{
JSONObject.parseObject(JSON.toJSONString(obj));
return true;
}catch (Exception e){
return false;
}
}
}
4、使用栗子
我這里做了注解的動態值操作,具體值從方法參數里獲取,參數可以是基本數據類型,可以是對象,也可以是對象套對象套對象(套娃)
動態值:最前面使用"#"開頭,然后進行對象.屬性的方式
普通值:直接填
1、請求為單個參數
@GetMapping("/fbssTest3")
@ZyLock("#id")//這里取的是參數名叫做"id"的值
public ResponseVo fbssTest3(Integer id,String name) throws InterruptedException {
System.out.println("我是方法內容1");
Thread.sleep(1000*2);
return ResponseVo.success("執行完成");
}
2、請求參數為普通的json對象
@PostMapping("/fbssTest2")
@ZyLock("#obj.key")//這里獲取的是參數名叫obj這個對象里面屬性名為key的值
public ResponseVo fbssTest2(@RequestBody JSONObject obj) throws InterruptedException {
System.out.println("我是方法內容1");
Thread.sleep(1000*2);
return ResponseVo.success("執行完成");
}
3、請求參數為套娃對象
@PostMapping("/fbssTest")
@ZyLock("#obj.obj1.obj2.obj3.key")//套娃對象
public ResponseVo fbssTest(@RequestBody JSONObject obj) throws InterruptedException {
System.out.println("我是方法內容1");
Thread.sleep(1000*2);
return ResponseVo.success("執行完成");
}
?4、代碼內容加了2秒的休眠操作,模擬執行時間,進行并發訪問
原文鏈接:https://blog.csdn.net/qq_39648029/article/details/124942458
相關推薦
- 2022-11-08 Python?Panda中索引和選擇?series?的數據_python
- 2022-08-28 Golang正則表達式判斷手機號或身份證方法實例_Golang
- 2022-08-11 golang時間及時間戳的獲取轉換_Golang
- 2022-09-17 詳解React?如何防止?XSS?攻擊論$$typeof?的作用_React
- 2022-02-17 RuntimeError: CUDA error: device-side assert trigg
- 2022-08-18 win10同網段/跨網段訪問虛擬機samba服務器的過程記錄_服務器其它
- 2024-03-16 nginx 報 unknown directive “server“ 詭異問題處理
- 2023-12-26 layui彈窗傳值
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支