携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第18天,点击查看活动详情
3.10 统一记录日志
这里日志的意思是平时不发生异常的话也记录日志。
切入点表达式:
# 切入点表达式
切入点表达式
execution(返回值 包.类名.方法名(参数类型))
execution(返回值 包.类名.*(..))
*代表类中所有方法 ..代表参数任意
aop.*.*(..) 代表aop包下的所有类的所有方法在执行时都要加前置通知
execution:
第一个代表方法的返回值,*代表不关心方法的返回值
之后空格写包名(包.类.方法名),切类中所有方法且不关心方法的参数写*(..)
以前写的关于AOP的博客:
Spring中AOP编程本质(动态代理机制)以及前置通知的开发
SpringAOP使用示例
Spring AOP 的示例
下面写一个示例体会一下 Spring Aop 的语法
写完这个示例之后将类的两个注解注释掉,防止影响记录日志时的数据观看
@Component
@Aspect
public class AlphaAspect {
@Pointcut("execution(* com.nowcoder.community.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; // 目标组件方法的返回值
}
}
/*
around before
before
2022-07-19 17:00:43,555 DEBUG [http-nio-8080-exec-1] c.n.c.d.L.selectByTicket [BaseJdbcLogger.java:143] ==> Preparing: select id, user_id, ticket, status, expired from login_ticket where ticket = ?
2022-07-19 17:00:43,555 DEBUG [http-nio-8080-exec-1] c.n.c.d.L.selectByTicket [BaseJdbcLogger.java:143] ==> Parameters: e626e90074e84641993380de204f177e(String)
2022-07-19 17:00:43,557 DEBUG [http-nio-8080-exec-1] c.n.c.d.L.selectByTicket [BaseJdbcLogger.java:143] <== Total: 1
afterRetuning
after
around after
*/
对所有业务组件记录日志
@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,ip地址],在[xx时间],访问了[com.nowcoder.community.service.xxx()].
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
// 得到request对象
HttpServletRequest request = attributes.getRequest();
String ip = request.getRemoteHost(); // 利用request得到ip地址
String now = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()); // 时间
String target = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();
logger.info(String.format("用户[%s],在[%s],访问了[%s].", ip, now, target));
}
}
访问首页:
经测试,统一记录日志功能完成