SpringWebFlux端点性能记录器
您知道记录SpringWebFlux控制器端点性能以保持反应性的良好实践吗?似乎以下原则不起作用,因为它会阻止IO,因为ProceedingJoinPoint不返回Publisher,它只返回一个对象SpringWebFlux端点性能记录器,spring,spring-webflux,spring-aop,project-reactor,Spring,Spring Webflux,Spring Aop,Project Reactor,您知道记录SpringWebFlux控制器端点性能以保持反应性的良好实践吗?似乎以下原则不起作用,因为它会阻止IO,因为ProceedingJoinPoint不返回Publisher,它只返回一个对象 @Aspect @Component @Slf4j public class LoggingAspect { //AOP expression for which methods shall be intercepted @Around("execution(* com
@Aspect
@Component
@Slf4j
public class LoggingAspect
{
//AOP expression for which methods shall be intercepted
@Around("execution(* com.company.service..*(..)))")
public Object profileAllMethods(ProceedingJoinPoint proceedingJoinPoint) throws Throwable
{
MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
//Get intercepted method details
String className = methodSignature.getDeclaringType().getSimpleName();
String methodName = methodSignature.getName();
final StopWatch stopWatch = new StopWatch();
//Measure method execution time
stopWatch.start();
Object result = proceedingJoinPoint.proceed();
stopWatch.stop();
//Log method execution time
log.info("Execution time of " + className + "." + methodName + " :: " + stopWatch.getTotalTimeMillis() + " ms");
return result;
}
}
实际上,正如@Toerktumlare在注释
proceedingJoinPoint.procedure()
返回对象的类型,无论控制器端点返回类型是什么,因此可以保持反应性。注意.subscribeOn(Schedulers.parallel())
在这里是可选的,即我的后台代码支持并行性。为此发布解决方案:
@Aspect
@Component
@Slf4j
public class LoggingAspect
{
//AOP expression for which methods shall be intercepted
@Around("execution(* com.company.service..*(..)))")
public Object logEndpointPerformance(ProceedingJoinPoint proceedingJoinPoint) throws Throwable
{
MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
//Get intercepted method details
String className = methodSignature.getDeclaringType().getSimpleName();
String methodName = methodSignature.getName();
final StopWatch stopWatch = new StopWatch();
//Measure method execution time
stopWatch.start();
Object result = proceedingJoinPoint.proceed();
if(result instanceof Mono){
return ((Mono)result).subscribeOn(Schedulers.parallel()).flatMap(r -> {
logExecutionTime(className, methodName, stopWatch);
return Mono.just(r);
});
}
else if(result instanceof Flux){
return ((Flux<Object>)result).subscribeOn(Schedulers.parallel()).collectList().flatMapMany(r -> {
logExecutionTime(className, methodName, stopWatch);
return Flux.fromIterable(r);
});
}
else{
logExecutionTime(className, methodName, stopWatch);
return result;
}
}
private void logExecutionTime(final String className, final String methodName, final StopWatch stopWatch){
stopWatch.stop();
//Log method execution time
log.debug("[ " + stopWatch.getTotalTimeMillis() + " mls ] lasted execution of" + className + "." + methodName );
}
}
@方面
@组成部分
@Slf4j
公共类日志方面
{
//应截取哪些方法的AOP表达式
@关于(“执行(*com.company.service.*(…))”)
公共对象logEndpointPerformance(ProceedingJoinPoint ProceedingJoinPoint)抛出可丢弃
{
MethodSignature MethodSignature=(MethodSignature)proceedingJoinPoint.getSignature();
//获取截获的方法详细信息
String className=methodSignature.getDeclaringType().getSimpleName();
字符串methodName=methodSignature.getName();
最终秒表秒表=新秒表();
//度量方法执行时间
秒表。开始();
对象结果=proceedingJoinPoint.procedure();
如果(单声道的结果实例){
return((Mono)result).subscribeOn(Schedulers.parallel()).flatMap(r->{
日志执行时间(类名、方法名、秒表);
返回Mono.just(r);
});
}
else if(通量的结果实例){
返回((通量)结果).subscribeOn(Schedulers.parallel()).collectList().flatMapMany(r->{
日志执行时间(类名、方法名、秒表);
返回通量。可计算(r);
});
}
否则{
日志执行时间(类名、方法名、秒表);
返回结果;
}
}
私有void logExecutionTime(最终字符串类名称、最终字符串方法名称、最终秒表秒表){
秒表;
//日志方法执行时间
log.debug(“[”+stopWatch.getTotalItemillis()+“mls]持续执行“+className+”+methodName”);
}
}
您可以使用instanceof
进行检查,并将其转换为mono或flux。一个对象没有阻塞,这取决于什么类型的对象决定它是否阻塞。@Toerktumlare真的吗?我会检查一下,谢谢。但另一方面,你不能像以前那样对函数计时,因为Mono/Flux会立即返回(很像未来)。如果你想给一个函数计时,你需要得到一个开始时间,并将它放入反应式上下文中,然后在链的后面,得到另一个时间,从上下文中检索第一个时间,然后计算经过的时间。@Toerktumlare Yep做了类似的事情,与上下文一起传递,它算得上是正确的。在我看来,它不包括事务打开、R2dbc连接释放时间,因为对于执行,我接收到例如1秒,但postman显示1.5秒。谢谢大家!@Toerktumlare发布了我拥有的最终代码不要忘记接受你自己的答案以结束问题。非常感谢。