一、依赖
1 <dependency>
2 <groupId>org.springframework.boot</groupId>
3 <artifactId>spring-boot-starter-web</artifactId>
4 </dependency>
5
6 <!-- aop -->
7 <dependency>
8 <groupId>org.springframework.boot</groupId>
9 <artifactId>spring-boot-starter-aop</artifactId>
10 </dependency>
二、注解
1 @Target(ElementType.METHOD)
2 @Retention(RetentionPolicy.RUNTIME)
3 @Documented
4 public @interface Limiter {
5 /**
6 * 使用spel表达式获取限流的key
7 * @return
8 */
9 String value();
10 }
三、AOP切面的应用
1 @Aspect
2 @Component
3 public class LimiterAspect {
4 private ExpressionParser parser = new SpelExpressionParser();
5 private LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();
6
7 @Pointcut("@annotation(limiter)")
8 public void pointcut(Limiter limiter) {
9 }
10
11 @Around("pointcut(limiter)")
12 public Object around(ProceedingJoinPoint pjp, Limiter limiter) throws Throwable {
13 Method method = this.getMethod(pjp);
14 String methodName = method.toString();
15
16 //获取方法的参数值
17 Object[] args = pjp.getArgs();
18 EvaluationContext context = this.bindParam(method, args);
19
20 //根据spel表达式获取值
21 Expression expression = parser.parseExpression(limiter.value());
22 Object key = expression.getValue(context);
23 //打印
24 System.out.println(key);
25
26 return pjp.proceed();
27 }
28
29 /**
30 * 获取当前执行的方法
31 *
32 * @param pjp
33 * @return
34 * @throws NoSuchMethodException
35 */
36 private Method getMethod(ProceedingJoinPoint pjp) throws NoSuchMethodException {
37 MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
38 Method method = methodSignature.getMethod();
39 Method targetMethod = pjp.getTarget().getClass().getMethod(method.getName(), method.getParameterTypes());
40 return targetMethod;
41 }
42
43 /**
44 * 将方法的参数名和参数值绑定
45 *
46 * @param method 方法,根据方法获取参数名
47 * @param args 方法的参数值
48 * @return
49 */
50 private EvaluationContext bindParam(Method method, Object[] args) {
51 //获取方法的参数名
52 String[] params = discoverer.getParameterNames(method);
53
54 //将参数名与参数值对应起来
55 EvaluationContext context = new StandardEvaluationContext();
56 for (int len = 0; len < params.length; len++) {
57 context.setVariable(params[len], args[len]);
58 }
59 return context;
60 }
四、Controller
1 @RestController
2 public class TestController {
3
4 //获取名为id的参数
5 @Limiter("#id")
6 @GetMapping("test")
7 public String test(Long id){
8 return "hello";
9 }
10 }
五、获取对象(补充)
1、注解
1 @Limter(value = "#testObj")
2 public JSONObject test01(TestObj testObj){
3 // ......
4 }
多个切点同时获取
1 /**
2 * 设置操作日志切入点 记录操作日志 在注解的位置切入代码
3 */
4 //@Pointcut("@annotation(com.test.Limter)")
5 @Pointcut("@annotation(limter)")
6 public void operLogPointCut(Limter limter) {
7 }
8
9 @Pointcut("execution(public * com.test.aaa..*.*(..))")
10 public void operLogPointMethod() {
11 }
线程变量的使用,当前切面类中使用线程变量存储变量
1 @Aspect
2 @Component
3 public class LogAspect {
4
5 @Autowired
6 private LogsService logsService;
7 // 线程变量
8 private ThreadLocal<String> threadLocal = new ThreadLocal<>();
9
10 /**
11 * 设置操作日志切入点 记录操作日志 在注解的位置切入代码
12 */
方法体中存入数据
public void savaData(){
threadLocal.set("asdf");
}
在另一个方法体中获取当前线程数据
public void savaData(){
String value = threadLocal.get();
}
切点多条件限制 &&
1 @AfterReturning(value = "operLogPointCut(limter) && operLogPointMethod()", returning = "returnValue")
2 public void saveOperLog(JoinPoint joinPoint, Limter limter, Object returnValue) {
3 Object[] args = joinPoint.getArgs();
4 // 从切面织入点处通过反射机制获取织入点处的方法
5 MethodSignature signature = (MethodSignature) joinPoint.getSignature();
6 // 获取切入点所在的方法
7 Method method = signature.getMethod();
8 EvaluationContext context = this.bindParam(method, args);
9 Expression expression = parser.parseExpression(limter.value());
10
11 TestObj testObj= expression.getValue(context, TestObj.class);
12 // ......
13 new Thread(() -> logsService.saveLogs(Obj...)).start();
14
15 // 存入数据库后移除当前线程变量
16 threadLocal.remove();
17 }
参考:
https://blog.csdn.net/weixin_45052750/article/details/105742934
其他参考:
所有评论(0)