Programowanie zorientowane aspektowo w Springu

     W dzisiejszych czasach istnieje wiele paradygmatów programowania. Projektanci oraz developerzy w zależności od potrzeb decydują, które z nich wybrać by powstał dobry, optymalny i działający program. Jednym z nich, o którym będzie mowa w tym artykule, jest tzw. programowanie zorientowane aspektowo.

Na wstępnie chciałbym posłużyć się dobrym przykładem, opisanym w książce pt. „Spring w akcji.” - Craig Walls. Pozwoli on zrozumieć koncept tego podejścia oraz w późniejszej części artykułu odpowiedzieć po co stosowane są aspekty.

     Nie przedłużając już dłużej cofnijmy się teraz do ciepłych letnich dni, gdy panowały wysokie temperatury i było bardzo gorąco. Dla własnego komfortu klimatyzacja jest świetnym rozwiązaniem. Niestety jej wadą jest zużycie energii, za którą musimy zapłacić. Posiadamy w domu licznik rejestrujący kilowaty, i co pewien okres czasu odwiedza nas pracownik, który odczytuje go i przekazuje informacje do zakładu energetycznego.
Co by się stało, gdyby nie było takiego licznika? Pracownik z zakładu nie odwiedzałby domów, a zgłoszenie zużycia energii byłoby zadaniem właściciela. Większość osób nie przejmowałaby się uważną rejestracją zużycia światła czy klimatyzacji.
Kontrola tego procesu jest ważna, lecz dla właściciela jest to czynność pasywna. Koszenie trawników, odkurzanie domu to przykłady czynności, w które właściciel jest aktywnie zaangażowany.
W systemach informatycznych pewne funkcje są „podobne” do liczników elektrycznych w domach, muszą być wywoływane w wielu miejscach aplikacji, lecz nie chcemy ich jawnie tam wywoływać. Bezpieczeństwo, logowanie w aplikacji są ważne, lecz czy nie lepiej by obiekty były skoncentrowane na logice biznesowej, a te aspekty byłyby obsługiwane przez inne funkcje?
Metody przenikające wiele miejsc w aplikacji nazywane są zagadnieniami przecinającymi (ang. Cross-Cutting Concerns). Oddzielenie tych zagadnień od logiki biznesowej jest to programowanie zorientowane aspektowo. Na poniższym rysunku zobrazowałem przykładowe tego zastosowanie.

 

Rysunek 1. Zagadnienia przecinające w typowej strukturze aplikacji (opracowane z wykorzystaniem draw.io)

 

     Aspekt może być wykorzystany ponownie w różnych lokalizacjach. Jest to klasa, która może być zastosowana do różnych części projektu w zależności od konfiguracji.
Jakie czerpiemy z tego korzyści? Logika typowych modułów usługowych jest uporządkowana, zawierają kod realizujący główne ich cele i funkcjonalności. Zagadnienia drugorzędne są w jednym miejscu, nie są rozrzucone po kodzie.
Pracownik zakładu energetycznego odwiedzający domy ma główne zadanie: odczytać liczniki właścicieli domów. Analogicznie, aspekt ma główne zadanie- wykonać daną czynność będącą celem ich istnienia. Jest to tak zwana porada - czynność, która ma zostać wykonana oraz wskazanie momentu, kiedy ma być wywołana. Spójrzmy na poniższy przykład:

Rysunek 2. Przykład aspektu z poradami

 

     Używając adnotacji @Before wołana metoda drinkCoffee() zostanie wywołana przed metodą work() z klasy WorkerController.
Podobnie pozostałe:
• @AfterReturning- metoda porady wywołana jest po zakończeniu działania metody,
• @AfterThrowing- jeśli zostanie rzucony wyjątek.
Istnieją jeszcze dwie adnotacje @Around oraz @After, a ich metody porady zostaną wywołane przed i po w przypadku pierwszej oraz w przypadku drugiej za, niezależnie od jej wyniku.
Celem osoby od kontroli liczników jest dany dom, który ma obowiązek odwiedzić. Podobnie w aplikacjach jest bardzo dużo miejsc, gdzie mogłaby być stosowana porada. Miejsca takie jak wywołanie metody, obsługa wyjątku, modyfikacja obiektu czy pola nazywane są punktami złączenia (ang. Join Point).
Niemal niemożliwym jest by jeden pracownik zdołał odczytać wszystkie domy podlegające kontroli przez zakład energetyczny i lista ta jest zawężona. Używając tzw. punktów przecięcia (ang. PointCut) można ograniczyć listę wyżej wspominanych punków złączenia:

Rysunek 3. Przykład aspektu z poradami oraz punktem przecięcia

 

      Podając odpowiednie parametry programista może zdecydować, czy wywołanie ma nastąpić dla danego pakietu, klasy, metody publicznej, prywatnej czy też gdy aplikacja rzuci wyjątek.
Podsumowując, dzięki zastosowaniu aspektów w programowaniu obiektowym możemy zachować czytelność kodu, rozdzielić go na moduły wielokrotnego użytku. Pozwala to ograniczyć powielanie kodu, być bardziej zgody z regułą DRY (Don’t repeat yourself) oraz skupić się na głównych funkcjonalnościach klas. Jednak należy pamiętać by aspekty stosować w dobry i przemyślany sposób.


Źródło: Craig Walls – „Spring w akcji. Wydanie IV”.


Mateusz

Programista Java w Nexio Management

Powrót