Michał Mech – W stronę Java

Zapiski programisty

Archiwum tagu ‘Dependency Injection’

Automatyczne wstrzykiwanie bean’ów w Springu

brak komentarzy

Jednym z najważniejszych modułów frameworka Spring jest jego kontener odwrócenia sterowania (ang. Inversion of Control, IoC), który dostarcza nam możliwości wstrzykiwania zależności (ang. Dependency Injection, DI). Jest to miejsce gdzie dzieje się magia :-)

Taki kontener należy odpowiednio skonfigurować, aby bean‘y zarządzane przez framework były odpowiednio zainicjowane oraz ze sobą połączone. Nie będę opisywał wszystkich aspektów konfiguracji kontenera IoC, gdyż to zadanie na niekrótką książkę. Skupię się tylko na definiowaniu powiązań między bean‘ami za pomocą automatycznego wstrzykiwania (ang. autowire).

Przeczytaj resztę wpis »

Opublikowany przez Michał Mech

2009-06-16 o 23:13:25

Wstrzykiwanie zależności – serce Seam’a

Ilość komentarzy: 4

We wstępie do dokumentacji autorzy frameworka JBoss Seam piszą, że jednym ze wzorców, którym hołdowali budując Seam’a jest wstrzykiwanie zależności (ang. Dependency Injection, DI). Wzorzec DI został nie tylko zastosowany w Seam’ie ale również rozszerzony i nazwany Bijection.

Bijection od DI różnią trzy cechy:

  1. contextual – wstrzykiwane do komponentów zależności są wybierane z odpowiedniego kontekstu w jakim występują. Seam posiada kilka kontekstów i zanim wstrzyknie zależność do komponentu szuka jej w odpowiednim miejscu;
  2. bidirectional – mechanizm Bijection pozwala nie tylko na wstrzykiwanie zależności do komponentów ale również na wystrzeliwanie ich na zewnątrz do dowolnego kontekstu;
  3. dynamic – twórcy Seam’a gwarantują, że mechanizm Bijection jest bardziej elastyczny.

Autorzy Seam’a wyżej cenią adnotacje niż konfigurację za pomocą XML‘a, stąd właśnie one posłużą nam informowaniu kontenera o zależnościach między komponentami i jak powinny być one wstrzykiwane i wystrzeliwane.

Za mechanizm bijection odpowiedzialne są dwie adnotacje: @In i @Out. Lecz, żeby dobrze je zrozumieć zacznijmy od prostej adnotacji @Name. Za pomocą @Name możemy nadać nazwę dowolnemu komponentowi w aplikacji. Nazwa musi być unikalna dla całej aplikacji. Krótki przykład zastosowania:

@Entity
@Name("article")
public class Article implements Serializable {

    private long id;

    private String title;

    ...
}

Jeśli jakiś komponent (lub nawet JSF) odwoła się do obiektu o nazwie article, Seam przeszuka obowiązujący kontekst i dostarczy zależność. W powyższym przykładzie mamy jeszcze adnotację @Entity, która w opisywanym zagadnieniu nie gra większej roli. Wskazuje ona, że klasa jest encją reprezentującą trwały obiekt w bazie danych.

Przejdźmy teraz do wstrzykiwania i wystrzeliwania zależności. Oto komponent sesyjny (ang. Session Bean), który wykona dla nas trochę logiki biznesowej:

@Stateless
@Name("paper")
public class PaperAction implements Paper {
    @In @Out
    private Article article;

    @Out
    private List lt;Articlegt; articles;

    @PersistenceContext
    private EntityManager em;

    public String addArticle () {
        em.persist (article);
        article = new Article ();

        articles = em.createQuery("select a from Article a")
            .getResultList();

        return null;
    }
}

Adnotacja @Stateless informuje nas, że komponent jest bezstanowy co oznacza, że będzie tworzony od nowa za każdym razem kiedy kontener zostanie poproszony o jego dostarczenie. Nazwą komponentu (określoną przez adnotację @Name) jest paper.

Skupmy się teraz na zależnościach. Widzimy przy polu article adnotację @In. Oznacza to, że zanim zostanie wykonana jakakolwiek metoda komponentu, kontener ma wstrzyknąć do tego pola zależność o nazwie article. Jeśli chcemy do pola article wstrzyknąć zależność o innej nazwie niż pole powinniśmy do adnotacji dodać parametr value, np.: @In(value=”favoriteArticle”) (Adnotacja @In oraz @Out posiada kilka innych prostych parametrów. Polecam zapoznanie się z nimi.) Oczywiście komponent może zawierać dowolną ilość elementów z adnotacją @In. Pamiętać należy o tym, że za każdym razem będą one wstrzykiwane.

W dalszej kolejności widzimy adnotacje @Out, opisujące pola article oraz articles. Oznaczają one, że po zakończeniu pracy komponentu kontener powinien pobrać zawartość tych oraz umieścić w odpowiednich kontekstach. Obiekty te, będą teraz dostępne dla innych komponentów. Zostaną wystrzelone na zewnątrz komponentu.

Komponent paper zawiera jeszcze jedną adnotację: @PersistenceContext. Informuje ona, że do opisanego za jej pomocą pola kontener ma wstrzyknąć managera encji. Podobnie jak w przypadku @Entity nie jest to w tej chwili meritum sprawy.

Jedyna metoda komponentu addArticle() ma za zadanie zapisać artykuł znajdujący się polu article do bazy danych a później pobrać wszystkie artykuły i zapisać je w polu articles.

Na samym końcu zerknijmy na fragment widoku (JSF), który mógłby służyć do podania tytułu artykułu oraz miałby za zadanie wyświetlić wszystkie inne tytuły artykułów:

<h:form>
    Podaj tytuł artykułu:
    <h:inputText value="#{article.title}"/>
    <h:commandButton type="submit" value="Zapisz" action="#{paper.addArticle}" />
</h:form>

<h:dataTable value="#{articles}" var="article">
    <h:column>
        <h:outputText value="#{article.title}"/>
    </h:column>
</h:dataTable>

A teraz co się stanie kiedy klikniemy Zapisz:

  1. Seam postara się odnaleźć dwa komponenty: article oraz paper. Pierwszy jest wymagany ponieważ do komponentu o tej nazwie, a dokładniej do jego pola title, ma być zapisany tytuł wpisany w pole tekstowe. Drugi komponent jest poszukiwany aby wykonać jego metodę addArticle();
  2. Oba komponenty zostaną utworzone ponieważ nie ma ich w żadnym kontekście. Article jest encją, w której zapiszemy dane z formularza a paper jest komponentem bezstanowym, który wykona trochę logiki;
  3. Zostanie wykonana akcja a po jej zakończeniu pola oznaczone za pomocą @Out zostaną wystrzelone do kontenera, dzięki czemu będą dostępne dla innych komponentów oraz dla widoku.

Zastosowana w widoku notacja #{…} to Expression Language (EL), na który polecam zwrócić uwagę ponieważ jest wykorzystywany w Seam’ie niemal wszędzie gdzie się da.

Na koniec dodatkowa, ważna informacja. Za pomocą @In oraz @Out możemy adnotować również metody aby osiągnąć identyczny efekt jak w powyższym, przykładowym komponencie. Oto przykład jak wyglądałby komponent paper, gdybym adnotacji użył do opisania metod:

@Stateless
@Name("paper")
public class PaperAction {
    private Article article;

    private List lt;Articlegt; articles;

    @PersistenceContext
    private EntityManager em;

    public String addArticle () {
        em.persist (article);
        article = new Article ();

        articles = em.createQuery("select a from Article a")
            .getResultList();

        return null;
    }

    @In
    public function void setArticle(Article article) {
        this.article = article;
    }

    @Out
    public function Article getArticle() {
        return article;
    }

    @Out
    public function List lt;Articlegt; getArticles() {
        return articles;
    }
}

Opublikowany przez Michał Mech

2009-01-25 o 16:49:00