计算方法执行时间是大多数后端应用程序中常见的非功能性需求。以下是一些计算执行时间的传统方法:
long startTime=(System.currentTimeMillis());// 你的逻辑代码long executionTime=(System.currentTimeMillis()-startTime)/1000;LOGGER.info("计算所花费的时间为:{} 秒",executionTime);StopWatch watch=newStopWatch();watch.start();// 你的逻辑代码watch.stop();LOGGER.info("计算所花费的时间为:{} 秒",watch.getTotalTimeSeconds());
可以看到需要在每个需要计算执行时间的方法里增加相同的计算代码,这种统计代码执行时间的方式存在代码冗余、违反 DRY 原则、侵入性强等问题。
接下来让我们通过 AOP 来实现在方法顶部添加一个注解,就可以非常高效地计算所有方法的执行时间的功能。
首先,通过在 POM.xml 中添加以下内容来启用 Spring AOP:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency>
现在让我们在 Spring Boot 中创建一个名为 ExecutionTimeLogger 的自定义注解。可以看到,该注解在运行时起作用,并且适用于方法级别。
@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public@interfaceExecutionTimeLogger{}
创建一个作为切面的新类,包含计算方法执行时间的逻辑。在 Spring AOP 中有多种使用切面的方式,这里使用 @Around 注解。创建 ExecutionTimeLoggerAspect 类并使用 @Aspect 注解,再创建 executionTimeLogger 方法并添加 @Around 注解,将注解名称作为参数传递给 @Around,这样该方法会在带 ExecutionTimeLogger 注解的方法执行前后被调用:
@Aspect @Component publicclass ExecutionTimeLoggerAspect{staticfinal Logger logger=LoggerFactory.getLogger(ExecutionTimeLoggerAspect.class);@Around("@annotation(ExecutionTimeLogger)")publicObjectexecutionTimeLogger(ProceedingJoinPoint joinPoint){try{long startTime=System.currentTimeMillis();Object proceed=joinPoint.proceed();long executionTime=(System.currentTimeMillis()-startTime);logger.info("{}方法在{}毫秒内执行完毕",joinPoint.getSignature(),executionTime);returnproceed;}catch(Throwable e){logger.error("在计算{}方法执行时间时出错",joinPoint.getSignature(),e);returnnull;}}}
所有必需的配置都已完成。现在我们唯一需要做的就是在想要计算 Java 代码中方法执行时间的地方使用该注解。假设要计算方法的执行时间,如下面的代码所示。只需在方法顶部添加注解即可。
publicclassCustomLoggingService{@ExecutionTimeLoggerpublicvoidmyMethod(){try{Thread.sleep(20000);}catch(InterruptedException e){e.printStackTrace();}}}
当 myMethod 在你的代码中执行时的输出:
c.n.t.a.ExecutionTimeLoggerAspect|voidcom.main.project.CustomLoggingService.myMethod()方法在20毫秒内执行完毕
是不是很简单?想象一下节省了多少时间和精力。只需写一遍计算执行时间的代码,然后在需要计算执行时间的地方继续使用注解即可。
总结一下:
创建自定义注解。
创建 @Aspect 类,包含计算执行时间的方法。
用 @Around 声明方法并指定为自定义注解执行。
在要记录执行时间的方法上加注解。