使用 Spring 引导和 AOP 进行性能记录

Performance Logging with Spring Boot and AOP

我正在尝试基于此 post 实现性能日志记录:http://www.baeldung.com/spring-performance-logging. I'd like to log each controller endpoint and every database request. If you would like to see the full project, you can find it here。当我到达端点时,没有任何记录。在拦截器中放置一个断点 class 它也不会停止。我已经将包的日志记录设置为跟踪级别。我错过了什么?我相信这与 @PointCut 有关,但在查看文档后我相信我是正确的。

拦截器

public class PerformanceMonitorInterceptor extends AbstractMonitoringInterceptor
{
    @Override
    protected Object invokeUnderTrace(MethodInvocation methodInvocation, Log log) throws Throwable
    {
        String name = createInvocationTraceName(methodInvocation);
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        log.trace(String.format("Method %s execution start at %s", name, LocalDateTime.now()));

        try
        {
            return methodInvocation.proceed();
        }
        finally
        {
            stopWatch.stop();
            log.trace(String.format("Method %s execution took %dms (%s)", name,
                stopWatch.getTotalTimeMillis(), DurationFormatUtils
                    .formatDurationWords(stopWatch.getTotalTimeMillis(), true, true)));
        }
    }
}

配置

@Configuration
@EnableAspectJAutoProxy
@Aspect
public class ContactControllerPerfLogConfig
{
    @Bean
    public PerformanceMonitorInterceptor performanceMonitorInterceptor()
    {
        return new PerformanceMonitorInterceptor();
    }

    // Any public method on the ContactController
    @Pointcut("execution(public * org.example.phonebookexample.app.contact.ContactController.*(..))")
    public void contactControllerMonitor()
    {
    }

    @Bean
    public Advisor contactControllerMonitorAdvisor(
        PerformanceMonitorInterceptor performanceMonitorInterceptor)
    {
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression("org.example.phonebookexample.app.contact.ContactControllerPerfLogConfig.contactControllerMonitor()");
        return new DefaultPointcutAdvisor(pointcut, performanceMonitorInterceptor);
    }
}

AbstractTraceInterceptor 实现了 MethodInterceptor 并且其 invoke() 方法实现如下:

public Object invoke(MethodInvocation invocation) throws Throwable {
    Log logger = getLoggerForInvocation(invocation);
    if (isInterceptorEnabled(invocation, logger)) {
        return invokeUnderTrace(invocation, logger);
    }
    else {
        return invocation.proceed();
    }
}

因此需要将拦截器 class 的记录器设置为 TRACE。对于基本 PerformanceMonitorInterceptor,那将是 org.springframework.aop.interceptor.PerformanceMonitorInterceptor。由于您已经编写了自己的拦截器,因此您必须为自己的 class 设置日志记录级别。 查看 JamonPerformanceMonitorInterceptor 的替代方法示例,如果需要,可以跟踪所有调用,而不管日志级别如何。

为了完整起见,我还将post一个xml配置示例,因为涉及到AOP时,Spring java配置不是这样的与 xml 配置相比优雅:

<bean id="performanceMonitorInterceptor" class="org.springframework.aop.interceptor.PerformanceMonitorInterceptor"/>

<aop:config>
    <aop:pointcut id="contactControllerMonitor" expression="execution(public * org.example.phonebookexample.app.contact.ContactController.*(..))" />
    <aop:advisor id="contactControllerMonitorAdvisor" pointcut-ref="contactControllerMonitor" advice-ref="performanceMonitorInterceptor"/>
</aop:config>

此配置可以导入到您的 java 配置中,如下所示:

@ImportResource("classpath:/aop-config.xml")
public class MainConfig { ... }

如果您要自定义它,我一直不明白 AbstractTraceInterceptor 的重要性。

我总觉得代码对我来说太多了,如果您已经有 @Aspect,可以通过一个简单的 @Around 建议来实现。

    @Around("execution(* com..*.*(..))")
    public Object logStartAndEnd(ProceedingJoinPoint pjp) throws Throwable{
        long startTime = System.currentTimeMillis();
        String className = pjp.getTarget().getClass().getCanonicalName();
        String methodName = pjp.getSignature().getName();
        log.info("started method : " + className+"."+methodName);

        Object obj;
        try {
            obj = pjp.proceed();
            log.info("finished method : " + className+"."+methodName);
            return obj;
        } catch (Throwable e) {
            throw e;
        }finally {
            log.info("Method "+className+"."+methodName+" execution lasted:"+((System.currentTimeMillis() - startTime )/1000f)+" seconds");
        }
    }