1. 依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2. 切面类
重要注解:
- @Aspect:将一个java类定义为切面类
- @Pointcut:定义一个切入点,可以是一个规则表达式,比如下例中某个package下的所有函数,也可以是一个注解等
- @Before:在切入点开始处切入内容
- @After:在切入点结尾处切入内容
- @AfterReturning:在切入点return内容之后切入内容(可以用来对处理返回值做一些加工处理)
- @Around:在切入点前后切入内容,并自己控制何时执行切入点自身的内容
- @AfterThrowing:用来处理当切入内容部分抛出异常之后的处理逻辑
package com.activiti.aop;
import com.alibaba.fastjson.JSONObject;
import javax.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
/**
* @author : jiangBeiPing
* @description: 日志切面
* @date 2021/11/16
*/
@Aspect
@Component
@Slf4j
public class LogAcpect {
@Pointcut("execution(public * com.activiti.controller..*.*(..))") // 切点
public void controllerMethod(){
}
/**
* 方法执行前日志打印
*
* JoinPoint:
* --Object[] getArgs:返回目标方法的参数
* --Signature getSignature:返回目标方法的签名
* --Object getTarget:返回被织入增强处理的目标对象
* --Object getThis:返回AOP框架为目标对象生成的代理对象
* @param joinPoint 织入增强处理的连接点
*/
@Before("controllerMethod()")
public void logRequestInfo(JoinPoint joinPoint) throws Throwable {
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
assert requestAttributes != null;
HttpServletRequest request = requestAttributes.getRequest();
Signature signature = joinPoint.getSignature();
StringBuilder requestLog = new StringBuilder();
requestLog.append("请求URL: ").append(request.getRequestURL()).append("\n");
requestLog.append("请求方式: ").append(request.getMethod()).append("\n");
requestLog.append("请求IP: ").append(request.getRemoteAddr()).append("\n");
requestLog.append("类方法: ").append(signature.getDeclaringTypeName()).append("\n");
// 请求参数
String[] parameterNames = ((MethodSignature) signature).getParameterNames();
Object[] parameterValues = joinPoint.getArgs();
int paramLength = parameterNames == null ? 0 : parameterNames.length;
if (paramLength == 0){
requestLog.append("无参请求");
}else {
requestLog.append("请求参数 = [");
for (int i = 0; i < paramLength; i++) {
requestLog.append(parameterNames[i]).append("=").append(JSONObject.toJSONString(parameterValues[i]));
}
requestLog.append("]");
}
log.info(requestLog.toString());
}
@AfterReturning(returning = "returnValue",pointcut = "controllerMethod()")
public void logReturnValue(Object returnValue) throws Throwable{
log.info("方法返回值:{}",returnValue.toString());
}
}
3. 测试类
@GetMapping("/aopTest")
@ResponseBody
public String aopTest(@RequestParam("name") String name){
return "success" + name;
}
4. 测试效果
5. 注意问题
- 启动类无需加@EnableAspectJAutoProxy注解,引入了AOP依赖后,默认已经开启。
- 不同的@Aspect类依靠@Order(x)注解来区分优先级,order的值越小越先执行。
- 同一个@Aspect类,针对同一个 pointcut,定义了两个相同的advice,无法确定执行顺序。