SpringBoot 日志记录

"Hello SpringBoot, Hello Log"

Posted by 墨城烟柳(Mcyl) on July 29, 2020

“Hello everyone! ”

需求介绍

以前老项目接口请求越来越慢,维护越来越困难,要在所有接口中记录请求日志监控,因为项目比较老了,所以接口还是挺多的, 公司新招的毕业生预估需要三天才能完成,我说还是让我来吧!

AOP使用场景:

今天我们就来讲讲切点的一种配置方式:@annotation,通过@annotation配置切点,我们可以灵活的控制切到哪个方法, 同时可以进行一些个性化的设置,今天我们就用它来实现一个记录所有接口请求功能吧。

AOP实现自定义注解

1、不管三七二十一,先看效果:

1
2
3
4
5
6
7
8
9
10
  INFO 1110 --- [nio-8080-exec-2] com.example.aoplog.aop.AopLog            : ======================请求开始========================
  INFO 1110 --- [nio-8080-exec-2] com.example.aoplog.aop.AopLog            : 请求连接:http://localhost:8080/hello
  INFO 1110 --- [nio-8080-exec-2] com.example.aoplog.aop.AopLog            : 接口描述:hello接口
  INFO 1110 --- [nio-8080-exec-2] com.example.aoplog.aop.AopLog            : 请求类型:GET
  INFO 1110 --- [nio-8080-exec-2] com.example.aoplog.aop.AopLog            : 请求方法:com.example.aoplog.controller.HelloControllerhello
  INFO 1110 --- [nio-8080-exec-2] com.example.aoplog.aop.AopLog            : 请求IP:0:0:0:0:0:0:0:1
  INFO 1110 --- [nio-8080-exec-2] com.example.aoplog.aop.AopLog            : 请求参数:[{"name":"Hello World"}]
  INFO 1110 --- [nio-8080-exec-2] com.example.aoplog.aop.AopLog            : 请求耗时:77ms
  INFO 1110 --- [nio-8080-exec-2] com.example.aoplog.aop.AopLog            : 请求返回:hello,Hello World
  INFO 1110 --- [nio-8080-exec-2] com.example.aoplog.aop.AopLog            : ======================请求结束========================

通过结果我们可以看到,我们的自定义注解EagleEye做到了统一的记录下了请求链接、接口描述、请求类型、请求方法、请求IP、请求参数、请求耗时、请求返回等信息。

是不是感觉还不错呢?下面我们就来一起动手实现它吧!

2、添加jar依赖

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
64
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.3.0.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>aoplog</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>aoplog</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-aop</artifactId>
		</dependency>

		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>fastjson</artifactId>
			<version>1.2.46</version>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<version>1.16.10</version>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

3、自定义注解

1
2
3
4
5
6
7
8
9
10
11
12
13
@Retention(RetentionPolicy.RUNTIME)    // 注解的生命周期
@Target(ElementType.METHOD)			   // 注解修饰的方法
@Documented							   // 注解被javadoc记录
public @interface EagleEye {

    /**
     * 接口描述
     * @return
     */
    String desc() default "";


}

1、定义了注解的生命周期为运行时

2、定义了注解的作用域为方法

3、标识该注解可以被JavaDoc记录

4、定义注解名称为EagleEye(自称为鹰眼)

5、定义一个元素desc,用来描述被修饰的方法

注解虽然定义好了,但是还用不了,因为没有具体的实现逻辑,接下来我们用AOP实现它。

4、配置AOP切面

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
@Slf4j
@Aspect
@Component
public class AopLog {

    @Pointcut("@annotation(com.example.aoplog.aop.EagleEye)")
    public void eagleEye() {

    }

    @Around("eagleEye()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        // 系统时间
        long begin = System.currentTimeMillis();
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        Signature signature = pjp.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        EagleEye eagleEye = method.getAnnotation(EagleEye.class);

        //接口信息
        String desc = eagleEye.desc();

        log.info("======================请求开始========================");

        log.info("请求连接:{}", request.getRequestURL().toString());

        log.info("接口描述:{}", desc);

        log.info("请求类型:{}", request.getMethod());

        log.info("请求方法:{}{}", signature.getDeclaringTypeName(), signature.getName());

        log.info("请求IP:{}", request.getRemoteAddr());

        log.info("请求参数:{}", JSON.toJSONString(pjp.getArgs()));

        Object result = pjp.proceed();
        long end = System.currentTimeMillis();
        log.info("请求耗时:{}ms", end - begin);

        log.info("请求返回:{}", result);

        log.info("======================请求结束========================");
        return result;
    }
}

好了,到大功告成,我们就完成了利用AOP自定义注解的所有步骤。

5、使用配置

1
2
3
4
5
6
7
8
9
@RestController
public class HelloController {

    @RequestMapping("/hello")
    @EagleEye(desc = "hello接口")
    public String hello(@RequestBody HelloVO helloVO){
        return "hello," + helloVO.getName();
    }
}

对于需要AOP增强的方法,我们只需要:

1、在方法上加上@EagleEye注解

2、通过desc元素设置方法的描述

接下来启动应用,请求接口看一下控制台输出是不是像我们开头贴出的那样吧。

总结

当然,这仅仅是自定义注解的一种小用法而已,用来实现这个日志记录的小功能显得有些大材小用,但是确实挺方便的。

源码下载:

https://github.com/mochengyanliu/Study/tree/master/aoplog