Spring - 使用 AOP 为 Service 统一追加日志

继续后端服务系列:

使用 AOP 为 Service 追加方法调用前后的日志

效果如下:

1
2
3
4
5
6
7
8
9
[00:51:04:133] [INFO] - com.tracenote.aspects.ServiceLogAspect.doBefore(ServiceLogAspect.java:22) - 【Service】方法执行前,当前时间:2020-11-20 00:51:04
[00:51:04:133] [INFO] - com.tracenote.aspects.ServiceLogAspect.doBefore(ServiceLogAspect.java:26) - 【Service】请求URL : http://localhost:8080/api/helloUser
[00:51:04:134] [INFO] - com.tracenote.aspects.ServiceLogAspect.doBefore(ServiceLogAspect.java:27) - 【Service】请求方法 : POST
[00:51:04:134] [INFO] - com.tracenote.aspects.ServiceLogAspect.doBefore(ServiceLogAspect.java:28) - 【Service】IP地址 : 0:0:0:0:0:0:0:1
[00:51:04:134] [INFO] - com.tracenote.aspects.ServiceLogAspect.Around(ServiceLogAspect.java:54) - 【Service】环绕前:2020-11-20 00:51:04
[00:51:04:134] [INFO] - com.tracenote.service.UserServiceImpl.getUser(UserServiceImpl.java:11) - ==== {} User(name=zhang)
[00:51:04:135] [INFO] - com.tracenote.aspects.ServiceLogAspect.AfterReturning(ServiceLogAspect.java:44) - 【Service】方法返回前,当前时间:2020-11-20 00:51:04
[00:51:04:135] [INFO] - com.tracenote.aspects.ServiceLogAspect.Around(ServiceLogAspect.java:56) - 【Service】环绕后:2020-11-20 00:51:04
[00:51:04:135] [INFO] - com.tracenote.aspects.ServiceLogAspect.after(ServiceLogAspect.java:39) - 【Service】方法执行后,当前时间:2020-11-20 00:51:04

实现:

这是Service

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.tracenote.service;

import com.tracenote.bean.vo.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

@Service
@Slf4j
public class UserServiceImpl implements IUserService {
public User getUser(User user) {
log.info("==== {} " + user.toString());
return user;
}
}

切面类

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
package com.tracenote.aspects;

import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;

import javax.servlet.http.HttpServletRequest;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

//定义切面类
@Slf4j
public class ServiceLogAspect {

//定义通知,方法执行前
public void doBefore(JoinPoint poin) throws UnsupportedEncodingException {
log.info("【Service】方法执行前,当前时间:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
// 记录下请求内容
log.info("【Service】请求URL : " + request.getRequestURL().toString());
log.info("【Service】请求方法 : " + request.getMethod());
log.info("【Service】IP地址 : " + request.getRemoteAddr());
Enumeration<String> enu = request.getParameterNames();
while (enu.hasMoreElements()) {
String name = (String) enu.nextElement();
log.info("【Service】参数:{},值:{}", name, new String(request.getParameter(name).getBytes("ISO-8859-1"), "utf-8"));
}

}

//定义通知,方法执行后
public void after(JoinPoint poin) {
log.info("【Service】方法执行后,当前时间:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
}

//定义通知,方法返回前
public void AfterReturning(JoinPoint poin) {
log.info("【Service】方法返回前,当前时间:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
}

//定义通知,抛出异常
public void AfterThrowing(Throwable error) {
log.info("【Service】方法报错,当前时间:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
}

//定义通知环绕型
public Object Around(ProceedingJoinPoint pjp) throws Throwable {
log.info("【Service】环绕前:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
Object obj = pjp.proceed();
log.info("【Service】环绕后:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
return obj;
}
}

配置 applicationContext.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<context:component-scan base-package="com.tracenote"/>
<aop:aspectj-autoproxy proxy-target-class="true"/>

<bean id="ServiceLogAspect" class="com.tracenote.aspects.ServiceLogAspect"></bean>
<aop:config>
<aop:aspect id="serviceLogAspect" ref="ServiceLogAspect">
<aop:pointcut expression="execution(* com.tracenote.service..*.*(..))" id="businessService"/>
<aop:before method="doBefore" pointcut-ref="businessService"/>
<aop:after method="after" pointcut-ref="businessService"/>
<aop:around method="Around" pointcut-ref="businessService"/>
<aop:after-returning method="AfterReturning" pointcut-ref="businessService"/>
<aop:after-throwing method="AfterThrowing" pointcut-ref="businessService" throwing="error"/>
</aop:aspect>
</aop:config>

参考:https://www.cnblogs.com/li-zhi-long/p/9394966.html