tonglin0325的个人主页

SpringBoot学习笔记——aop

它是一种在运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想。用于切入到指定类指定方法的代码片段叫做切面,而切入到哪些类中的哪些方法叫做切入点

AOP编程允许把遍布应用各处的功能分离出来形成可重用的组件

 

实现一个AOP可以分成下面几个步骤:

1.引入依赖 

1
2
3
4
5
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

2.自定义注解 @Permission,其中的 @Target 和 @Retention 元注解参考:元注解(Annotation)

1
2
3
4
5
6
7
8
9
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Permission {
}

参考

3.编写切点

常用的Aspect指示器:@execution,@within,@annotation

@execution:用于在方法执行时触发,如:在com.example.demo.controller.XXXController.register方法在任意参数(..)下执行,返回任意类型(*)的情况下执行

1
2
@Pointcut("execution(* com.example.demo.controller.XXXController.register(..))")

@within:用于在方法执行时触发,如:在com.example.demo.controller包下的任意方法执行

1
2
@Pointcut("within(com.example.demo.controller.*)")

@annotation:用于注解对象,如:指定 com.example.xxx 包下及其所有子目录下的所有带有 @hello 注解的方法体为切点

1
2
@Pointcut("within(com.example.xxx.*) &amp;&amp; @annotation(hello)")

  

4.编写切点checkTokenCut,以及定义切面Aspect,简单检查request请求的cookie中是否包含token,且切点设置在添加了 @Permission 注解的 方法上

此外还可以在aop类上添加 @Order注解,来定义Spring IOC容器中Bean的执行顺序的优先级,值越小拥有越高的优先级,可为负数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;

@Slf4j
@Aspect
@Component
public class PermissionAspect {

@Pointcut("@annotation(com.example.demo.annotation.Permission) &amp;&amp; within(com.example.demo.controller.*)")
public void checkTokenCut() {
}

@Around("checkTokenCut()")
public Object doCheckToken(ProceedingJoinPoint point) throws Throwable {
ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
HttpServletRequest request = attr.getRequest();
Cookie[] cookies = request.getCookies();
int len = cookies.length;
for (int i = 0; i < len; i++) {
Cookie cookie = cookies[i];
if ("token".equals(cookie.getName())) {
log.info("has token");
break;
}
if (i == len - 1) {
log.info("no token");
}
}
   //执行代理目标方法
return point.proceed();
}

}

5.注入AspectJ切面 @Permission

1
2
3
4
5
6
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@RequestMapping(path = "/fail", method = RequestMethod.GET)
@Permission
public ControllerResponseT fail() {
return ControllerResponseT.ofFail(50001, "error", null);
}

请求接口的时候将会执行check token逻辑

 

 

参考:SpringBoot使用AOP+注解实现简单的权限验证

前后端分离:使用spring的Aop实现Token验证

 

其他aop的例子:

使用aop实现数据脱敏:改造了以前写的数据脱敏插件,更好用了

使用aop实现接口响应时间记录:Spring Boot 2实践系列(四十七):Spring AOP 实现API接口处理请求耗时监控

使用aop实现全局异常处理以及统一打印接口请求入参和返回结果日志,打印接口访问性能日志,处理sql注入攻击以及处理入参特殊字符等问题:Springboot项目全局异常统一处理