1. 使用技巧
以下是需要注意的部分:
- 在环绕通知中使用
ProceedingJoinPoint
,控制目标方法的运行。 - 在其他通知类型中使用
JoinPoint
。 - 如果使用
JoinPoint
则必须位于参数的第一位。 ProceedingJoinPoint
中有特殊的方法proceed()。- 当有多个切面时,使用@
Order(11)
来指定注解的优先级。- 在切点之前,
@Order
从小到大被执行,也就是说越小的优先级越高; - 在切点之后,
@Order
从大到小被执行,也就是说越大的优先级越高;
- 在切点之前,
- 切面流程:环绕前置--> 普通前置--> 目标方法执行--> 普通返回 --> 普通后置--> 环绕返回 -->环绕后置
2. 使用流程
-
在pom中引入相关依赖。
<properties> <fastjson.version>1.2.83</fastjson.version> </properties> <!--aop依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <!--用于日志切面,以json打印出入参数--> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>${fastjson.version}</version> </dependency>
-
在annotation包下创建
WebLog
注解。package com.zhao.common.annotation; import java.lang.annotation.*; /** * 配置系统日志 */ @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface WebLog { /** * 日志描述信息 */ String description() default ""; }
-
在aspect包下创建
WebLogAspect
类。package com.zhao.common.aspect; import com.google.gson.Gson; import com.zhao.common.annotation.WebLog; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; import java.lang.reflect.Method; /** * 系统日志,切面处理类 */ @Aspect // 声明该类是一个注解类 @Component // 注册为组件 @Profile({"dev", "test"}) // 使用场景:在配置文件中配置 public class WebLogAspect { /** * 使用slf4j注解 */ private static final Logger logger = LoggerFactory.getLogger(WebLogAspect.class); /** * 换行符 */ private static final String LINE_SEPARATOR = System.lineSeparator(); /** * 以自定义的日志注解作为切入点 */ @Pointcut("@annotation(com.zhao.annotation.WebLog)") public void logPointCut() { } /** * 在切入点前 */ @Before("logPointCut()") public void doBefore(JoinPoint joinPoint) throws Throwable { // 开始打印日志请求 ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); // 获取@WebLog注解的描述信息 String methodDescription = getAspectLogDescription(joinPoint); // 打印请求 url logger.info("URL : {}", request.getRequestURL().toString()); // 打印描述信息 logger.info("Description : {}", methodDescription); // 打印 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 : {}", JSON.toJSON(joinPoint.getArgs())); } /** * 在切点之后织入 */ //@After("logPointCut()") //public void doAfter() throws Throwable { // // 接口结束后换行,方便分割查看 //} /** * 环绕 */ @Around("logPointCut()") public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { logger.info("========================================== Start =========================================="); long startTime = System.currentTimeMillis(); Object result = proceedingJoinPoint.proceed(); // 打印出参 logger.info("Response Args : {}", JSON.toJSON(result)); // 执行耗时 logger.info("Time-Consuming : {} ms", System.currentTimeMillis() - startTime); // 接口结束后换行,方便分割查看 logger.info("=========================================== End ===========================================" + LINE_SEPARATOR); return result; } /** * 获取切面注解的详细描述 */ public String getAspectLogDescription(JoinPoint joinPoint) throws Throwable { String targetName = joinPoint.getTarget().getClass().getName(); String methodName = joinPoint.getSignature().getName(); Object[] arguments = joinPoint.getArgs(); Class targetClass = Class.forName(targetName); Method[] methods = targetClass.getMethods(); StringBuilder description = new StringBuilder(); for (Method method : methods) { if (method.getName().equals(methodName)) { Class[] clazzs = method.getParameterTypes(); if (clazzs.length == arguments.length) { description.append(method.getAnnotation(WebLog.class).description()); break; } } } return description.toString(); } }
-
在application配置文件中设置环境
Spring: profiles: active: dev
-
使用时在方法上添加注解即可。