Zaczynamy mini kurs programowania aspektwego z ApectJ i Eclipse. Nie chcę wnikać w spinanie projektów z mavenem (tak z lenistwa), a zatem będzie tylko w eclipse.

Instalacja softu

Z tej strony pobieramy odpowiedni dla nas pakiecik i restartujemy Eclipse. Zakładam, że wiesz jak instalować plugin eclipsowy za pomocą Update Site. Jeżeli nie to sorry Winnetou. Kurs będzie mocno Eclipse only.
Następnie tworzymy nowy projekt AspectJ. Zostaniemy zapytani czy chcemy włączyć mechanizm weaveringu i zrestartować Eclipse. Oczywiście włączamy go i restartujemy IDE.

Podstawowe pojęcia

W tradycyjnym modelu obiektowym gdy zaczynamy pisać program to okazuje się, że w pewnym momencie należy do naszego kodu dodać kilkanaście różnych ciekawych czy nie, ale wymaganych funkcjonalności. Zazwyczaj jest to logowanie, kontrola dostępu, jakieś duperele związane z profilowaniem. Robiąc to za pomocą klasycznych metod zazwyczaj łamiemy dwie zasady. Po pierwsze SRP ponieważ nasza klasa zaczyna mieć wiele odpowiedzialności. A to logowanie, a to security, a tu jeszcze admin mówi, żeby włączyć profilowanie w jednym miejscu i natłuc raportów. Poza tym robi się burdel w kodzie. Oczywiście w pewnym momencie dochodzimy do wniosku, że większość z tych bajerów nie jest nam potrzebna i łamiemy OCP. Ponieważ by je wyłączyć zaczynamy grzebać w oryginalnym kodzie. Tu z pomocą przychodzą nam aspekty. Aspekt jest to moduł aplikacji zawierający jakąś funkcjonalność, która jest wtłaczana do kodu za pomocą kompilatora aspektowego. Aspekt jest opisany za pomocą specjalnego języka, na którego podstawie kompilator odpowiednio modyfikuje kod wynikowy w procesie kompilacji. Poniżej kilka ważnych pojęć
Punkt dostępu – ang. Join Point – dowolny punkt w kodzie, w którym kompilator aspektowy może wstawić kod aspektu. To czym jest ten punkt zależy od konkretnej implementacji języka aspektowego. W przypadku AspectJ są to metody, klasy, pola.
Punkt przecięcia – ang. Pointcut – konkretny punkt dostępu do którego stosowany jest dany aspekt.
Porada – ang. advice – kod który jest wstawiany.
Wiem, że osoby, które miały do czynienia z programowaniem aspektowym uznają ten opis za uproszczony, ale KISS MY ASS (Keep Is Simple Stupid. Mayby You Are Support Soft).

Co to jest AspectJ?

Znowu upraszczając jest to rozszerzenie języka Java o kilka słów kluczowych i mechanizm weaveringu, czyli właśnie wkompilowywania kodu. Inaczej rzecz ujmując jest to biblioteka, która zawiera specjalny kompilator, będący rozszerzeniem kompilatora javy o funkcjonalność jaką jest obsługa aspektów. Zawiera specjalnego agenta JVM, który może wykonać pracę kompilatora w trakcie ładowania kodu. Jest to zacne i przydatne rozwiązanie.
AspectJ wspiera dwa rodzaje składni. Pliki .aj, które są „naturalne” w jego środowisku oraz mechanizm oparty o adnotacje i zwykłe klasy javy. Przy czym każdy prawidłowy plik java jest prawidłowym plikiem aspektowym. Koniec końców AspectJ jest tylko rozszerzeniem języka (trochę jak C++ do C), a nie czymś całkowicie nowym.

Zajawka

Dzisiejszą część poświęcimy tylko na prostą aplikację w tylu „hello world”, ale pozwoli ona załapać Ci jak działa programowanie aspektowe. Na początek mamy kod taki jak poniżej:

Listing 1. Bazowa aplikacja

package pl.koziolekweb.blog.aspectj;

public class Main {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		Service service = new Service();
		service.welcome();
		service.welcome("Koziołek");
	}

}
//....
package pl.koziolekweb.blog.aspectj;

public class Service {
	public void welcome() {
		System.out.println("Witamy w systemie");
	}

	public void welcome(String name) {
		System.out.println("Witaj " + name);
	}
}

Naszym zadaniem jest zabezpieczyć aplikację przed niepożądanymi wywołaniami. Posłuży nam do tego specjalna klasa NKWD:

Listing 2. Klasa NKWD – odpowiada za bezpieczeństwo

package pl.koziolekweb.blog.aspectj;

import java.util.Scanner;

public class NKWD {

	private boolean isAuth = false;

	public void auth() {
		if (isAuth) {
			return;
		} else {
			System.out.print("podaj hasło: ");
			Scanner scanner = new Scanner(System.in);
			String password = scanner.next();
			if ("dupa".equals(password)) {
				isAuth = true;
			}
			else{
				throw new RuntimeException("Wypad na Łubiankę");
			}
		}
	}
}

Pytanie co zrobimy w klasycznym podejściu? Pewno wystarczy utworzyć fabrykę obiektów NKWD, która będzie dbała o to by do każdego wątku był przyporządkowany odpowiedni obiekt NKWD. Będziemy go pobierać w każdej metodzie i w razie czego sprawdzać… no cóż… chłopaki od php zapewne by na tym poprzestali, ale mają łatwiej, bo jest u nich funkcja require\_once i przetwarzanie skryptu zatem można takie sztuki robić. My niestety używamy języka programowania i zastosujemy programowanie aspektowe.
Stworzymy zatem aspekt, który będzie przed każdym wywołaniem metody welcome sprawdzał czy wszystko śmiga.

Listing 3. Nasz pierwszy aspekt

package pl.koziolekweb.blog.aspectj;

public aspect SecurityAspect {
	private NKWD nkwd = new NKWD();
	
	pointcut auth() : call( * Service.welcome(..));
	
	before() : auth() {
		System.out.println("NKWD działa");
		nkwd.auth();
	}
}

Kompilujemy i uruchamiamy jako aplikację AspectJ. Efekt:

Listing 4. wyniki działania naszego pierwszego aspektu

NKWD działa
podaj hasło: dupa
Witamy w systemie
NKWD działa
Witaj Koziołek

Chwila ze składnią

Za pomocą słowa pointcut definiujemy miejsce przecięcia. Format jest dość swobodny w przypadku AspectJ zazwyczaj używamy składni bardzo zbliżonej do UMLowego definiowania sygnatur metod. Znak * oznacza dowolne słowo, a .. dowolną ilość słów.
Słowo before wskazuje, że dana porada będzie uruchamiana przed wywołaniem dowolnej metody pasującej do wskazanego punktu przecięcia.

Podsumowanie

Czytam „AspectJ in Action” i mam nadzieję, że powstanie kacusiowa recenzja.