Spring Performance Logging
1. Überblick
In diesem Tutorial werden einige grundlegende Optionen erläutert, die das Spring Framework für die Leistungsüberwachung bietet.
2. PerformanceMonitorInterceptor
Als einfache Lösung, um grundlegende Überwachungsfunktionen für die Ausführungszeit unserer Methoden zu erhalten, können wir die KlassePerformanceMonitorInterceptoraus Spring AOP (Aspect Oriented Programming) verwenden.
Spring AOP ermöglicht die Definition von Querschnittsthemen in Anwendungen, dh Code, der die Ausführung einer oder mehrerer Methoden abfängt, um zusätzliche Funktionen hinzuzufügen.
Die KlassePerformanceMonitorInterceptor ist ein Interceptor, der jeder benutzerdefinierten Methode zugeordnet werden kann, die gleichzeitig ausgeführt werden soll. Diese Klasse verwendet eineStopWatch-Instanz, um die Anfangs- und Endzeit des Methodenlaufs zu bestimmen.
Erstellen wir eine einfachePerson-Klasse und einePersonService-Klasse mit zwei Methoden, die wir überwachen werden:
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();
}
}
Um den Spring Monitoring Interceptor nutzen zu können, müssen Sie einen Pointcut und einen Advisor definieren:
@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();
}
}
Der Pointcut enthält einen Ausdruck, der die Methoden identifiziert, die abgefangen werden sollen - in unserem Fall diegetFullName()-Methode derPersonService-Klasse.
Nach dem Konfigurieren derperformanceMonitorInterceptor()-Bean müssen wir den Interceptor dem Pointcut zuordnen. Dies wird durch einen Berater erreicht, wie im obigen Beispiel gezeigt.
Schließlich aktiviert die Annotation@EnableAspectJAutoProxyAspectJ support für unsere Bohnen. Einfach ausgedrückt ist AspectJ eine Bibliothek, die erstellt wurde, um die Verwendung von Spring AOP durch praktische Anmerkungen wie@Pointcut zu vereinfachen.
Nach dem Erstellen der Konfiguration müssen wirset the log level of the interceptor class to TRACE eingeben, da dies die Ebene ist, auf der Nachrichten protokolliert werden.
Mit Jog4j können wir dies beispielsweise über die Dateilog4j.propertieserreichen:
log4j.logger.org.springframework.aop.interceptor.PerformanceMonitorInterceptor=TRACE, stdout
Bei jeder Ausführung der MethodegetAge() wird die MeldungTRACE im Konsolenprotokoll angezeigt:
2017-01-08 19:19:25 TRACE
PersonService:66 - StopWatch
'com.example.performancemonitor.PersonService.getFullName':
running time (millis) = 10
3. Benutzerdefinierter Interceptor zur Leistungsüberwachung
Wennmore control over the way the performance monitoring ausgeführt werden soll, können wir unseren eigenen benutzerdefinierten Interceptor implementieren.
Erweitern Sie dazu die KlasseAbstractMonitoringInterceptorund überschreiben Sie die MethodeinvokeUnderTrace(), um Start, Ende und Dauer einer Methode zu protokollieren, sowie eine Warnung, wenn die Methodenausführung länger als 10 ms dauert:
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!");
}
}
}
}
Die gleichen Schritte zum Zuordnen des benutzerdefinierten Interceptors zu einer oder mehreren Methoden wie im vorherigen Abschnitt müssen ausgeführt werden.
Definieren wir einen Pointcut für diegetAge()-Methode vonPersonService und ordnen Sie ihn dem von uns erstellten Interceptor zu:
@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());
}
Setzen wir die Protokollstufe für den benutzerdefinierten Interceptor aufINFO:
log4j.logger.com.example.performancemonitor.MyPerformanceMonitorInterceptor=INFO, stdout
Die Ausführung der Methode getAge()ergab die folgende Ausgabe:
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. Fazit
In diesem kurzen Tutorial haben wir im Frühjahr eine einfache Leistungsüberwachung eingeführt.
Wie immer finden Sie den vollständigen Quellcode für diesen Artikel inover on Github.