Programowanie zorientowane aspektowo (AOP) to podejście do programowania, które umożliwia przechwycenie działań wskazanej metody, w celu uruchomieniu jakiegoś fragmentu kodu przed lub po logice wykonującej się w przechwytywanej metodzie.
Przykład
Przykładowo jest metoda foo, której zadaniem jest zapis informacji i wyświetlenie komunikatu o zapisaniu. W tradycyjnym podejściu jedną metodę zapisuje się jedna pod drugą.
public void foo() { save(); System.out.println("saved"); }
W AOP dąży się do czystości kodu, poprzez izolacje odpowiedzialności. Metody robią to tylko za co są odpowiedzialne, nie miesza się logik jakimi są zapisywanie i wypisywanie informacji w oknie konsoli.
W podejściu AOP metoda foo zapisuje jedynie informacje. Inna metoda odpowiedzialna za wypisywanie tekstu na ekranie nasłuchuje metodę foo i kiedy foo skończyło swoją pracę to metoda nasłuchująca wykonuje swoje działanie.
Implementacja
Zależnością jaką trzeba dodać do projektu jest:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
Zależność umożliwia na między innymi na wykorzystanie trzech kluczowych porad, które w parametrze przyjmują ścieżkę do metody jaka ma zostać przechwycona:
- @Around – Metoda oznaczona tą adnotacją wykona się przed lub zamiast metody wskazanej w parametrze.
- @Before – Metoda oznaczona tą adnotacją wykona się przed metodą wskazaną w parametrze.
- @After – Metoda oznaczona tą adnotacją wykona się po metodzie wskazanej w parametrze.
Metoda, którą chcemy przechwycić to metoda sayHello
public String sayHello() { return "Hello " + ""; }
Żeby stworzyć możliwość jej przechwycenia trzeba utworzyć klasę z adnotacjami:
- @Aspect
- @Component
@Aspect @Component public class HelloAspect { @Around("@annotation(Hello)") public void aroundHello(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("aroundHello"); joinPoint.proceed(); } @Before("@annotation(Hello)") public void beforeHello() { System.out.println("beforeHello"); } @After("execution(String pl.bykowski.springbootaop.HelloApi.sayHello())") public void afterHello() { System.out.println("afterHello"); } }
W poniższym przypadku zostały zaimplementowane trzy metody (zwane również poradami). W przypadku wywołania metody sayHello kolejno uruchomią się metody:
- aroundHello
- beforeHello
- sayHello
- afterHello
Warto zwrócić uwagę, że porada @Around przyjmuje w parametrze ProceedingJoinPoint. Dzięki temu, możliwe jest przekazanie wątku dalej do metody przechwytywanej. Bez wywołania joinPoint.proceed() to metoda przechwytywana nie wykonałaby się. Takie działanie może mieć swoje uzasadnienie w wybranych przypadkach.
Podsumowanie
Programowanie zorientowane aspektowo pozwala zachować czytelność kodu. Jednak odbywa się to kosztem zaburzenia naturalnego przepływu działania programu i jest w sprzeczności z zasadami programowania obiektowego. Dlatego należy stosować AOP rozsądnie i przemyślanie. Najczęściej wykorzystuje się go do logowania informacji lub zabezpieczeń.