CDI (Context and Dependency Injection) jest standardem wstrzykiwania zależności w Javie EE. Możliwe jest wykorzystanie implementacji również w Javie SE. Aktualna wersja oznaczona jest numerem 1.2, jednak w Javie EE 8 pojawi się wersja CDI 2.0. Specyfikacja definiująca CDI oznaczona jest jako JSR 299.
Implementacje🔗
CDI podobnie jak wiele składowych Javy EE jest jedynie specyfikacją do tego jakie wymogi mają spełniać jej implementacje. Najpopularniejszą i referencyjną implementacją jest Weld rozwijany pod skrzydłami firmy redhat. Wykorzystywany jest on zarówno w serwerach redhata jak JBoss i Wildfly, ale również w innych np. Glassfishu. Rzadziej spotykaną alternatywą jest Apache OpenWebBeans.
W przypadku Welda dostępna jest również wersja Weld-SE, która pozwala na wykorzystanie wstrzykiwania zależności w tradycyjnych aplikacjach desktopowych, które nie będą uruchamiane w kontenerach Javy EE.
Możliwości🔗
Specyfikacja CDI łączy w sobie nie tylko możliwości wstrzykiwania zależności, ale definiuje również standard programowania aspektowego, który realizowany jest w Javie EE poprzez mechanizm interceptorów.
CDI świetnie integruje się z większością już istniejących specyfikacji dzięki czemu możemy z niego korzystać w technologiach takich jak serwlety, EJB, czy JaxRS.
Konfiguracja🔗
W przypadku, gdy korzystamy z Mavena i aplikacji, która będzie uruchamiana w kontenerze Javy EE, powinniśmy posługiwać się zależnościami dostarczanymi przez kontener, z którego korzystamy. Jeśli jest to serwer zgodny z Javą EE 7 to korzystając z Mavena wystarczy dodać zależność:
<dependency>
<groupId>javax.enterprise</groupId>
<artifactId>cdi-api</artifactId>
<version>1.2</version>
</dependency>
Najlepszym pomysłem jest korzystanie z sekcji dependencyManagement, dzięki czemu możliwe będzie pominięcie definiowania wersji i ustawienie zasięgu na provided.
Chcąc skorzystać z CDI w Javie SE w projekcie o naturze mavena należy dodać zależność do biblioteki Weld SE:
<dependency>
<groupId>org.jboss.weld.se</groupId>
<artifactId>weld-se-core</artifactId>
<version>2.3.4.Final</version>
</dependency>
lub pobrać bibliotekę w formie .jar z oficjalnej strony. Zwracamy uwagę, żeby pobrać wersję ze wszystkimi zależnościami (Uber Jar).
Wstrzykiwanie zależności (Weld)🔗
Wstrzykiwanie zależności jest techniką, która pozwala nam unikać silnych powiązań pomiędzy klasami. Silną rolę odgrywa tutaj korzystanie z interfejsów oraz zalet jakie daje nam polimorfizm.
Konfiguracja projektu🔗
Pobierz najnowszą wersję biblioteki Weld-SE i dodaj ją do swojego projektu. W przypadku Eclipse najlepiej utworzyć w tym celu folder lib, w którym należy umieścić bibliotekę, a następnie kliknij na nią prawym przyciskiem myszy i wybierz opcję Build Path . Add to build path.
W przypadku projektu Mavena dodaj jedną z wcześniej podawanych zależności.
Drugim krokiem jest kliknięcie prawym przyciskiem myszy na projekcie i przejście do konfiguracji (Properties), następnie wskazujemy Project Facets > Convert to faceted form. Dzięki temu będziemy mogli zaznaczyć, że w projekcie chcemy wsparcie dla CDI i wygenerowany zostanie jedyny wymagany plik konfiguracyjny o nazwie beans.xml.
W przypadku aplikacji Java SE plik beans.xml zostanie utworzony w folderze META-INF, a w aplikacjach webowych w WEB-INF.
Definiowanie ziaren🔗
W przypadku frameworków udostępniających nam kontener wstrzykiwania zależności takich jak CDI, czy Spring, obiekty zarządzane przez kontener nazywać będziemy ziarnami. W przypadku Springa do dyspozycji mamy konfigurację opartą o XML i w nowszych wersjach o adnotacje Javy. Ponieważ CDI powstało później i wynika z najlepszych praktyk, to zdecydowano się konfigurację XML ograniczyć do minimum, stawiając na podejście convention over configuration i stosowanie adnotacji.
W celu wskazania klasy jako ziarno zarządzane CDI należy je opatrzyć jedną z adnotacji zasięgu np. @Dependent, czy @RequestScoped.
Najpierw definiujemy klasę HelloService, której zadaniem jest zwrócenie komunikatu powitalnego.
package pl.javastart.bean;
import javax.enterprise.context.Dependent;
@Dependent
public class HelloService {
public String getMessage() {
return "Hello world from Hello Service!";
}
}
Następnie komunikat ten chcemy wykorzystać w klasie SayHelloService, więc musimy do niego wstrzyknąć instancję powyższej klasy, co robimy poprzez adnotację @Inject, która wykorzystywana jest do wstrzykiwania większości rzeczy, również ziaren EJB.
package pl.javastart.bean;
import javax.enterprise.context.Dependent;
import javax.inject.Inject;
@Dependent
public class SayHelloService {
@Inject
private HelloService helloService;
public void sayHello() {
System.out.println(helloService.getMessage());
}
}
Uruchamianie kontenera🔗
Instancję SayHelloService chcemy teraz pobrać z kontenera Welda i wywołać na niej metodę sayHello().
package pl.javastart.app;
import org.jboss.weld.environment.se.Weld;
import org.jboss.weld.environment.se.WeldContainer;
import pl.javastart.bean.SayHelloService;
public class CdiTest {
public static void main(String[] args) {
Weld weld = new Weld();
WeldContainer container = weld.initialize();
SayHelloService sayHelloService = container.select(SayHelloService.class).get();
sayHelloService.sayHello();
}
}
Po uruchomieniu aplikacji w konsoli pojawią się logi Welda, a następnie komunikat wydrukowany przez metodę sayHello(). Jak widać korzystając z kontenera wstrzykiwania zależności odpowiedzialność za tworzenie obiektów i zarządzanie ich cyklem życia stoi po stronie kontenera, a nie naszej - nigdzie nie wywołujemy konstruktorów, ani nie ustawiamy zależności poprzez settery.
W przypadku aplikacji tworzonych w środowisku Java EE kontener DI pracuje w tle, nie będzie więc potrzebne definiowania obiektów Weld, czy WeldContainer.
Komentarze do artykułu
Wyłączyliśmy możliwość dodawania komentarzy. Poniżej znajdziesz archiwalne wpisy z czasów gdy strona była jeszcze hobbystycznym blogiem. Zapraszamy natomiast do zadawnia pytań i dyskusji na naszej grupe na facebooku.