Java >> Java Tutorial >  >> Tag >> Spring

Leistungsüberwachung mit Spring Boot

In diesem Beitrag möchte ich einige interessante Funktionen zeigen, die Spring Boot für die Leistungsüberwachung bietet.

Sobald die Anwendung zu skalieren beginnt, wird die Leistung zur obersten Priorität. Wir überoptimieren die Anwendung, um die Einfachheit zu verlieren. So funktioniert Softwareentwicklung. In einem Produktionsszenario überwachen wir unsere Anwendung auf Leistung. Da die meisten Anwendungen in die Cloud verlagert werden, ist es wichtig, die Anwendung zu überwachen und die Leistung ständig zu verbessern.

Wenn Sie einen Federantrieb verwendet haben, bietet dieser eine Reihe von Statistiken zur Überwachung. Zuvor habe ich dieses Thema Federantrieb behandelt.

Anschließend werden wir einige verschiedene Funktionen von Spring Boot behandeln. Wir werden über CustomizableTraceInterceptor sprechen , PerformanceMonitorInterceptor und CommonsRequestLoggingFilter .

Verwendung von CustomizableTraceInterceptor

Sie können CustomizableTraceInterceptor als Bean hinzufügen und verwenden Sie diese Bean als Ratgeber für die Ausdrücke, die Sie abfangen möchten. Grundsätzlich ermöglicht uns dieser Interceptor, die Methodenaufrufe abzufangen und benutzerdefinierte Protokollmeldungen hinzuzufügen.

Um dies im Arbeitsbeispiel zu zeigen, werden wir die Repository-Timings verfolgen. Erstellen Sie zunächst eine Klasse, die CustomizableTraceInterceptor erweitert wie folgt:


package com.abccompany.home.performance;

import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.aop.interceptor.CustomizableTraceInterceptor;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;

public class RepositoryMethodInterceptor extends CustomizableTraceInterceptor
{
    @Override
    protected Class getClassForLogging(Object target)
    {
        Class classForLogging = super.getClassForLogging(target);
        if (SimpleJpaRepository.class.equals(classForLogging))
        {
            Class[] interfaces = AopProxyUtils.proxiedUserInterfaces(target);
            if (interfaces.length > 0)
            {
                return interfaces[0];
            }
        }
        return classForLogging;
    }


    protected void writeToLog(Log logger, String message, Throwable ex)
    {
        if (ex != null)
        {
            logger.info(message, ex);
        }
        else
        {
            logger.info(message);
        }
    }

    protected boolean isInterceptorEnabled(MethodInvocation invocation, Log logger)
    {
        return true;
    }

}

Ebenso werde ich gleich erklären, was diese Klasse macht. Wir brauchen eine @Bean die diesen Interceptor verwenden, um Repository-Methoden abzufangen. Der Code dafür sieht wie folgt aus:


package com.abccompany.home.performance;

import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class TraceLoggerConfig
{
    @Bean
    public RepositoryMethodInterceptor repositoryMethodInterceptor()
    {
        RepositoryMethodInterceptor repositoryMethodInterceptor = new RepositoryMethodInterceptor();
        repositoryMethodInterceptor.setHideProxyClassNames(true);
        repositoryMethodInterceptor.setUseDynamicLogger(false);
        repositoryMethodInterceptor.setExitMessage("Executed $[methodName] in $[invocationTime] " +
                "ms");
        return repositoryMethodInterceptor;
    }

    @Bean
    public Advisor advisor()
    {
        AspectJExpressionPointcut aspectJExpressionPointcut = new AspectJExpressionPointcut();
        aspectJExpressionPointcut.setExpression("execution(public * com.abccompany.home" +
                ".repositories.*Repository+.*(..))");
        return new DefaultPointcutAdvisor(aspectJExpressionPointcut, repositoryMethodInterceptor());
    }
}

Wenn wir uns nun diese Konfiguration ansehen, erstellt sie eine Bean für die Verwendung von RepositoryMethodInterceptor das ist eine Unterklasse von CustomizableTraceInterceptor . Sie können sehen, dass wir eine Exit-Nachricht verwendet haben, um das Timing zu protokollieren, das die Repository-Methode in dieser Bean verwendet hat.



repositoryMethodInterceptor.setExitMessage("Executed $[methodName] in $[invocationTime] " + "ms");


AspectJExpression erstellt einen Ausdruck, für den das Abfangen von Paketen erfolgen soll. Die Klasse RepositoryMethodInterceptor macht ein paar nützliche Dinge. Erstens hilft es uns, die Klasseninformationen zu verfolgen von Repository Klassen. Zweitens protokolliert es die Nachricht in unserer Logdatei. Sobald Sie die Anwendung ausführen, sehen Sie die folgenden Protokollmeldungen:



2020-05-24 19:08:04.870 INFO 14724 --- [nio-8443-exec-9] c.r.h.p.RepositoryMethodInterceptor : Entering method 'findUserByEmail' of class [com.abccompany.home.repositories.UserdataRepository] Hibernate: select userdata0_.id as id1_4_, userdata0_.email as email2_4_, userdata0_.firstname as firstnam3_4_, userdata0_.guid as guid4_4_, userdata0_.lastname as lastname5_4_, userdata0_.middlename as middlena6_4_, userdata0_.confirmpassword as confirmp7_4_, userdata0_.passwordtxt as password8_4_, userdata0_.phonenumber as phonenum9_4_, userdata0_.role as role10_4_ from userdata userdata0_ where userdata0_.email=? 
2020-05-24 19:08:04.872 INFO 14724 --- [nio-8443-exec-9] c.r.h.p.RepositoryMethodInterceptor : Executed findUserByEmail in 2 ms 
2020-05-24 19:08:04.872 INFO 14724 --- [nio-8443-exec-9] c.r.h.p.RepositoryMethodInterceptor : Entering method 'findAll' of class [com.abccompany.home.repositories.FeedbackRepository] Hibernate: select feedback0_.id as id1_1_, feedback0_.createdon as createdo2_1_, feedback0_.fromdate as fromdate3_1_, feedback0_.guid as guid4_1_, feedback0_.rating as rating5_1_, feedback0_.rentalpropertyid as rentalpr8_1_, feedback0_.review as review6_1_, feedback0_.todate as todate7_1_, feedback0_.userid as userid9_1_ from feedback feedback0_ 
2020-05-24 19:08:04.876 INFO 14724 --- [nio-8443-exec-9] c.r.h.p.RepositoryMethodInterceptor : Executed findAll in 4 ms


Verwendung der PerformanceMonitorInterceptor-Funktion

Also, um PerformanceMonitorInterceptor zu verwenden , erstellen wir eine Konfigurationsklasse und fügen eine Bean hinzu, die PerformanceMonitorInterceptor erstellt . AspectJExpressionPointcut zeigt auf den Ausdruck, der unsere Controller-Klassen auswertet.

Wie CustomizableTraceInterceptor , werden wir eine Unterklasse haben, die erweitert wird PerformanceMonitoringInterceptor damit wir unsere Nachrichten in der Spring Boot-Protokollierung protokollieren können. Dies sieht wie folgt aus:


package com.abccompany.home.performance;

import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.springframework.aop.interceptor.PerformanceMonitorInterceptor;


public class ControllerMonitoringInterceptor extends PerformanceMonitorInterceptor
{
    protected void writeToLog(Log logger, String message, Throwable ex)
    {
        if (ex != null)
        {
            logger.info(message, ex);
        }
        else
        {
            logger.info(message);
        }
    }

    protected boolean isInterceptorEnabled(MethodInvocation invocation, Log logger)
    {
        return true;
    }
}


Wir werden eine Bean für ControllerMonitoringInterceptor erstellen . Diese Bean wird Teil unserer Logger-Konfiguration sein, die auch AspectJExpression auswertet für Controller-Klassen. Daher sieht es wie folgt aus:



package com.abccompany.home.performance;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.interceptor.PerformanceMonitorInterceptor;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@EnableAspectJAutoProxy
@Aspect
public class ControllerLoggerConfig
{
    @Pointcut("execution(* com.abccompany.home.controllers.*Controller+.*(..))")
    public void monitor()
    {

    }

    @Bean
    public ControllerMonitoringInterceptor controllerMonitoringInterceptor()
    {
        return new ControllerMonitoringInterceptor();
    }

    @Bean
    public Advisor advisorPerformance()
    {
        AspectJExpressionPointcut aspectJExpressionPointcut = new AspectJExpressionPointcut();
        aspectJExpressionPointcut.setExpression("com.abccompany.home.performance" +
                ".ControllerLoggerConfig.monitor()");
        return new DefaultPointcutAdvisor(aspectJExpressionPointcut,
                controllerMonitoringInterceptor());
    }
}


Wenn wir nun die Anwendung ausführen, zeigen die Protokollnachrichten Latenzen für Controller-Klassen.


2020-05-24 20:12:09.237  INFO 9280 --- [nio-8443-exec-6] c.r.h.p.ControllerMonitoringInterceptor  : StopWatch 'com.abccompany.home.controllers.LoginController.signin': running time (millis) = 0
2020-05-24 20:12:18.263  INFO 9280 --- [nio-8443-exec-2] c.r.h.p.ControllerMonitoringInterceptor  : StopWatch 'com.abccompany.home.controllers.MainController.home': running time (millis) = 43
2020-05-24 20:12:20.025  INFO 9280 --- [nio-8443-exec-9] c.r.h.p.ControllerMonitoringInterceptor  : StopWatch 'com.abccompany.home.controllers.MainController.logout': running time (millis) = 12
2020-05-24 20:12:20.042  INFO 9280 --- [nio-8443-exec-5] c.r.h.p.ControllerMonitoringInterceptor  : StopWatch 'com.abccompany.home.controllers.LoginController.login': running time (millis) = 0


Verwendung von CommonsRequestLoggingFilter

Darüber hinaus bietet Spring Boot eine nützliche Funktion zum Protokollieren eingehender Anfragen. Dies hilft bei der Überwachung der Anwendung und um zu sehen, wie die Anfragen kommen. Um diese Funktion zu verwenden, erstellen wir einen @Configuration Klasse RequestLoggingFilter wie folgt:


package com.abccompany.home.performance;


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.AbstractRequestLoggingFilter;
import org.springframework.web.filter.CommonsRequestLoggingFilter;

import javax.servlet.http.HttpServletRequest;

@Configuration
public class RequestLoggingFilter extends AbstractRequestLoggingFilter
{
    @Bean
    public CommonsRequestLoggingFilter requestLoggingFilterConfig()
    {
        CommonsRequestLoggingFilter commonsRequestLoggingFilter = new CommonsRequestLoggingFilter();
        commonsRequestLoggingFilter.setIncludeClientInfo(true);
        commonsRequestLoggingFilter.setIncludeQueryString(true);
        commonsRequestLoggingFilter.setIncludePayload(true);
        return commonsRequestLoggingFilter;
    }

    @Override
    protected void beforeRequest (HttpServletRequest request, String message)
    {
        logger.info(message);
    }

    @Override
    protected void afterRequest (HttpServletRequest request, String message)
    {
        logger.info(message);
    }
}

Sobald wir dies hinzugefügt haben, sehen wir beforeRequest und afterRequest Meldungen im Protokoll wie folgt:



2020-05-24 21:07:15.161  INFO 11984 --- [nio-8443-exec-1] gFilter$$EnhancerBySpringCGLIB$$cb4fdaab : Before request [uri=/css/bootstrap.min.css]
2020-05-24 21:07:15.171  INFO 11984 --- [nio-8443-exec-2] gFilter$$EnhancerBySpringCGLIB$$cb4fdaab : Before request [uri=/js/jquery.min.js]
2020-05-24 21:07:15.203  INFO 11984 --- [nio-8443-exec-7] gFilter$$EnhancerBySpringCGLIB$$cb4fdaab : Before request [uri=/js/bootstrap.min.js]
2020-05-24 21:07:15.290  INFO 11984 --- [nio-8443-exec-7] gFilter$$EnhancerBySpringCGLIB$$cb4fdaab : After request [uri=/js/bootstrap.min.js]
2020-05-24 21:07:15.306  INFO 11984 --- [nio-8443-exec-2] gFilter$$EnhancerBySpringCGLIB$$cb4fdaab : After request [uri=/js/jquery.min.js]
2020-05-24 21:07:15.318  INFO 11984 --- [nio-8443-exec-1] gFilter$$EnhancerBySpringCGLIB$$cb4fdaab : After request [uri=/css/bootstrap.min.css]


Schlussfolgerung

Abschließend habe ich drei Funktionen zur Leistungsüberwachung gezeigt – CustomizableTraceInterceptor , PerformanceMonitorInterceptor und CommonsRequestLoggingFilter um nützliche Leistungsmetriken zu protokollieren.

Referenzen

  1. Spring Framework-Funktionen
  2. CommonsRequestLoggingFilter


Java-Tag