Spring的AOP(Aspect-Oriented Programming,面向切面编程)是一种编程范式,它允许程序员将横切关注点(cross-cutting concerns)从业务逻辑中分离出来,从而提高了代码的可维护性和可重用性。日志记录就是一个典型的横切关注点,因为它通常需要在多个地方进行,但并不属于业务逻辑的一部分。
下面是一个使用Spring AOP实现登录日志记录的详细步骤:
第一步:导入aop依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
第二步:写一个切面类(添加@Component和@Aspect注解)
定义切点:@Pointcut
切点表达式:使用表达式来匹配特定包下的方法
匹配特定方法名:execution(* com.example.service.MyService.myMethod(..))
匹配特定参数类型:execution(* com.example.service.*.*(String, ..))
匹配特定访问修饰符:execution(public * com.example.service.*.*(..))
第三步:使用环绕通知进行更细粒度的控制(@Around 它允许在方法执行的整个过程中插入自定义的逻辑。)
@Around(定义好的切点)
//环绕通知
@Around("aopLog()")
public Object loginLog(ProceedingJoinPoint pjp){
try {
LoginLog loginLog = new LoginLog();
loginLog.setTime(new Date());
//使用ServletRequestAttributes请求上下文获取方法更多
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
//获取方法所在类的名字
String className = pjp.getSignature().getDeclaringTypeName();
//获取方法名
String methodName = pjp.getSignature().getName();
//获取参数
Object[] args = pjp.getArgs();
ObjectMapper objectMapper = new ObjectMapper();
log.info("调用前:{}:{},传递的参数为:{}",className,methodName,objectMapper.writeValueAsString(args));
log.info("URL:{}",request.getRequestURL().toString());
log.info("IP地址:{}",request.getRemoteAddr());
//开始时间
long startTime = System.currentTimeMillis();
//执行方法
Object obj=pjp.proceed();
//结束时间
long finishTime = System.currentTimeMillis();
long runTime=finishTime-startTime;
loginLog.setIp(request.getRemoteAddr());
loginLog.setClassName(className);
loginLog.setMethodName(methodName);
loginLog.setStatus("登录成功");
loginLog.setUrl(request.getRequestURL().toString());
loginLog.setRunTime((int)runTime);
//添加登录日志
userRemoteService.add(loginLog);
//执行方法后打印日志
log.info("调用后:{}:{},返回值:{}",className,methodName,objectMapper.writeValueAsString(obj));
log.info("耗时:{}ms",runTime);
return obj;
} catch (Throwable e) {
throw new RuntimeException(e);
}
}