long blogs

进一步有进一步惊喜


  • Home
  • Archive
  • Tags
  •  

© 2025 long

Theme Typography by Makito

Proudly published with Hexo

springBootAop使用

Posted at 2019-08-10 笔记 spring 

pom引入aop的依赖

1
2
3
4
5
<!--引入aop的依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

application.properties配置aop

1
2
spring.aop.auto=true
spring.aop.proxy-target-class=false

ProceedingJoinPoint joinPoint

继承JoinPoint
常用方法
1、JoinPoint#getArgs()->Objcet[]返回参数列表
2、ProceedingJoinPoint#proceed()正常运行函数,参数由上级传入
3、ProceedingJointPoint#proceed(Object[])正常运行函数,函数的入口参数为指定的Object数组
4、procced()返回值便是执行切面函数之后的返回值

切面常用函数

1、@Around()
入口参数ProceedingJoinPoint joinpoint
出口参数Object通常是joinpoint.proceed()返回的结果作为出口参数。
使用around方法的时候,如果没有返回数据通常就是出口参数问题。在对controller层做切面的时候,around的方法没有返回值。也就是前台没有返回值了。在joinpoint中可以拿到要加载参数和返回的参数。proceed的入口参数使用getArgs()获得。出口参数使用joinpoint.proceed()方法返回。使用around就要处理joint。使用空的around会跳过切面函数的执行。
2、@Before()
3、@After()
4、@AfterReturning()
5、@AfterThrowing()

切面函数的执行次序

1.@Around ->joinpint.proceed()开始->@Before->proceed对应的函数->@After->@AfterReturning

使用注解来实现统一的日志管理

1、建立一个注解名为MyLog.这个注解是用来定位那个函数需要记录日志的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.longquanxiao.springboot.annocation;

import java.lang.annotation.*;

/**
* 日志注解
* @author longquanxiao
* @date 2019/8/10
*/
// 注解到的目标 参数,方法
@Target({ElementType.PARAMETER,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyLog {
String value() default "";
}

2、建立一个切面的实现类,将切点定位到注解中。这样只要使用了这个注解就会使用该切面

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
package com.longquanxiao.springboot.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
* @author longquanxiao
* @date 2019/8/10
*/
@Component
@Aspect
public class LogAop {
/**
* 切点为我的注解,只要有这个注解的都可以切
*/
@Pointcut("@annotation(com.longquanxiao.springboot.annocation.MyLog)")
public void pointCut(){}

@Before("pointCut()")
public void before(JoinPoint joinPoint){
System.out.println("..................before .............");
}

@After("pointCut()")
public void after(){
System.out.println(".................after() .............");
}

@AfterReturning("pointCut()")
public void afterReturning(JoinPoint joinPoint){
System.out.println("............after returning() ...");
}

@Around("pointCut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable{
// 调用方法前的日志
String className = joinPoint.getTarget().getClass().getName();
String method = joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
// 打印日志
System.out.println("-----------------------------------------------");
System.out.println("logging className = "+className);
System.out.println("logging method = "+ method);
System.out.println("logging parameters:");
for (int i = 0; i<args.length; i++){
System.out.println("parameter " + i + ",value="+args[i].toString());
}
Object ret = joinPoint.proceed();
// 调用方法后的日志
System.out.println("logging proceed return value = "+ret.toString());
System.out.println("-----------------------------------------------");
return ret;
}
}

3、建立切面要切的类和函数
其中有一个函数print使用了@MyLog注解,print2不是用注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.longquanxiao.springboot.service;

import com.longquanxiao.springboot.annocation.MyLog;
import org.springframework.stereotype.Component;

/**
* @author longquanxiao
* @date 2019/8/10
*/
@Component
public class Function {
@MyLog
public String print(String message1,String message2){
System.out.println("start function print ...........");
System.out.println("message1="+message1);
System.out.println("message2="+message2);
System.out.println("end function print..............");
return "ok";
}
public String print2(){
System.out.println("I have no log");
return "ok2";
}
}

4、测试

1
2
3
4
5
@Test
public void myLog(){
function.print("mm","dd");
function.print2();
}

5、输出的结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
-----------------------------------------------
logging className = com.longquanxiao.springboot.service.Function
logging method = print
logging parameters:
parameter 0,value=mm
parameter 1,value=dd
..................before .............
start function print ...........
message1=mm
message2=dd
end function print..............
logging proceed return value = ok
-----------------------------------------------
.................after() .............
............after returning() ...
I have no log

6、给print2也打上日志注解,输出的结果如下

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
-----------------------------------------------
logging className = com.longquanxiao.springboot.service.Function
logging method = print
logging parameters:
parameter 0,value=mm
parameter 1,value=dd
..................before .............
start function print ...........
message1=mm
message2=dd
end function print..............
logging proceed return value = ok
-----------------------------------------------
.................after() .............
............after returning() ...
-----------------------------------------------
logging className = com.longquanxiao.springboot.service.Function
logging method = print2
logging parameters:
..................before .............
I have no log
logging proceed return value = ok2
-----------------------------------------------
.................after() .............
............after returning() ...

在切面函数中,每个函数都可以传入JoinPoint对象来获取相应的参数和设置相应的参数。在around中可以传入一个不同的参数,ProceedingJoinPoint 是JointPoint的子类。拥有proceed()方法。可以按需的调用被代理的函数。

获得日志注解传进来的值

1、在@Around()中value使用@annotation(logInstance)和argNames="joinPoint,logInstance"
Around的处理函数接收两个参数joinPoint,logInstance如果只有参数列表只有joinpoint可以省略
public Object around(ProceedingJoinPoint joinPoint,MyLog logInstance) throws Throwable{}
这样在函数中想要传进来的参数值便可以用logInstance.value()获得了。注意其中的参数问题,logInstance在annotation中使用,在参数列表中使用。
2、只要注解的值

1
2
3
4
@After(value = "@annotation(log)",argNames = "log")
public void after(MyLog log){
System.out.println(log.value());
}

3、可不可以要该函数上另外注解的值呢?
3.1 为了去了解是否可以使用该注解切面获得该函数上其它注解的值。做出了如下的实验。
(1) 新建一个名为MyDescroption的注解

1
2
3
4
5
6
7
8
9
10
/**
* @author longquanxiao
* @date 2019/8/12
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyDescription {
String value() default "description default";
String description() default "body";
}

(2)将切面中的@Around方法,更改成

1
2
3
4
5
6
@Around(value = "pointCut()&&@annotation(logInstance)&&@annotation(description)",argNames = "joinPoint,logInstance,description")
public Object around(ProceedingJoinPoint joinPoint, MyLog logInstance, MyDescription description) throws Throwable{
// 打印description
System.out.println("description value = " + description.value());
System.out.println("description description = " + description.description());
}

(3) 将注解打入函数中

1
2
3
4
5
6
@MyDescription(value = "print2",description = "print2Body")
@MyLog(value = "print2")
public String print2(){
System.out.println("I have no log");
return "ok2";
}

输出结果:

1
2
description value = print2
description description = print2Body

(4)结论:将切点切入函数中,函数上所有的注解被获得和使用

Share 

 Previous post: 基础算法 Next post: npm相关 

© 2025 long

Theme Typography by Makito

Proudly published with Hexo