https://blog.csdn.net/weixin_42700635/article/details/106629583
统一记录日志,可能会想到封装一个记日志的组件,在每个业务中调用,但是这样实现不利于维护,这里就需要AOP技术。
Spring AOP语法
package com.nowcoder.community.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class AlphaAspect {
@Pointcut("execution(* com.nowcoder.community.service.*.*(..))") // 意思连接点是service包下的所有类的所有方法的任意参数的任意返回类型
public void pointcut() {
}
// 前置通知
@Before("pointcut()")
public void before() {
System.out.println("before");
}
@After("pointcut()")
public void after() {
System.out.println("after");
}
// 在切入点的返回值之后增强
@AfterReturning("pointcut()")
public void afterRetuning() {
System.out.println("afterRetuning");
}
@AfterThrowing("pointcut()")
public void afterThrowing() {
System.out.println("afterThrowing");
}
// 环绕通知
@Around("pointcut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("around before");
Object obj = joinPoint.proceed();
System.out.println("around after");
return obj;
}
}
1、使用@Component和@Aspect注解修饰类,表明是切面Bean
@Component注解表明一个类会作为组件类,并告知Spring要为这个类创建bean。
2、使用@Pointcut定义连接点,execution固定关键字,*表示任何方法返回值都行,com.neu.langsam.community.service.*表示service包下所有类,再.*表示所有方法,(…)表示所有的参数都要处理,也可以指定明确的方法
3、五种注解实现五种通知,前四个实现大同小异,around表示前后都执行,实现方法就是传入joinPoint,调用joinPoint的proceed方法,也就是业务方法,在调用前后写需要织入的逻辑。
统一处理日志
//@Component
//@Aspect
public class ServiceLogAspect {
private static final Logger logger = LoggerFactory.getLogger(ServiceLogAspect.class);
@Pointcut("execution(* com.nowcoder.community.service.*.*(..))")
public void pointcut() {
}
@Before("pointcut()")
public void before(JoinPoint joinPoint) {
// 用户[1.2.3.4],在[xxx],访问了[com.nowcoder.community.service.xxx()].
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attributes == null) {
return;
} // 1. 获取request
HttpServletRequest request = attributes.getRequest();
String ip = request.getRemoteHost(); // 2. 获取IP
String now = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()); // 3. 获取当前日期,并进行格式化
// 4. 获取访问的类与对象
// joinPoint 是要织入的方法,所以通过它可以获取所在的类,以及方法名
String target = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();
logger.info(String.format("用户[%s],在[%s],访问了[%s].", ip, now, target));
}
}