AOP (Aspektorientierte Programmierung) ist ein Programmierparadigma, das die objektorientierte Programmierung erweitert. Es werden Querschnittsbelange wie z. B. Caching, Security, Transaktionen und Auditierung gekapselt, die das System an mehreren Stellen benötigt. Diese Funktionalitäten werden nicht an mehreren Stellen (Klassen, Methoden) wiederholt implementiert, sondern an eine zentrale Stelle ausgelagert. Die ausgelagerte Funktionalität wird zur Compile- oder Laufzeit an den Stellen hinzugefügt, an denen sie gebraucht wird. Die Menge dieser Stellen nennt man Pointcut.
Bei der Entwicklung von Spring AOP wird folgendes Pattern für die Pointcut-Definition benutzt: execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(param-pattern) throws-pattern?). Es ist manchmal schwierig, ein gemeinsames Pattern für alle Methoden, die gematcht werden sollen, zu finden. In so einem Fall empfiehlt sich eine elegantere Variante und zwar die Erstellung einer eigenen Annotation, wie zum Beispiel @Transactional für die Pointcut-Definition.
Der Artikel zeigt anhand von Codebeispielen wie mit Spring AOP eine eigene Annotation für die Pointcut-Definition geschrieben wird. Für das Beispiel wurde mit Spring Initializr eine Spring Boot Applikation generiert.
Die Realisierung erfolgt in den folgenden Schritten:
Als erstes wird Spring AOP eingeschaltet:
@EnableAspectJAutoProxy @SpringBootApplication public class CustomAnnotationApplication { public static void main(String[] args) { SpringApplication.run(CustomAnnotationApplication.class, args); } }
Der nächste Schritt ist die Erzeugung der eigenen Annotation:
@Retention(RetentionPolicy.RUNTIME) public @interface MyCustomAnnotation { String value(); }
Der nächste Schritt ist die Definition der AOP-Logik. In unserem Fall ist das die Messung der Performanz:
@Aspect @Component public class MonitorPerformance { @Around("execution(@de.oio.custom.annotation.MyCustomAnnotation * *(..)) && @annotation(myCustomAnnotation)") public Object monitor(ProceedingJoinPoint joinPoint, MyCustomAnnotation myCustomAnnotation) throws Throwable { long startTime = System.currentTimeMillis(); Object result = joinPoint.proceed(); long endTime = System.currentTimeMillis(); long duration = endTime - startTime; System.out.println(myCustomAnnotation.value()+": "+duration+"ms"); return result; } }
Die Annotation kann jetzt benutzt werden:
@Controller public class MyController { @RequestMapping("/customAnnotation/hello") @MyCustomAnnotation("Hello Custom Annotation") public @ResponseBody String getHelloWorld(){ try { Thread.sleep(3000); } catch (InterruptedException e) { throw new RuntimeException("Sleep Interrupted", e); } return "Hello World"; } }