目录
前言:
代码实现:
优化后的代码:
优化后的代码:
最近在打英雄联盟 一下子冲到了 黄金,奥里给
@Aspect
@Component
public class LoggingAspect {
private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);
@Before("execution(* com.example.demo.service.*.*(..))")
public void logBefore(JoinPoint joinPoint) {
logger.info("Before method: " + joinPoint.getSignature().getName());
}
@After("execution(* com.example.demo.service.*.*(..))")
public void logAfter(JoinPoint joinPoint) {
logger.info("After method: " + joinPoint.getSignature().getName());
}
@AfterReturning(pointcut = "execution(* com.example.demo.service.*.*(..))", returning = "result")
public void logAfterReturning(JoinPoint joinPoint, Object result) {
logger.info("After returning method: " + joinPoint.getSignature().getName() + ", result: " + result);
}
@AfterThrowing(pointcut = "execution(* com.example.demo.service.*.*(..))", throwing = "exception")
public void logAfterThrowing(JoinPoint joinPoint, Exception exception) {
logger.error("After throwing method: " + joinPoint.getSignature().getName() + ", exception: " + exception.getMessage());
}
}
示例中,我们使用了Spring AOP框架来实现日志切面。我们定义了一个LoggingAspect类,并使用@Aspect注解将其标记为切面类。我们还使用@Component注解将其标记为Spring组件,以便Spring可以自动扫描并将其实例化。
我们定义了四个切点方法,分别在方法执行前、执行后、执行成功返回后和执行抛出异常后执行。我们使用@Before、@After、@AfterReturning和@AfterThrowing注解来标记这些方法,并使用execution表达式指定切点。在这个示例中,我们使用了通配符来匹配com.example.demo.service包中的所有方法。
在每个切点方法中,我们使用JoinPoint参数来获取当前执行的方法的名称和参数。我们使用LoggerFactory获取一个Logger实例,并使用info()或error()方法记录日志。在@AfterReturning方法中,我们还使用返回值参数来记录方法的返回值。
最后,我们需要在Spring配置文件中启用AOP自动代理,以便Spring可以自动将切面织入我们的应用程序中。我们可以使用以下配置:
示例只是一个简单的演示,实际的日志切面可能需要更复杂的逻辑和更详细的日志记录
@Aspect
@Component
public class LoggingAspect {
private final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);
@Pointcut("execution(* com.example.demo.service.*.*(..))")
public void serviceMethods() {}
@Before("serviceMethods()")
public void logBefore(JoinPoint joinPoint) {
logger.info("Before method: {}", joinPoint.getSignature().getName());
}
@AfterReturning(pointcut = "serviceMethods()", returning = "result")
public void logAfterReturning(JoinPoint joinPoint, Object result) {
logger.info("After returning method: {}, result: {}", joinPoint.getSignature().getName(), result);
}
@AfterThrowing(pointcut = "serviceMethods()", throwing = "exception")
public void logAfterThrowing(JoinPoint joinPoint, Exception exception) {
logger.error("After throwing method: {}, exception: {}", joinPoint.getSignature().getName(), exception.getMessage());
}
}
示例中,我们使用了更简洁的语法来定义切点和切点方法。我们使用@Pointcut注解定义了一个名为serviceMethods的切点方法,它匹配com.example.demo.service包中的所有方法。我们还使用{}和参数占位符来更方便地记录日志。
我们还删除了@After注解,因为它不是必需的。如果我们不需要在方法执行后记录日志,我们可以完全省略它。
最后,我们还使用了final关键字来定义Logger实例,以便它不能被修改。这是一个良好的实践,因为Logger实例通常是线程安全的,所以我们不需要在每个方法调用中创建一个新的实例。
@Aspect
@Component
public class LoggingAspect {
private final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);
@Pointcut("execution(* com.example.demo.service.*.*(..))")
public void serviceMethods() {}
@Before("serviceMethods()")
public void logBefore(JoinPoint joinPoint) {
logger.info("Before method: {}", joinPoint.getSignature().getName());
}
@AfterReturning(pointcut = "serviceMethods()", returning = "result")
public void logAfterReturning(JoinPoint joinPoint, Object result) {
logger.info("After returning method: {}, result: {}", joinPoint.getSignature().getName(), result);
}
@AfterThrowing(pointcut = "serviceMethods()", throwing = "exception")
public void logAfterThrowing(JoinPoint joinPoint, Exception exception) {
logger.error("After throwing method: {}, exception: {}", joinPoint.getSignature().getName(), exception.getMessage());
}
@Around("serviceMethods()")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
Object result = null;
try {
result = joinPoint.proceed();
return result;
} finally {
long endTime = System.currentTimeMillis();
long duration = endTime - startTime;
logger.info("Method: {}, execution time: {} ms", joinPoint.getSignature().getName(), duration);
}
}
}
示例中,我们添加了一个新的切点方法logAround,它使用@Around注解来拦截方法的执行,并在方法执行前后记录日志。我们使用ProceedingJoinPoint参数来调用原始方法,并使用try-finally块来确保我们在方法执行后记录日志。
我们还添加了一个计时器来记录方法的执行时间。我们使用System.currentTimeMillis()方法来获取当前时间,并在方法执行前和执行后记录时间。我们还使用Object类型的变量result来存储方法的返回值,并在finally块中返回它。
这个示例还演示了如何在同一个切面中使用多个切点方法来拦截不同的方法。我们可以使用不同的execution表达式来匹配不同的方法,并在不同的切点方法中记录日志。这使得我们可以更灵活地控制日志记录的粒度和详细程度。