Skip to main content

Wstrzykiwanie EJB do akcji Struts2 z @EJB

Chciałbym dzisiaj pokazać niekoniecznie odkrywczy, ale dość ciekawy przykład integracji frameworku Struts2 z EJB3 - a wszystko sklejone za pomocą Springa. Tytuł posta jest bowiem tendencyjny: EJB można wstrzykiwać do dowolnych beanów Springowych, ale skupimy się na akcjach Struts2.

Przyjmijmy, że w naszej aplikacji istnieje EJB z lokalnym interfejsem DateServiceLocal:
@Local
public interface DateServiceLocal {
String getCurrentDate(Locale locale, TimeZone timeZone);
}

Usługa prosta, zwraca bieżący czas w podanej strefie czasowej, uwzględniając lokalizację (np. czas w Australii po rosyjsku). Z drugiej strony chcemy skorzystać z tej usługi w akcji Struts2. Jednak brzydzi nas (anty)wzorzec Service Locator, a tym bardziej szastanie na prawo i lewo klasą InitialContext. Mamy XXI wiek, "don't call me, I'll call you" głosi hasło reklamowe wzorca Dependency Injection. Nasza akcja powinna wyglądać tak:

public class DateAction extends ActionSupport {

@EJB
private DateServiceLocal dateService;
private Locale language;
private TimeZone timeZone;

public String execute() throws Exception {
addActionMessage(dateService.getCurrentDate(language, timeZone));
return SUCCESS;
}

/*...*/
}


Mamy pole oznaczone standardową adnotacją @EJB (uwaga: nie potrzebuje settera) oraz pola language i timeZone pochodzące z formularza. Potem w execute() najzwyczajniej w świecie wołamy metodę lokalnego interfejsu naszego EJB. To wszystko! Jak przygotować środowisko do tak wygodnej integracji?

Przede wszystkim przygotowujemy aplikację Struts2 zintegrowaną ze Springiem (cyklem życia akcji ma zarządzać kontener IoC). Jak to zrobić, już pokazywałem, chociażby w artykule "Elegancki CRUD w jednej akcji Struts2". Następnie tworzymy springowe proxy odwołujące się do wskazanego EJB. Jeśli nigdy nie korzystaliście z tej funkcji: Spring tworzy specjalne proxy, które z jednej strony zachowuje się jak zwykły bean springowy, jednak w rzeczywistości deleguje wszystkie wywołania do wskazanego EJB. Dzięki zastosowani przestrzeni nazw jee wystarczy wpisać:


<jee:local-slsb
id="dateService"
jndi-name="dateserver-ear-${project.version}/DateService/local"
business-interface="com.blogspot.nurkiewicz.dateserver.DateServiceLocal"/>


Przykład testowałem na JBossie 5.0.1, który poprzedza nazwy JNDI nazwą EARa zawierającego EJB-JAR. A ponieważ maven domyślnie dokleja wersję do nazwy artefaktu ear (dateserver-ear-0.0.1-SNAPSHOT.ear, i radzę tego nie zmieniać), należy przefiltrować plik applicationContext.xml i wkleić doń aktualną wersję. Naturalnie zahardkodowanie 0.0.1-SNAPSHOT to kiepski pomysł :-).

Od tej chwili mamy już bean springowy o id dateService, a w rzeczywistości proxy do EJB. Jeśli spodziewacie się teraz deklaratywnego wstrzykiwania tego beanu do odpowiednich akcji to muszę Was zawieźć... Nic więcej robić nie trzeba! No, prawie. Poniższy wpis sprawi, że Spring przeszuka wszystkie właściwości nowotworzonych beanów i będą oznaczone adnotacją @EJB, automatycznie wstrzyknie pasujący bean/EJB:


<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor"/>


Nawiasem mówiąc ten post procesor (zachęcam do pisania własnych post procesorów, to naprawdę potężny mechanizm!) rozpoznaje również adnotacje javax.annotation.PostConstruct i PreDestroy - również używam ich w tej aplikacji.

Ot, cała filozofia. Od tej pory możemy się cieszyć bardzo wygodną integracją frameworku webowego Struts2 z back-endem w EJB3. A wszystko to spaja - o zgrozo - największy rywal EJB, czyli Spring. Może zatem, zamiast się gryźć, próbujmy połączyć te dwa żywioły?

Tutaj dostępny kod źródłowy przykładowej aplikacji (maven friendly). Podzieliłem ją na cztery artefakty: ejb-api (interfejs EJB), ejb, web i ear. Jest to dodatkowy zysk z EJB: bardzo wyraźny podział widoku i logiki biznesowej, punktem styku są jedynie interfejsy komponentów sesyjnych. Do potestowania wystarczy mvn package i wdrożenie na JBossie. A na koniec obiecany czas w Australii po rosyjsku - jak na aplikację testową całkiem przydatna funkcjonalność ;-). U nich już jutrzejszy poranek, a w Polsce pora iść spać. Dobrej nocy!

Comments

  1. A nie da się w taki sposób skonfigurować aplikacji, aby bez użycia Springa móc wstrzykiwać objekty EJB? Np. w taki sposób jak jest to rozwiązane w jsf2.0.

    ReplyDelete
  2. Nie znam JSF 2.0, ale w Struts2 pewnie by się dało. Chyba najciekawszym rozwiązaniem byłby własny interceptor, który rozpoznawałby w obiektach akcji pola zaadnotowane @EJB czy @Resource i wstrzykiwał ręcznie odpowiednie proxy. Zasadniczo dokładnie to samo robi Spring, ale na etapie tworzenia akcji, a nie obsługi żądania HTTP. Zatem może własna fabryka akcji byłaby odpowiedniejsza? Możliwości jest wiele.

    ReplyDelete

Post a Comment