1、springboot中使用AOP切面完成全局日志
可选择在控制台输出日志或者收集日志信息存储进数据库中
1、在配置 AOP 切面之前,我们需要了解下 aspectj
相关注解的作用:
- @Aspect:作用是把当前类标识为一个切面、供容器读取
- @Pointcut:(哪些方法或者类需要进行AOP织入)定义一个切点,后面跟随一个表达式,表达式可以定义为某个 package 下的方法,也可以是自定义注解等;
- 切点定义好后,就是围绕这个切点做文章了:
- @Before: 在切点之前,织入相关代码;
- @After: 在切点之后,织入相关代码;
- @AfterReturning: 在切点返回内容后,织入相关代码,一般用于对返回值做些加工处理的场景;
- @AfterThrowing: 用来处理当织入的代码抛出异常后的逻辑处理;
- @Around: 在切入点前后织入代码,并且可以自由的控制何时执行切点;
2、导入依赖
注:第二个依赖可选择不用,本质就是将数据 JSON 化、使用阿里的也行(后期出错再改)
<!-- aop 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- 用于日志切面中,以 json 格式打印出入参(本来使用阿里的 FASTJSON, 但是对于文件上传的接口,打印参数会报错,换为 Gson) -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.5</version>
</dependency>
3、配置文件中声明
注:可不用声明,默认开启且使用的是 JDK(即接口方式的动态代理,如果需要使用类的动态代理就需要将proxy-target-class: true
设置为true,默认是false)
这里其实不需要进行下面的配置,只是提一下
#spring配置
spring:
#切面启用
aop:
proxy-target-class: true
auto: true
4、编写全局日志处理
定义一个类,类名为:WebLogAspect
(可任意取)
注:下面只是实现了在控制台打印日志信息,我们在末尾可添加一个插入方法,插入此次收获的所有信息存储进日志表中
同时,最好只插入增删改三者,因其涉及对数据的变动,查询不会变动数据可忽略(不然日志信息太多)
其次,此实现只AOP类控制层的方法,其他层也可照此。文章来源:https://www.toymoban.com/news/detail-431824.html
package com.zou.config;
import com.google.gson.Gson;
import io.swagger.annotations.ApiOperation;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
@Aspect
@Component
public class WebLogAspect {
// 获取日志类,方便直接在控制台输出统一格式的日志信息
private final static Logger logger = LoggerFactory.getLogger(WebLogAspect.class);
/*
方式1:controller包下所有类中的开头带有insert的方法
@Pointcut("execution(public * com.zou.controller.*.insert*(..))")
方式2:
@Pointcut("execution(public * com.ldb.admin.controller.*.create*(..))||" +
"execution(public * com.ldb.admin.controller.*.update*(..))||" +
"execution(public * com.ldb.admin.controller.*.delete*(..))")
注:可使用 || &&
* 1)execution(public * (..))——表示匹配所有public方法
* 2)execution( set(..))——表示所有以“set”开头的方法
* 3)execution( com.xyz.service.AccountService.(..))——表示匹配所有AccountService接口的方法
* 4)execution( com.xyz.service..(..))——表示匹配service包下所有的方法
* 5)execution(* com.xyz.service...(..))——表示匹配service包和它的子包下的方法
*/
/** 以 controller 包下定义的所有请求为切入点 */
@Pointcut("execution(public * com.zou.controller.*.*(..))")
public void webLog() {}
/**
* 在切点之前织入
* @param joinPoint
* @throws Throwable
*/
@Before("webLog()") // webLog():是你@Pointcut注解的方法名
public void doBefore(JoinPoint joinPoint) throws Throwable {
// 开始打印请求日志
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
// 打印请求相关参数
logger.info("========================================== Start ==========================================");
// 打印请求 url
logger.info("URL : {}", request.getRequestURL().toString());
// 打印 Http method
logger.info("HTTP Method : {}", request.getMethod());
// 打印调用 controller 的全路径以及执行方法
logger.info("Class Method : {}.{}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName());
// 打印请求的 IP
logger.info("IP : {}", request.getRemoteAddr());
// 打印请求入参
logger.info("Request Args : {}", new Gson().toJson(joinPoint.getArgs()));
// 获取 @ApiOperation("") 注解中的信息,此注解属于swagger的,但也能获取,其他注解可举一反三
ApiOperation apiOperation = null;
// JoinPoint:oinPoint对象封装了SpringAop中切面方法的信息,在切面方法中添加JoinPoint参数,就可以获取到封装了该方法信息的JoinPoint对象.大概就是获取目标方法的一些信息
MethodSignature ms = (MethodSignature) joinPoint.getSignature();
apiOperation = ms.getMethod().getDeclaredAnnotation(ApiOperation.class);
if (apiOperation != null) { ;
logger.info("操作 : {}", apiOperation.value());
}
}
/**
* 在切点之后织入
* @throws Throwable
*/
@After("webLog()")
public void doAfter() throws Throwable {
logger.info("=========================================== End ===========================================");
// 每个请求之间空一行
logger.info("");
}
/**
* 环绕
* @param proceedingJoinPoint
* @return
* @throws Throwable
*/
@Around("webLog()")
public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
Object result = proceedingJoinPoint.proceed();
// 打印出参
logger.info("Response Args : {}", new Gson().toJson(result));
// 执行耗时
logger.info("Time-Consuming : {} ms", System.currentTimeMillis() - startTime);
return result;
}
}
JoinPoint
常用API
方法名 功能
Signature getSignature(); 获取封装了署名信息的对象,在该对象中可以获取到目标方法名,所属类的Class等信息
Object[] getArgs(); 获取传入目标方法的参数对象
Object getTarget(); 获取被代理的对象
Object getThis(); 获取代理对象
ProceedingJoinPoint对象
ProceedingJoinPoint对象是JoinPoint的子接口,该对象只用在@Around的切面方法中,
添加了以下两个方法。文章来源地址https://www.toymoban.com/news/detail-431824.html
Object proceed() throws Throwable //执行目标方法
Object proceed(Object[] var1) throws Throwable //传入的新的参数去执行目标方法
到了这里,关于1、springboot中使用AOP切面完成全局日志的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!