22 listopada 2007

Bieżący kontekst Spring'a w aplikacji JSF

Wyobraźmy sobie, że mamy aplikację Spring + JSF (choć łatwo uogólnić na inne technologie WWW). W pewnej klasie potrzebujemy ziarna zarządzanego Spring, ale nie możemy go wstrzyknąć (ang. injection) poprzez konfigurację, gdyż cyklem życia tej klasy nie zarządza Spring. Przykładem niech będzie komponent JSF. To nie Spring tworzy instancje tych komponentów, tylko JSF, więc nie możemy wstrzyknąć naszej zależności. Poniżej fragment kodu pokazujący jak pobrać bieżący kontekst Spring’a (utworzony przez ContextLoaderListener zdefiniowany w web.xml) i z niego ziarno zarządzane. Oto on:


import javax.faces.context.FacesContext;
import javax.servlet.ServletContext;

import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

ServletContext servletContext = (ServletContext)FacesContext.
getCurrentInstance().getExternalContext().getContext();

WebApplicationContext applicationContext = WebApplicationContextUtils.
getWebApplicationContext(servletContext);

Object springBean = applicationContext.getBean("beanName");

9 komentarzy:

Wojciech pisze...

Szybciej, latwiej, bez rzutowania:
WebApplicationContext applicationContext = FacesContextUtils.getWebApplicationContext(FacesContext.
getCurrentInstance());

Mariusz Lipiński pisze...

Wielkie dzięki,

to jest właśnie najpiękniejsze w blogowaniu - jeśli coś robisz nie optymalnie to jest duża szansa że ktoś wskaże ci właściwą/lepszą drogę.

Waldek Kot pisze...

Cześć,

To co napisaliście to zadziała, ale jest IMHO trochę nieładne. Szkoda też rezygnować z możliwości konfigurowania obiektów i całej pozostałej 'maszynerii', które daje Spring.

Od Spring 2.0 jest taka ciekawa funkcjonalność, która może się przydać w sytuacjach, gdy cyklem życia obiektu nie zarządza Spring. Klasyczny przykład takiej sytuacji podawany przez ludzi ze Spring-a to ORM, ale nie ograniczałbym się tylko do tego.
Ta funkcjonalność to AOP (a dokładniej super eleganckie wykorzystywanie AspectJ przez Spring-a), adnotacja @Configurable oraz atrybut 'abstract' (badz 'lazy-init') przy definicji bean'ów w kontekście aplikacyjnym.

Tak w skrócie: Ten obiekt 'niezarządzany przez Spring-a' powinien być oznaczony adnotacją @Configurable. Następnie, w trakcie działania poprzez pointcut AOP jest wyłapywany moment inicjalizacji takiego bean-a (inicjalizacji w ogóle, a nie przez Springa - np. poprzez operator 'new', przez ORM albo - jak tu - przez JSF), a następnie uruchamia się aspekt, który bierze konfigurację tego bean'a (czytaną z kontekstu aplikacyjnego) i konfiguruje ten nowo utworzony obiekt. W ten sposób można skonfigurować zarówno atrybuty, jak i wstrzelić zależności do tego 'niezarzadzanego' obiektu. Ciekawe jest to, że można uruchomić aspekt zarówno po wywołaniu konstruktora, jak i przed (przed - gdyby się chciało z wewnątrz konstruktora odwoływać do atrybutów obiektu).

Moim zdaniem fajna rzecz.

Link do dokumentacji Spring

Pozdrawiam,
Waldek Kot

Anonimowy pisze...

Bieżący przez ż

Mariusz Lipiński pisze...

Dzięki,

ortograf poprawiony. Dzięki za info Waldek, rzeczywiście ciekawa funkcjonalność.

Mariusz Lipiński pisze...

Jeszcze jedna możliwość - gdybyście kiedykolwiek potrzebowali użyć ziaren Spring'a w filtrach dla serwletów to koniecznie przyjrzyjcie się klasie org.springframework.web.filter.DelegatingFilterProxy. Dobry przykład pod adresem http://forum.springframework.org/showthread.php?p=42415.

Sławomir Wojtasiak pisze...

Witam,

Za bardzo kombinujecie. Spring udostępnia variable resolver, który rozwiązuje powyższy problem. Wystarczy go dodać do faces-config.xml

(variable-resolver)
org.springframework.web.jsf.DelegatingVariableResolver (/variable-resolver)

Dzięki czemu można wstrzykiwać beany zarządzane przez Springa tak samo jak komponenty zarządzane przez JSF. Przykład:

(managed-property)
(property-name)locationGroupManager(/property-name)
(value)#{locationGroupManager}(/value)
(/managed-property)

locationGroupManager - Jest komponentem zarządzanym przez springa.

Pozdrawiam,

Mariusz Lipiński pisze...

OK,

i jak skorzystać z tego np. w filtrze serwletowym? To o czym piszesz rozwiązuje chyba jednak inny problem.

Sławomir Wojtasiak pisze...

Moja odpowiedz nawiązuje do tematu artykułu, który to artykuł zresztą znajduje się w grupie tematycznie związanych z technologią JSF (oraz mówi głównie o wstrzykiwaniu ziaren zarządzanych), więc chyba odpowiedz jest jak najbardziej na miejscu :). Jeślibym trafił na ten artykuł w grupie "Spring" pewnie zaproponowałbym jakieś rozwiązanie niezależne od docelowej technologi, przykładowo AOP. Zauważ że pierwszy komentarz też jest ściśle związany z JSF. Nawiasem mówiąc nie zauważyłem że poruszyłeś już wspomniany przeze mnie temat w poprzednim artykule :).

Przy okazji, wspomniane rozwiązanie z filtrami jest bardzo ciekawe :)

Pozdrawiam,