poniedziałek, 26 maja 2008

EJB3 - interceptory

Jedną z nowości w specyfikacji EJB w wersji trzeciej są interceptory, poprzez które w prosty sposób można zastosować w budowanym systemie paradygmat programowania zorientowanego aspektowo.
Interceptory w EJB3 mogą odnosić się zarówno do cyklu życia ziaren jak i ich metod biznesowych. Implementuje się je w postaci metod. Metody-interceptory mogą znajdować się w klasach ziaren jak i w klasach bazowych tych ziaren, ale także mogą się znajdować w odrębnych klasach (klasy interceptorów). Metody-interceptory mogą mieć dowolny poziom dostępu (public, package, protected, private), ale nie mogą być za to ani static, ani final.
Warto zaznaczyć, że implementacja interceptorów nie jest niczym ograniczona, gdyż można z nich wywoływać JNDI, JMS, inne ziarna, JDBC, oraz EntityManager'a.

1. InvocationContext

Metoda-interceptor do skutecznego działania musi mieć przede wszystkim kontekst wywołania, tj. instancję ziarna, informację o wywoływanej metodzie biznesowej oraz jej parametrów, a także rezultatu wywołania. Te dane można uzyskać poprzez obiekt InvocationContext, który jest przekazywany jako parametr do metody-interceptora.
Na szczególną uwagę zasługuje metoda InvocationContext.proceed(). Jej wywołanie powoduje przejście sterowania do następnego interceptora lub (jeśli jest wywołana w ostatnim interceptorze w łańcuchu) do metody biznesowej ziarna (jeśli jest to interceptor metod biznesowych).

2. Klasa interceptorów

Klasa interceptorów jest zwykłą klasą(nie musi być nawet oznaczona specjalną adnotacją), która po prostu posiada w sobie zdefiniowane metody-interceptory. Klasy te muszą posiadać publiczny bezargumentowy konstruktor.
Cykl życia interceptorów jest ściśle związany z cyklem życia ziarna do którego jest przypisany.
Klasy interceptorów można przypisywać do całego ziarna lub do metod biznesowych ziaren z osobna poprzez adnotację @Interceptors, który jako argument przyjmuje listę klas interceptorów.
W praktyce dołączanie klasy interceptorów wygląda mniej więcej następująco:
@Stateless
@Interceptors(pl.dwalczak.Interceptor1.class)
public class Ziarno {
...
  @Interceptors(pl.dwalczak.Interceptor2.class)
  public void metodaBiznesowa() {
  }
}

3. Interceptory cyklu życia ziaren

Aby dana metoda była interceptorem cyklu życia ziarna należy ją oznaczyć jedną z następujących adnotacji, odpowiednio do pożądanej fazy życia:   - @PostConstruct,   - @PostActivate,   - @PreDestroy,   - @PrePassivate Jeżeli metoda jest zdefiniowana w klasie ziarna, to powinna mieć następującą sygnaturę:
void <METHOD>()
Natomiast, jeżeli znajduje się w klasie interceptorów to powinna ona wyglądać tat:
void <METHOD>(InvocationContext)

4. Interceptory metod biznesowych

Aby dana metoda była interceptorem dla metod biznesowych, należy ją oznaczyć adnotacją @AroundInvoke.
W jednej klasie interceptora, ziarna, bądź klasie bazowej ziarna można tą adnotacją oznaczyć tylko jedną metodę, niemniej nie prowadzi to do ograniczenia, żeby metoda biznesowa ziarna miała tylko jeden interceptor. Wszystkie interceptory zdefiniowane w klasach bazowych, interceptorach podłączonych poprzez adnotację @Interceptors oraz ten zdefiniowany w klasie ziarna będą obowiązywać, a kolejność ich wykonania będzie zgodna z kolejnością ich deklarowania oraz hierarchią dziedziczenia klasy ziarna.
Metody oznaczone adnotacją @AroundInvoke są wykonywane na tym samycm stosie wywołania co metoda biznesowa. Taka metoda powinna zwracać wartość zwróconą przez metodę biznesową, oraz być zdolną do wyrzucenia wyjątku wyrzucanego przez metodę biznesową. Z tego powodu powinna mieć następującą sygnaturę:
Object <METHOD>(InvocationContext) throws Exception
Interceptor aby przekazać sterowanie dalej, tj. do następnego interceptora, bądź metody biznesowej, powinien wywołać metodę proceed na obiekcie InvocationContext.

5. Zasoby pomocnicze

Specyfikacja EJB3
The Interceptor Pattern

Brak komentarzy: