Baza Wiedzy

CDI - Context and Dependency Injection

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.

      cdi project eclipse

      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.

      project facet konfiguracja

      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.

      cdi eclipse project 2

      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.

      console log weld

      Najlepszy newsletter o Javie w Polsce

      Czy chcesz otrzymywać nowości ze świata Javy oraz przykładowe pytania rekrutacyjne? Zapisz się na newsletter i bądź na bieżąco! Otrzymasz także ekskluzywne materiały oraz informacje o nowych kursach i promocjach.

      Nikomu nie udostępniamy Twojego maila, a jeśli zechcesz to w każdej chwili możesz się wypisać.

      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.