Registro de desempenho da primavera
1. Visão geral
Neste tutorial, veremos algumas opções básicas que o Spring Framework oferece para monitoramento de desempenho.
2. PerformanceMonitorInterceptor
Uma solução simples para obter funcionalidade básica de monitoramento para o tempo de execução de nossos métodos, podemos fazer uso da classePerformanceMonitorInterceptor do Spring AOP (Aspect Oriented Programming).
O Spring AOP permite definir preocupações transversais em aplicativos, ou seja, código que intercepta a execução de um ou mais métodos, a fim de adicionar funcionalidade extra.
A classePerformanceMonitorInterceptor é um interceptor que pode ser associado a qualquer método personalizado a ser executado ao mesmo tempo. Esta classe usa uma instânciaStopWatch para determinar a hora de início e de término da execução do método.
Vamos criar uma classePerson simples e uma classePersonService com dois métodos que monitoraremos:
public class Person {
private String lastName;
private String firstName;
private LocalDate dateOfBirth;
// standard constructors, getters, setters
}
public class PersonService {
public String getFullName(Person person){
return person.getLastName()+" "+person.getFirstName();
}
public int getAge(Person person){
Period p = Period.between(person.getDateOfBirth(), LocalDate.now());
return p.getYears();
}
}
Para fazer uso do interceptador de monitoramento Spring, precisamos definir um pointcut e um orientador:
@Configuration
@EnableAspectJAutoProxy
@Aspect
public class AopConfiguration {
@Pointcut(
"execution(public String com.example.performancemonitor.PersonService.getFullName(..))"
)
public void monitor() { }
@Bean
public PerformanceMonitorInterceptor performanceMonitorInterceptor() {
return new PerformanceMonitorInterceptor(true);
}
@Bean
public Advisor performanceMonitorAdvisor() {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression("com.example.performancemonitor.AopConfiguration.monitor()");
return new DefaultPointcutAdvisor(pointcut, performanceMonitorInterceptor());
}
@Bean
public Person person(){
return new Person("John","Smith", LocalDate.of(1980, Month.JANUARY, 12));
}
@Bean
public PersonService personService(){
return new PersonService();
}
}
O pointcut contém uma expressão que identifica os métodos que queremos que sejam interceptados - em nosso caso, o métodogetFullName() da classePersonService.
Depois de configurar o beanperformanceMonitorInterceptor(), precisamos associar o interceptor ao pointcut. Isso é conseguido através de um consultor, conforme mostrado no exemplo acima.
Finalmente, a anotação@EnableAspectJAutoProxy ativaAspectJ support para nossos beans. Simplificando, AspectJ é uma biblioteca criada para tornar o uso do Spring AOP mais fácil por meio de anotações convenientes como@Pointcut.
Depois de criar a configuração, precisamosset the log level of the interceptor class to TRACE, pois este é o nível em que ele registra as mensagens.
Por exemplo, usando Jog4j, podemos fazer isso por meio do arquivolog4j.properties:
log4j.logger.org.springframework.aop.interceptor.PerformanceMonitorInterceptor=TRACE, stdout
Para cada execução do métodogetAge(), veremos a mensagemTRACE no log do console:
2017-01-08 19:19:25 TRACE
PersonService:66 - StopWatch
'com.example.performancemonitor.PersonService.getFullName':
running time (millis) = 10
3. Interceptor de monitoramento de desempenho personalizado
Se quisermos quemore control over the way the performance monitoring esteja pronto, podemos implementar nosso próprio interceptor personalizado.
Para isso, vamos estender a classeAbstractMonitoringInterceptor e substituir o métodoinvokeUnderTrace() para registrar o início, o fim e a duração de um método, bem como um aviso se a execução do método durar mais de 10 ms:
public class MyPerformanceMonitorInterceptor extends AbstractMonitoringInterceptor {
public MyPerformanceMonitorInterceptor() {
}
public MyPerformanceMonitorInterceptor(boolean useDynamicLogger) {
setUseDynamicLogger(useDynamicLogger);
}
@Override
protected Object invokeUnderTrace(MethodInvocation invocation, Log log)
throws Throwable {
String name = createInvocationTraceName(invocation);
long start = System.currentTimeMillis();
log.info("Method " + name + " execution started at:" + new Date());
try {
return invocation.proceed();
}
finally {
long end = System.currentTimeMillis();
long time = end - start;
log.info("Method "+name+" execution lasted:"+time+" ms");
log.info("Method "+name+" execution ended at:"+new Date());
if (time > 10){
log.warn("Method execution longer than 10 ms!");
}
}
}
}
As mesmas etapas para associar o interceptor personalizado a um ou mais métodos, como na seção anterior, precisam ser seguidas.
Vamos definir um ponto de corte para o métodogetAge() dePersonServicee associá-lo ao interceptor que criamos:
@Pointcut("execution(public int com.example.performancemonitor.PersonService.getAge(..))")
public void myMonitor() { }
@Bean
public MyPerformanceMonitorInterceptor myPerformanceMonitorInterceptor() {
return new MyPerformanceMonitorInterceptor(true);
}
@Bean
public Advisor myPerformanceMonitorAdvisor() {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression("com.example.performancemonitor.AopConfiguration.myMonitor()");
return new DefaultPointcutAdvisor(pointcut, myPerformanceMonitorInterceptor());
}
Vamos definir o nível de registro paraINFO para o interceptor personalizado:
log4j.logger.com.example.performancemonitor.MyPerformanceMonitorInterceptor=INFO, stdout
A execução do método getAge() produziu a seguinte saída:
2017-01-08 19:19:25 INFO PersonService:26 -
Method com.example.performancemonitor.PersonService.getAge
execution started at:Sun Jan 08 19:19:25 EET 2017
2017-01-08 19:19:25 INFO PersonService:33 -
Method com.example.performancemonitor.PersonService.getAge execution lasted:50 ms
2017-01-08 19:19:25 INFO PersonService:34 -
Method com.example.performancemonitor.PersonService.getAge
execution ended at:Sun Jan 08 19:19:25 EET 2017
2017-01-08 19:19:25 WARN PersonService:37 -
Method execution longer than 10 ms!
4. Conclusão
Neste tutorial rápido, apresentamos o monitoramento de desempenho simples no Spring.
Como sempre, o código-fonte completo deste artigo pode ser encontradoover on Github.