AspectJ – Join Point i pointcut, teoria

Co dziś miałbym przedstawić?

Wiemy już mniej więcej co to jest programowanie aspektowe i jak się to je. Wiemy jak zdefiniować poradę (i czym mniej więcej ona jest), umieścić ją w kodzie za pomocą punktu przecięcia i uruchomić program. Należałoby teraz powiedzieć czym są punkty przecięcia. Jednakże jest to dość skomplikowane i na razie musimy załapać trochę teorii.

Vox populi i moja teoria języków

W książce „AspectJ In Action” Ramnivas Laddad podaje pewne bardzo ciekawe podejście do problemu zdefiniowania czym jest punkt wejścia, a czym punkt przecięcia. Mekk w komentarzu do pierwszego tekstu o AspectJ prosił o dokładniejsze omówienie tego problemu. Zatem oto jestem 😉

Każdy paradygmat programowania definiuje pewne ogólne pojęcia. W programowaniu obiektowym są to obiekty i ich interakcje pomiędzy sobą. W programowaniu proceduralnym mamy do czynienia z procedurami, a w przypadku programowania imperatywnego takim pojęciem jest instrukcja. W przypadku programowania aspektowego mamy do czynienia z aspektem, czyli pewnym elementem logiki programu, który można odseparować od reszty. W klasycznym modelu różne aspekty przeplatają się w programie tworząc coś w rodzaju warkocza (ang. tress). Rozumienie kodu jest podobne do rozplątywania warkocza. Proces ten jest żmudny i może być nieprzyjemny. W programowaniu aspektowym poszczególne elementy są splatane przez tkacza (ang.weaver) tak jak płótno. Dzięki czemu możemy łatwo wyciągnąć pojedynczą nić – aspekt. Idąc tym torem rozumowania stajemy jednak przed pytaniem czym są zatem punkty przecięcia i punkty wejścia w programowaniu aspektowym?
Wróćmy na chwilę do świata obiektów. W naszym Obiektowie (genialne pojęcie wymyślone przez Piotr Rajce przy tłumaczeniu
Head First Object-Oriented Analysis and Design) na poziomie abstrakcji mamy Obiekty i ich interakcje. Jeżeli jednak zejdziemy do dzielnicy Javowo to zobaczymy, że poza Obiektami mamy jeszcze Klasy, Interfejsy, Enumy, Adnotacje i wiele innych elementów języka. No właśnie… języka… Język programowania niezależnie od realizowanych paradygmatów można podzielić na dwa elementy – specyfikację i implementację. Specyfikacja jest to opis jak realizowane są paradygmaty, jakie elementy zawiera język w celu osiągnięcia tego celu i jak elementy języka mają się do modelu ogólnego. Implementacja znowuż to praktyczna realizacja specyfikacji.
W takim kontekście AspectJ jest rozszerzeniem języka Java o paradygmat aspektowy. Rozszerzenie to specyfikuje nowe elementy języka – punkty dostępu, punkty przecięcia, porady, deklaracje oraz ich interakcję z innymi, już istniejącymi, elementami, a także implementuje tą dodatkową specyfikację.
Uff… rozumiecie coś z tego? Jeżeli tak to dobrze, jeżeli nie to też dobrze.

Każdy programuje aspektowo

Każdy chyba liznął „programowania w html i css”. Można zatem powiedzieć, że w pewnym sensie miał już do czynienia z programowaniem aspektowym. Nie jasne? Wróćmy więc od teorii. Paradygmat aspektowy mówi nam o aspektach. Nie mówi nic o konkretnej realizacji. Jeżeli popatrzymy na zwykłe dokumenty html i css oraz to jak realizowana jest ich obsługa w przeglądarce to pewne skojarzenia zaczynają się same nasuwać. Po pierwsze dokument html jest zbiorem punktów dostępu. Każdy element dokumentu jest takim punktem ponieważ można dla niego stworzyć regułę CSS. Każdy zdefiniowany selektor w dokumencie CSS jest punktem przecięcia. Wskazuje on jaki punkt dostępu należy wybrać i zaaplikować mu poradę – zestaw stylów.
Podobnie można opisać bazę danych. Każda krotka jest punktem dostępu. Zapytanie języka danych jest punktem przecięcia. Rezultat jest poradą.

Punkt dostępu i punk przecięcia w Javie

Popatrzmy zatem na kod Javy. Każda metoda jest punktem dostępu. Punktami takimi w rozumieniu AspectJ – czyli konkretnej implementacji aspektowej, są też – inicjacja klasy (jej ładowanie), obiektu (jego tworzenie), porada (tak jak metoda) oraz aspekt (tak jak klasa – aspekty są domyślnie singletonami). Dość specyficznymi w „załapaniu” punktami dostępu są też miejsca odczytu i przypisania wartości do pola obiektu. AspectJ nie umieszcza na liście punktów dostępu elementów kodu takich jak pętle, instrukcje warunkowe, bloki kodu, etykiety (tak w Javie mamy etykiety).
Punktem przecięcia jest zdefiniowany, za pomocą specjalnego języka, podzbiór punktów dostępu. Punkt przecięcia używa w swoich definicjach składni podobnej do tej znanej z sygnatur metod. Mamy zatem możliwość wyboru punktu dostępu na podstawie nazwy lub jej części np. * *.set*(..) – oznacza dowolną metodę, której nazwa zaczyna się od set, modyfikatora dostępu, nazwy pakietu, ilości oraz rodzaju argumentów w metodzie, adnotacji, użytych typów generycznych, zwracanych wyjątków, hierarchii dziedziczenia np. * NKWD+ oznacza każdą klasę dziedziczącą po NKWD (wybór tylko w dół hierarchii). Do punktu przecięcia, a w praktyce do wszystkich wybranych przez niego punktów dostępu, stosuje się poradę.

Podsumowanie

Zrozumienie modelu w jakim pracują punkty przecięcia jest bardzo trudne, ale to kluczowy element AspectJ. Na całe szczęście można pociąć ten temat na mniejsze i prostsze dawki. Na początek wystarczy to co już widzieliśmy, czyli dostęp do metod i typów na podstawie nazwy lub dodanej im adnotacji.
Na chwilę obecną nie będę poruszał problemu punktów przecięcia dla kontekstu wywołania.

4 myśli na temat “AspectJ – Join Point i pointcut, teoria

  1. W metaforze bazodanowej poradą byłby chyba raczej trigger – bądź to bądź jest to coś co się uruchamia ortogonalnie do głównej logiki przetwarzania i może być obwarowane warunkami…

  2. mam np coś takiego

    public class SomeClass(){

    private Pigeon pigeon;

    public void doStuff(){
    stuffService.doStuff();
    }

    public Pigeon getPigeon(){
    return pigeon;
    }

    mam metodę doStuff, czy mogę w punkcie przecięcia dla niej uzyskać dostęp do obiektu pigeon ?

  3. @machu, tak. Jak używasz AspectJ z adnotacjami to przykładowo dostęp przed doStuff():

    @Aspect
    public class SomeClassAspect{
      @Pointcut("call(* SomeClass.doStuff())")
      public void doStuff(){}
    
      @Before("doStuff()")
      public void before(JoinPoint tjp) {
         SomeClass sc = (SomeClass)(tjp.getTarget());
         sc.getPigeon();
      }
    }

    przy czym piszę to z pamięci i musisz dokładnie sprawdzić składnię 😀

Napisz odpowiedź

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *

To create code blocks or other preformatted text, indent by four spaces:

    This will be displayed in a monospaced font. The first four 
    spaces will be stripped off, but all other whitespace
    will be preserved.
    
    Markdown is turned off in code blocks:
     [This is not a link](http://example.com)

To create not a block, but an inline code span, use backticks:

Here is some inline `code`.

For more help see http://daringfireball.net/projects/markdown/syntax