SpringBoot用AOP统一处理请求日志
有时候我们想记录请求参数,请求地址等信息,此时可以在Controller层通过日志方式直接记录,但是采用这种方式我们需要在每个方法中一一处理,代码冗余度很高;而且如果想改变日志记录内容等信息就得排查每一个方法都改一遍,可维护性差。此时,我们可以采用AOP面向切面编程的方式对请求日志进行统一处理。
1.引入Aop依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2.编写切面类
@Component
@Aspect
public class LogAspect {
}
注:使用@Aspect注解将一个java类定义为切面类
3.在切面类中定义切入点
用@Pointcut定义切入点(即执行哪些方法时切入)
格式:
@Pointcut(expression)
其中,“expression”即匹配表达式常用的有:
1.execution()
格式:
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)throws-pattern?)
- modifiers-pattern:访问修饰符匹配
- ret-type-pattern:返回值类型匹配,*表示任何返回值
- declaring-type-pattern:类路径匹配
- name-pattern:方法名匹配(“*”表示任意方法名)
- param-pattern:参数匹配(可以指定参数类型,多个参数用“,”隔开,也可以用“*”匹配任意参数类型,"…"表示零个或多个参数)
- throws-pattern:异常类型匹配
其中带“?”的为可选项
** 例如:**
@Pointcut("execution(public * cn.lamb.controller.*.*(..))")
上述表达式表示匹配cn.lamb.controller包下所有类的所有方法并且返回值是任意类型的,参数为0个或者多个,也就是匹配cn.lamb.controller包下所有public修饰的方法。
2.@within、@target
用法:
@within(cn.lamb.annotation.MyTypeAnnotation)
@target(cn.lamb.annotation.MyTypeAnnotation)
以上均表示匹配类上标注了@MyTypeAnnotation注解的类下的任意方法
3.@annotation
用法:
@annotation(cn.lamb.annotation.MyTypeAnnotation)
表示匹配标注了@MyTypeAnnotation注解的方法
以上3种表达式均可单独使用,亦可通过“&& || 和!”即与或非的方式组合使用
具体用法:
//定义切入点
@Pointcut(表达式)
private void myPointcut(){}
@Before("myPointcut()")
public void doBefore(JoinPoint joinPoint){
//方法执行前具体的处理逻辑
}
@AfterReturning(pointcut = "myPointcut()",returning = "result")
public void doAfterReturning(Object result) throws Throwable {
// 处理完请求,返回内容,此处方法参数result即为返回值
}
@AfterThrowing("myPointcut()")
public void throwss(JoinPoint joinPoint){
//出异常时处理逻辑
}
@After("myPointcut()")
public void after(JoinPoint joinPoint){
//最终通知,不管方法正常执行结束还是出异常都执行此处理逻辑
}
@Around("myPointcut()")
public Object arround(ProceedingJoinPoint pjp) {
//环绕通知
try {
Object o = pjp.proceed();
return o;
} catch (Throwable e) {
e.printStackTrace();
return null;
}
}
附:
Pointcut表达式举例:
//任意公共方法:
execution(public * *(..))
//controller包里的任意方法的执行:
execution(* cn.lamb.controller.*.*(..))
//controller包中的类.
within(cn.lamb.controller.*)
//controller包和其所有子包里的类.
within(cn.lamb.controller..*)
//带有@MyAnnotation注解的所有类的任意方法.
@within(cn.lamb.annotation.MyAnnotation)
@target(cn.lamb.annotation.MyAnnotation)
//带有@MyAnnotation注解的任意方法.
@annotation(cn.lamb.annotation.MyAnnotation)
//匹配controller包里加了MyAnnotation注解的所有方法:
@Pointcut(execution(* cn.lamb.controller.*.*(..)) && @annotation(cn.lamb.annotation.MyAnnotation))