springboot-AOP使用@Before和@After做一个最简单的切面

写一个最简单明细的切面,希望可以复制了直接用。我会尽量把注释写详细

1.引入jar 因为我是用的springboot,所以只需要引入一个包,如果你习惯的是引入两个包 也可以引入下面的两个包 SpingBoot:

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

Spring:

<!--aop切面-->
<dependency>
   <groupId>org.aspectj</groupId>
   <artifactId>aspectjrt</artifactId>
</dependency>
<dependency>
   <groupId>org.aspectj</groupId>
   <artifactId>aspectjweaver</artifactId>
</dependency>
1
2
3
4
5
6
7
8
9

2.切面类 作用:可以做登录拦截或者参数拦截 首先新建一个.java文件,在类上加上@Component和@Aspect 注解

@Component 	//把切面类加入到IOC容器中 
@Aspect		//使之成为切面类
@Order(1)	//如果有多个 可以定义来控制顺序 数字越小执行顺序靠前
public class AopHandlerAspect {
	//日志 我是使用的hutool中的日志方法 你可以改为你自己的
    private Log logger = LogFactory.get();
	
	//为了记录执行时间 方便调试 如果不需要可以去掉
    ThreadLocal<Long> startTime = new ThreadLocal<>();

	//定义一个切入点 我这里是从controller切入 不是从注解切入
	//详情看下方的 切入点表达式
    @Pointcut("execution(public * cn.o.generate.controller.*.*(..))")
    public void pointCut() {}
	
	//在进入方法前执行 可以对参数进行限制或者拦截
	//通常在这边做日志存储存到数据库中
    @Before("pointCut()")
    public void before(JoinPoint joinPoint) throws Throwable {
        logger.info("==================前置执行=====================>");
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        logger.info("请求来源: =》" + request.getRemoteAddr());
        logger.info("请求URL:" + request.getRequestURL().toString());
        logger.info("请求方式:" + request.getMethod());
        logger.info("响应方法:" + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        logger.info("请求参数:" + Arrays.toString(joinPoint.getArgs()));
        logger.info("==================前置执行完成==================>");
        startTime.set(System.currentTimeMillis());
    }
//环绕执行
//定义需要匹配的切点表达式,同时需要匹配参数
    @Around("pointCut()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        StaticLog.info("==================方法环绕前置start=====================>");
        //这句必须有 往下执行方法
        Object result = pjp.proceed();

        StaticLog.info("==================方法环绕后置start=====================>");
        StaticLog.info("耗时(毫秒):" + time);
        StaticLog.info("返回数据:{}", result);
        StaticLog.info("==================方法环绕end======================>");
        return result;
    }

	//在方法执行后执行 可以打印返回的数据 判断数据是否是自己需要的
    @After("pointCut()")
    public void after(JoinPoint point) {
        if (startTime.get() == null) {
            startTime.set(System.currentTimeMillis());
        }
        logger.info("==================后置执行======================>");
        logger.info("耗时(毫秒):" + (System.currentTimeMillis() - startTime.get()));
        logger.info("返回数据:{}", point.getArgs());
        logger.info("==================后置执行完成==================>");
    }
}
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
44
45
46
47
48
49
50
51
52
53
54
55
56
57

切入点表达式

定义切入点的时候需要一个包含名字和任意参数的签名,还有一个切入点表达式,如execution(public * com.example.aop...(..))

切入点表达式的格式:execution([可见性]返回类型[声明类型].方法名(参数)[异常]) 
其中[]内的是可选的,其它的还支持通配符的使用: 
1) *:匹配所有字符 
2) ..:一般用于匹配多个包,多个参数 
3) +:表示类及其子类 
4)运算符有:&&,||,!

切入点表达式关键词用例: 
1)execution:用于匹配子表达式。 
//匹配com.cjm.model包及其子包中所有类中的所有方法,返回类型任意,方法参数任意 
@Pointcut(“execution(* com.cjm.model...(..))”) 
public void before(){}

2)within:用于匹配连接点所在的Java类或者包。 
//匹配Person类中的所有方法 
@Pointcut(“within(com.cjm.model.Person)”) 
public void before(){} 
//匹配com.cjm包及其子包中所有类中的所有方法 
@Pointcut(“within(com.cjm..*)”) 
public void before(){}

3) this:用于向通知方法中传入代理对象的引用。 
@Before(“before() && this(proxy)”) 
public void beforeAdvide(JoinPoint point, Object proxy){ 
//处理逻辑 
}

4)target:用于向通知方法中传入目标对象的引用。 
@Before(“before() && target(target) 
public void beforeAdvide(JoinPoint point, Object proxy){ 
//处理逻辑 
}

5)args:用于将参数传入到通知方法中。 
@Before(“before() && args(age,username)”) 
public void beforeAdvide(JoinPoint point, int age, String username){ 
//处理逻辑 
}

6)@within :用于匹配在类一级使用了参数确定的注解的类,其所有方法都将被匹配。 
@Pointcut(“@within(com.cjm.annotation.AdviceAnnotation)”) 
- 所有被@AdviceAnnotation标注的类都将匹配 
public void before(){}

7)@target :和@within的功能类似,但必须要指定注解接口的保留策略为RUNTIME。 
@Pointcut(“@target(com.cjm.annotation.AdviceAnnotation)”) 
public void before(){}

8)@args :传入连接点的对象对应的Java类必须被@args指定的Annotation注解标注。 
@Before(“@args(com.cjm.annotation.AdviceAnnotation)”) 
public void beforeAdvide(JoinPoint point){ 
//处理逻辑 
}

9)@annotation :匹配连接点被它参数指定的Annotation注解的方法。也就是说,所有被指定注解标注的方法都将匹配。 
@Pointcut(“@annotation(com.cjm.annotation.AdviceAnnotation)”) 
public void before(){}

10)bean:通过受管Bean的名字来限定连接点所在的Bean。该关键词是Spring2.5新增的。 
@Pointcut(“bean(person)”) 
public void before(){}
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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
上次更新: 2024-01-03, 13:22:13
最近更新
01
2023年度总结
01-03
02
MongoDB的简单的常用语法
12-11
03
cetnos7通过nfs共享磁盘文件
11-24
更多文章>